├── .github └── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── show-header-with-links.gif └── source ├── icons ├── links-for-headers-128.png ├── links-for-headers-16.png ├── links-for-headers-32.png ├── links-for-headers-48.png └── links-for-headers-64.png ├── manifest.json ├── scripts └── generate_links.js └── styles └── generate_links.css /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | My question / suggestion is: 2 | 3 | 4 | The URL (if applicable) pertaining to my problem is: 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Grant Winney 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 | # Generate Links for Headers 2 | 3 | I frequently want to share a link with someone, but I want to link to a specific section of the page. That means checking out the source code for the page, finding the header element or an anchor nearby, and (if it has an ID or Name assigned to it) appending it to the URL before sharing it. 4 | 5 | I figured I can do better than that. 6 | 7 | ## Create links for all headers automatically 8 | 9 | Available for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/generate-links-for-headers/) and [Chrome](https://chrome.google.com/webstore/detail/generate-links-for-header/dckfkngmahjdokkkmconmfjdmicjcmgf) (and so also Opera, Brave, and Edge), it scans the page and generates anchors for all headers on the page, *assuming they have an ID or Name assigned.* 10 | 11 | * Hover over the header, and the anchor link will appear. 12 | * Click on the 🔗 link icon to copy the link to the clipboard. 13 | 14 | Here's what it looks like.. pretty much. The screenshot is outdated but you get the point. 15 | 16 | ![](show-header-with-links.gif) 17 | 18 | ### Headers with child elements 19 | 20 | If the header itself doesn't have an ID or Name, it traverses all elements inside the header tags looking for the first element with an ID or Name assigned, since [any element can be used as an anchor](https://www.w3.org/TR/html4/struct/links.html#h-12.2.3). If it finds one, it uses it as the anchor; if not, then there's nothing to link to and you won't see the icon appear for that header. 21 | 22 | ### Excluded sites 23 | 24 | The following sites are intentionally excluded, either due to implementing similar behavior already, or because displaying the icon doesn't work due to existing site layout/styles. 25 | 26 | * github.com 27 | * docs.microsoft.com 28 | 29 | ## Questions? Issues? 30 | 31 | If you have any questions, comments, or issues, feel free to [create an issue](https://github.com/grantwinney/generate-links-for-headers/issues/new) and I'll check it out as my schedule permits. 32 | 33 | Enjoy! 34 | 35 | --- 36 | 37 | ## History 38 | 39 | **2018** 40 | - 1.0 - Initial 41 | - 1.0.2 - Show border momentarily when clicking on icon, to indicate something has happened. 42 | - 1.0.4 - Float icon to left of header instead of making it an inline block element. Previously, when the header was very long it consumed the -20px margin I had left for the icon, and the icon moved above the header. This fixes both issues. 43 | - 1.0.5 - Exclude portion of W3C site that breaks, and doesn't really need this extension anyway (they provide similar behavior). 44 | - 1.0.6 - Some sites, like Wikipedia, nest elements with IDs _inside_ header elements. If a header element doesn't have an ID, try to grab the first element with ID inside it (if any) and use that. Also, exclude Startpage.com which uses a header for every block of results. 45 | - 1.0.7 - Exclude github.com - it implements similar behavior. 46 | - 1.0.8 - Check for 'name' attribute in addition to 'id'. 47 | - 1.0.9 - Eliminate choppiness when hovering back and forth between header title and link. 48 | - 1.1.0 - Specify max z-index to ensure link shows above any other element. The link is tiny and invisible most of the time, and it needs to appear above all other elements when it's visible to be of any use at all. 49 | - 1.1.1 - Modified the link in the manifest file. 50 | 51 | **2019** 52 | - 1.2.1 - Adjusted CSS due to a bug that caused the link element to be hidden. 53 | - 1.2.2 - Allow links to be generated on help.github.com; was previously disabled for all github.com subdomains. 54 | 55 | **2020** 56 | - 1.2.5 - Moved anchor image to appear on right side of headers; sometimes it wasn't visible on the left side. 57 | - 1.2.6 - Enable on all sites except GitHub. 58 | - 1.2.7 - Disable on docs.microsoft.com, which implements its own solution. 59 | - 1.3.0 - Replaced custom svg with font awesome icon. Reworked css to fix a couple bugs. 60 | - 1.3.1 - Remove font awesome icon and just fix the original svg to work correctly. 61 | 62 | **2021** 63 | - 1.3.4 - Remove use of InnerHTML. Replace deprecated command used to copy to clipboard with standard api call. Replace svg icon with a standard unicode character. 64 | 65 | **2022** 66 | - 1.3.7 - Adjustments for sites that didn't play well with this addon. 67 | -------------------------------------------------------------------------------- /show-header-with-links.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantwinney/generate-links-for-headers/42a4206a72b08e203361c604915321beddab36aa/show-header-with-links.gif -------------------------------------------------------------------------------- /source/icons/links-for-headers-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantwinney/generate-links-for-headers/42a4206a72b08e203361c604915321beddab36aa/source/icons/links-for-headers-128.png -------------------------------------------------------------------------------- /source/icons/links-for-headers-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantwinney/generate-links-for-headers/42a4206a72b08e203361c604915321beddab36aa/source/icons/links-for-headers-16.png -------------------------------------------------------------------------------- /source/icons/links-for-headers-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantwinney/generate-links-for-headers/42a4206a72b08e203361c604915321beddab36aa/source/icons/links-for-headers-32.png -------------------------------------------------------------------------------- /source/icons/links-for-headers-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantwinney/generate-links-for-headers/42a4206a72b08e203361c604915321beddab36aa/source/icons/links-for-headers-48.png -------------------------------------------------------------------------------- /source/icons/links-for-headers-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grantwinney/generate-links-for-headers/42a4206a72b08e203361c604915321beddab36aa/source/icons/links-for-headers-64.png -------------------------------------------------------------------------------- /source/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "author": "Grant Winney", 4 | "homepage_url": "https://github.com/grantwinney/generate-links-for-headers", 5 | 6 | "name": "Generate Links for Headers", 7 | "description": "Automatically generates links for all headers on the page, to make it easier to share specific sections of the page.", 8 | "version": "1.3.7", 9 | 10 | "content_scripts": [ 11 | { 12 | "css": [ 13 | "styles/generate_links.css" 14 | ], 15 | "js": [ 16 | "scripts/generate_links.js" 17 | ], 18 | "matches": [ 19 | "" 20 | ], 21 | "exclude_matches": [ 22 | "*://reservations.cosi.org/*", 23 | "*://fiscaloffice.summitoh.net/*", 24 | "*://github.com/*", 25 | "*://docs.microsoft.com/*", 26 | "*://amazon.com/*" 27 | ] 28 | } 29 | ], 30 | 31 | "icons": { 32 | "16": "icons/links-for-headers-16.png", 33 | "32": "icons/links-for-headers-32.png", 34 | "48": "icons/links-for-headers-48.png", 35 | "64": "icons/links-for-headers-64.png", 36 | "128": "icons/links-for-headers-128.png" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /source/scripts/generate_links.js: -------------------------------------------------------------------------------- 1 | // Loop recursively through the header and its child elements, in search of an ID to link to 2 | // Return the ID if found, otherwise undefined 3 | function getFirstId(element) { 4 | if (element.hasAttribute('id')) { 5 | return element.getAttribute('id'); 6 | } else if (element.hasAttribute('name')) { 7 | return element.getAttribute('name'); 8 | } else if (element.hasChildNodes()) { 9 | for (let i = 0; i < element.children.length; i++) { 10 | let id = getFirstId(element.children[i]); 11 | if (id) { 12 | return id; 13 | } 14 | } 15 | } 16 | return undefined; 17 | } 18 | 19 | // Check the element's immediate parent, in search of an appropriate ID to link to 20 | // Return the ID if found, otherwise undefined 21 | function getParentId(element) { 22 | let pNode = element.parentNode; 23 | if (pNode !== undefined && (pNode.tagName === 'A' || pNode.tagName === 'DIV')) { 24 | if (pNode.hasAttribute('id')) { 25 | return pNode.getAttribute('id'); 26 | } else if (pNode.hasAttribute('name')) { 27 | return pNode.getAttribute('name'); 28 | } 29 | } 30 | return undefined; 31 | } 32 | 33 | let alreadyRun = false; 34 | document.addEventListener('readystatechange', event => { 35 | if (event.target.readyState === 'complete' && !alreadyRun) { 36 | alreadyRun = true; 37 | document.querySelectorAll('h1, h2, h3, h4, h5, h6') 38 | .forEach(function(header) { 39 | let id = getFirstId(header) || getParentId(header); 40 | if (id) { 41 | let anchorUrl = `${location.protocol}//${location.host}${location.pathname}${location.search}#${id}`; 42 | 43 | let copyLink = document.createElement('a'); 44 | copyLink.href = anchorUrl; 45 | copyLink.title = 'Copy link to clipboard'; 46 | copyLink.textContent = String.fromCodePoint(128279); 47 | copyLink.addEventListener('click', function() { 48 | navigator.clipboard.writeText(anchorUrl) 49 | }) 50 | 51 | let innerDiv = document.createElement('div'); 52 | innerDiv.className = 'glfh_linkContainer'; 53 | innerDiv.appendChild(copyLink); 54 | 55 | header.appendChild(innerDiv); 56 | header.classList.add('glfh_headerContainer'); 57 | } 58 | }); 59 | } 60 | }, false); 61 | -------------------------------------------------------------------------------- /source/styles/generate_links.css: -------------------------------------------------------------------------------- 1 | /* Set the icon's location and fading transition */ 2 | .glfh_linkContainer { 3 | display: inline; 4 | font-size: 75%; 5 | opacity: 0.0; 6 | padding-left: 10px; 7 | transition: all 200ms ease-out; 8 | vertical-align: middle; 9 | } 10 | 11 | /* Prevent the icon from showing underlining, etc */ 12 | .glfh_linkContainer > a, .glfh_linkContainer > a:hover { 13 | border: 0px !important; 14 | color: inherit; 15 | text-decoration: none !important; 16 | } 17 | 18 | /* Hovering over the header makes the icon visible */ 19 | .glfh_headerContainer:hover .glfh_linkContainer { 20 | opacity: 1.0; 21 | } 22 | --------------------------------------------------------------------------------