├── .gitignore ├── .travis.yml ├── package.json ├── LICENSE ├── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | tmp/ 4 | dist/ 5 | npm-debug.log* 6 | .DS_Store 7 | .nyc_output 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "4" 3 | - "5" 4 | - "6" 5 | - "7" 6 | sudo: false 7 | language: node_js 8 | script: "npm run test" 9 | # after_success: "npm i -g codecov && npm run coverage && codecov" 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nanohref", 3 | "description": "Tiny href click handler library", 4 | "repository": "yoshuawuyts/nanohref", 5 | "version": "3.1.0", 6 | "scripts": { 7 | "deps": "dependency-check . && dependency-check . --extra --no-dev -i nanoassert", 8 | "start": "node .", 9 | "test": "standard && npm run deps", 10 | "coverage": "nyc report --reporter=text-lcov > coverage.lcov" 11 | }, 12 | "browser": { 13 | "assert": "nanoassert" 14 | }, 15 | "dependencies": { 16 | "nanoassert": "^1.1.0" 17 | }, 18 | "devDependencies": { 19 | "dependency-check": "^2.8.0", 20 | "nyc": "^10.2.0", 21 | "standard": "^10.0.1", 22 | "tape": "^4.6.3" 23 | }, 24 | "keywords": [ 25 | "nano", 26 | "browser", 27 | "href", 28 | "click", 29 | "anchor" 30 | ], 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Yoshua Wuyts 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 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | 3 | var safeExternalLink = /(noopener|noreferrer) (noopener|noreferrer)/ 4 | var protocolLink = /^[\w-_]+:/ 5 | 6 | module.exports = href 7 | 8 | function href (cb, root) { 9 | assert.notEqual(typeof window, 'undefined', 'nanohref: expected window to exist') 10 | 11 | root = root || window.document 12 | 13 | assert.equal(typeof cb, 'function', 'nanohref: cb should be type function') 14 | assert.equal(typeof root, 'object', 'nanohref: root should be type object') 15 | 16 | window.addEventListener('click', function (e) { 17 | if ((e.button && e.button !== 0) || 18 | e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || 19 | e.defaultPrevented) return 20 | 21 | var anchor = (function traverse (node) { 22 | if (!node || node === root) return 23 | if (node.localName !== 'a' || node.href === undefined) { 24 | return traverse(node.parentNode) 25 | } 26 | return node 27 | })(e.target) 28 | 29 | if (!anchor) return 30 | 31 | if (window.location.protocol !== anchor.protocol || 32 | window.location.hostname !== anchor.hostname || 33 | window.location.port !== anchor.port || 34 | anchor.hasAttribute('data-nanohref-ignore') || 35 | anchor.hasAttribute('download') || 36 | (anchor.getAttribute('target') === '_blank' && 37 | safeExternalLink.test(anchor.getAttribute('rel'))) || 38 | protocolLink.test(anchor.getAttribute('href'))) return 39 | 40 | e.preventDefault() 41 | cb(anchor) 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nanohref [![stability][0]][1] 2 | [![npm version][2]][3] [![build status][4]][5] 3 | [![downloads][8]][9] [![js-standard-style][10]][11] 4 | 5 | Tiny href click handler library. 6 | 7 | ## Usage 8 | ```js 9 | var nanohref = require('nanohref') 10 | 11 | // Handler automatically attached to window.document 12 | nanohref(function (location) { 13 | console.log('new location is', location.pathname) 14 | }) 15 | 16 | // Create DOM node 17 | var el = document.createElement('a') 18 | el.setAttribute('href', '/my-link') 19 | el.innerText = 'Click me' 20 | document.body.appendChild(el) 21 | 22 | // Trigger click 23 | el.click() 24 | // => "new location is /my-link" 25 | ``` 26 | 27 | ## Ignoring links 28 | By default all href links are handled. The event is not handled under the 29 | following conditions: 30 | - the click event had `.preventDefault()` called on it 31 | - the link has a `data-nanohref-ignore` attribute 32 | - the link has a `target="_blank"` attribute with `rel="noopener noreferrer"` 33 | - a modifier key is enabled (e.g. `ctrl`, `alt`, `shift` or `meta`) 34 | - the link's href starts with protocol handler such as `mailto:` or `dat:` 35 | - the link points to a different host 36 | - the link has a `download` attribute 37 | 38 | :warning: Note that we only handle `target=_blank` if they also have 39 | `rel="noopener noreferrer"` on them. This is needed to [properly sandbox web 40 | pages](https://mathiasbynens.github.io/rel-noopener/). Once `noopener` [becomes 41 | more widespread](http://caniuse.com/#feat=rel-noopener), we can drop 42 | `noreferrer` too (currently just 60% of browsers in use support it). 43 | 44 | ## API 45 | ### `nanohref(handler(location), [rootNode])` 46 | Create a new anchor click handler. The second argument is for the root node, 47 | which defaults to `window.document`. 48 | 49 | ## See Also 50 | - [MDN/link-types](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types) 51 | - [caniuse/rel=noopener](http://caniuse.com/#feat=rel-noopener) 52 | - [mapbox/link-hijacker](https://github.com/mapbox/link-hijacker) 53 | 54 | ## License 55 | [MIT](https://tldrlegal.com/license/mit-license) 56 | 57 | [0]: https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square 58 | [1]: https://nodejs.org/api/documentation.html#documentation_stability_index 59 | [2]: https://img.shields.io/npm/v/nanohref.svg?style=flat-square 60 | [3]: https://npmjs.org/package/nanohref 61 | [4]: https://img.shields.io/travis/choojs/nanohref/master.svg?style=flat-square 62 | [5]: https://travis-ci.org/choojs/nanohref 63 | [6]: https://img.shields.io/codecov/c/github/choojs/nanohref/master.svg?style=flat-square 64 | [7]: https://codecov.io/github/choojs/nanohref 65 | [8]: http://img.shields.io/npm/dm/nanohref.svg?style=flat-square 66 | [9]: https://npmjs.org/package/nanohref 67 | [10]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 68 | [11]: https://github.com/feross/standard 69 | --------------------------------------------------------------------------------