{"id":13756725,"url":"https://github.com/alienzhou/web-highlighter","last_synced_at":"2025-05-15T09:07:22.135Z","repository":{"id":37663816,"uuid":"158157712","full_name":"alienzhou/web-highlighter","owner":"alienzhou","description":"✨ A no-runtime dependency lib for text highlighting \u0026 persistence on any website ✨🖍️","archived":false,"fork":false,"pushed_at":"2024-04-29T16:00:43.000Z","size":3900,"stargazers_count":927,"open_issues_count":41,"forks_count":149,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-05-07T08:02:09.055Z","etag":null,"topics":["highlight","note","range","selection","text","website"],"latest_commit_sha":null,"homepage":"https://alienzhou.github.io/web-highlighter/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alienzhou.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-19T03:38:30.000Z","updated_at":"2025-05-06T01:27:31.000Z","dependencies_parsed_at":"2024-06-18T14:14:56.286Z","dependency_job_id":null,"html_url":"https://github.com/alienzhou/web-highlighter","commit_stats":{"total_commits":146,"total_committers":7,"mean_commits":"20.857142857142858","dds":0.3835616438356164,"last_synced_commit":"1dbe0c3a61acff3d116731b0ab406211320fc5aa"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienzhou%2Fweb-highlighter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienzhou%2Fweb-highlighter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienzhou%2Fweb-highlighter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alienzhou%2Fweb-highlighter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alienzhou","download_url":"https://codeload.github.com/alienzhou/web-highlighter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310515,"owners_count":22049469,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["highlight","note","range","selection","text","website"],"created_at":"2024-08-03T11:00:52.178Z","updated_at":"2025-05-15T09:07:17.127Z","avatar_url":"https://github.com/alienzhou.png","language":"TypeScript","funding_links":[],"categories":["website",":file_folder: Browser"],"sub_categories":["Other"],"readme":"\u003cdiv\u003e\n    \u003ch1 align=\"center\"\u003e\u003ccode\u003eWeb Highlighter\u003c/code\u003e\u0026nbsp;\u0026nbsp;🖍️\u003c/h1\u003e\n    \u003cp align=\"center\"\u003e\n        \u003cstrong\u003e✨ A no-dependency lib for text highlighting \u0026 persistence on any website ✨🖍️\u003c/strong\u003e\n    \u003c/p\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/alienzhou/web-highlighter/master/docs/img/logo.png\"\u003e\n    \u003cp align=\"center\"\u003e\n        \u003ca href=\"https://travis-ci.org/alienzhou/web-highlighter\" target=\"_blank\"\u003e\n            \u003cimg src=\"https://api.travis-ci.org/alienzhou/web-highlighter.svg?branch=master\" alt=\"Build status\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://www.npmjs.com/package/web-highlighter\" target=\"_blank\"\u003e\n            \u003cimg src=\"https://img.shields.io/npm/v/web-highlighter.svg\" alt=\"NPM version\" /\u003e\n        \u003c/a\u003e\n        \u003ca href='https://coveralls.io/github/alienzhou/web-highlighter?branch=master'\u003e\n            \u003cimg src='https://coveralls.io/repos/github/alienzhou/web-highlighter/badge.svg?branch=master' alt='Coverage Status' /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://unpkg.com/web-highlighter\" target=\"_blank\"\u003e\n            \u003cimg src=\"https://img.badgesize.io/https://unpkg.com/web-highlighter/dist/web-highlighter.min.js?compression=gzip\" alt=\"Gzip size\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://codebeat.co/projects/github-com-alienzhou-web-highlighter-master\" target=\"_blank\"\u003e\n            \u003cimg src=\"https://codebeat.co/badges/f5a18a9b-9765-420e-a17f-fa0b54b3a125\" alt=\"Codebeat\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://opensource.org/licenses/mit-license.php\" target=\"_blank\"\u003e\n            \u003cimg src=\"https://img.shields.io/github/license/alienzhou/web-highlighter\" alt=\"MIT Licence\" /\u003e\n        \u003c/a\u003e\n    \u003c/p\u003e\n\u003c/div\u003e\n\n---\n\nEnglish | [简体中文](https://github.com/alienzhou/web-highlighter/blob/master/README.zh_CN.md)\n\n## Background\n\nIt's from an idea: highlight texts on the website and save the highlighted areas just like what you do in PDF.\n\nIf you have ever visited [medium.com](http://medium.com), you must know the feature of highlighting notes: users select a text segment and click the 'highlight' button. Then the text will be highlighted with a shining background color. Besides, the highlighted areas will be saved and recovered when you visit it next time. It's like the simple demo bellow.\n\n![](https://raw.githubusercontent.com/alienzhou/web-highlighter/master/docs/img/sample.gif)\n\nThis is a useful feature for readers. If you're a developer, you may want your website support it and attract more visits. If you're a user (like me), you may want a browser-plugin to do this.\n\nFor this reason, the repo (web-highlighter) aims to help you implement highlighting-note on any website quickly (e.g. blogs, document viewers, online books and so on). It contains the core abilities for note highlighting and persistence. And you can implement your own product by some easy-to-use APIs. It has been used for our sites in production.\n\n## Install\n\n```bash\nnpm i web-highlighter\n```\n\n## Usage\n\nOnly two lines, highlighted when texts are selected.\n\n```JavaScript\nimport Highlighter from 'web-highlighter';\n(new Highlighter()).run();\n```\n\nIf you need persistence, four lines make it.\n\n```JavaScript\nimport Highlighter from 'web-highlighter';\n\n// 1. initialize\nconst highlighter = new Highlighter();\n\n// 2. retrieve data from backend, then highlight it on the page\ngetRemoteData().then(s =\u003e highlighter.fromStore(s.startMeta, s.endMeta, s.id, s.text));\n\n// 3. listen for highlight creating, then save to backend\nhighlighter.on(Highlighter.event.CREATE, ({sources}) =\u003e save(sources));\n\n// 4. auto highlight\nhighlighter.run();\n```\n\n## Example\n\nA more complex example\n\n```JavaScript\nimport Highlighter from 'web-highlighter';\n\n// won't highlight pre\u0026code elements\nconst highlighter = new Highlighter({\n    exceptSelectors: ['pre', 'code']\n});\n\n// add some listeners to handle interaction, such as hover\nhighlighter\n    .on('selection:hover', ({id}) =\u003e {\n        // display different bg color when hover\n        highlighter.addClass('highlight-wrap-hover', id);\n    })\n    .on('selection:hover-out', ({id}) =\u003e {\n        // remove the hover effect when leaving\n        highlighter.removeClass('highlight-wrap-hover', id);\n    })\n    .on('selection:create', ({sources}) =\u003e {\n        sources = sources.map(hs =\u003e ({hs}));\n        // save to backend\n        store.save(sources);\n    });\n\n// retrieve data from store, and display highlights on the website\nstore.getAll().forEach(\n    // hs is the same data saved by 'store.save(sources)'\n    ({hs}) =\u003e highlighter.fromStore(hs.startMeta, hs.endMeta, hs.text, hs.id)\n);\n\n// auto-highlight selections\nhighlighter.run()\n```\n\nBesides, there is an example in this repo (in `example` folder). To play with it, you just need ——\n\nFirstly enter the repository and run\n\n```bash\nnpm i\n```\n\nThen start the example\n\n```\nnpm start\n```\n\nFinally visit http://127.0.0.1:8085/\n\n---\n\nAnother real product built with web-highlighter (for the highlighting area on the left):\n\n![product sample](https://user-images.githubusercontent.com/9822789/64678049-632e8500-d4ab-11e9-99d6-f960bc90d17b.gif)\n\n## How it works\n\nIt will read the selected range by [`Selection API`](https://caniuse.com/#search=selection%20api). Then the information of the range will be converted to a serializable data structure so that it can be store in backend. When users visit your page next time, these data will be returned and deserialized in your page. The data structure is tech stack independent. So you can use on any 'static' pages made with React / Vue / Angular / jQuery and others.\n\nFor more details, please read [this article (in Chinese)](https://www.alienzhou.com/2019/04/21/web-note-highlight-in-js/).\n\n## APIs\n\n### 1. Options\n\n```JavaScript\nconst highlighter = new Highlighter([opts])\n```\n\nCreate a new `highlighter` instance.\n\n`opts` will be merged into the default options (shown bellow).\n\n```JavaScript\n{\n    $root: document.documentElement,\n    exceptSelectors: null,\n    wrapTag: 'span',\n    style: {\n        className: 'highlight-mengshou-wrap'\n    }\n}\n```\n\nAll options:\n\n| name | type | description | required | default |\n|---|---|---|---|---|\n| $root | `Document | HTMLElement` | the container to enable highlighting | No | `document` |\n| exceptSelectors | `Array\u003cstring\u003e` | if an element matches the selector, it won't be highlighted | No | `null` |\n| wrapTag | `string` | the html tag used to wrap highlighted texts | No | `span` |\n| verbose | `boolean` | dose it need to output (print) some warning and error message | No | `false` |\n| style | `Object` | control highlighted areas style | No | details below |\n\n`style` field options:\n\n| name | type | description | required | default |\n|---|---|---|---|---|\n| className | `string` | the className for wrap element | No | `highlight-mengshou-wrap` |\n\n`exceptSelectors` needs `null` or `Array\u003cstring\u003e`. It supports id selectors, class selectors and tag selectors. For example, to skip h1 and `.title` elements:\n\n```JavaScript\nvar highlighter = new Highlighter({\n    exceptSelectors: ['h1', '.title']\n});\n```\n\n### 2. Static Methods\n\n#### `Highlighter.isHighlightSource(source)`\n\nIf the `source` is a highlight source object, it will return `true`, vice verse.\n\n#### `Highlighter.isHighlightWrapNode($node)`\n\nIf the `$node` is a highlight wrapper dom node, it will return `true`, vice verse.\n\n### 3. Instance Methods\n\n#### `highlighter.run()`\n\nStart auto-highlighting. When the user select a text segment, a highlighting will be added to the text automatically.\n\n#### `highlighter.stop()`\n\nIt will stop the auto-highlighting.\n\n#### `highlighter.dispose()`\n\nWhen you don't want the highlighter anymore, remember to call it first. It will remove some listeners and do some cleanup.\n\n#### `highlighter.fromRange(range)`\n\nYou can pass a [`Range`](https://developer.mozilla.org/en-US/docs/Web/API/Range) object to it and then it will be highlighted. You can use `window.getSelection().getRangeAt(0)` to get a range object or use `document.createRange()` to create a new range.\n\nUse it as bellow:\n\n```JavaScript\nconst selection = window.getSelection();\nif (!selection.isCollapsed) {\n    highlighter.fromRange(selection.getRangeAt(0));\n}\n```\n\n#### `highlighter.fromStore(start, end, text, id)`\n\nMostly, you use this api to highlight text by the persisted information stored from backend.\n\nThese four values are from the `HighlightSource` object. `HighlightSource` object is a special object created by web-highlighter when highlighted area created. For persistence in backend (database), it's necessary to find a data structure to represent a dom node. This structure is called `HighlightSource` in web-highlighter.\n\nFour attributes' meanings:\n\n- start `Object`:    meta info about the beginning element\n- end   `Object`:    meta info about then end element\n- text  `string`:    text content\n- id    `string`:    unique id\n\n#### `highlighter.remove(id)`\n\nRemove (clean) a highlighted area by it's unique id. The id will be generated by web-highlighter by default. You can also add a hook for your own rule. [Hooks doc here](https://github.com/alienzhou/web-highlighter/blob/master/docs/ADVANCE.md).\n\n#### `highlighter.removeAll()`\n\nRemove all highlighted areas belonging to the root.\n\n#### `highlighter.addClass(className, id)`\n\nAdd a className for highlighted areas (wrap elements) by unique id. You can change a highlighted area's style by using this api.\n\n\n#### `highlighter.removeClass(className, id)`\n\nRemove the className by unique id. It's `highlighter.addClass`'s inverse operation.\n\n#### `highlighter.getDoms([id])`\n\nGet all the wrap nodes in a highlighted area. A highlighted area may contain many segments. It will return all the dom nodes wrapping these segments.\n\nIf the `id` is not passed, it will return all the areas' wrap nodes.\n\n\n#### `highlighter.getIdByDom(node)`\n\nIf you have a DOM node, it can return the unique highlight id for you. When passing a non-wrapper element, it will find the nearest ancestor wrapper node.\n\n#### `highlighter.getExtraIdByDom(node)`\n\nIf you have a DOM node, it can return the extra unique highlight id for you. When passing a non-wrapper element, it will find the nearest ancestor wrapper node.\n\n#### `highlighter.setOption(opt)`\n\nYou can use this API to change the highlighter's options. The parameters' structure is the same as the constructor's. You can pass partial options.\n\n### 4. Event Listener\n\nweb-highlighter use listeners to handle the events.\n\ne.g.\n\n```JavaScript\nvar highlighter = new Highlighter();\nhighlighter.on(Highlighter.event.CREATE, function (data, inst, e) {\n    // ...\n});\n```\n\nThe callback function will receive three parameters:\n\n- data `any`: event data\n- inst `Highlighter`: current Highlighter instance\n- e `Event`: some event is triggered by the browser (such as click), web-highlighter will expose it\n\n`Highlighter.event` is `EventType` type. It contains：\n\n- `EventType.CLICK`: click the highlighted area\n- `EventType.HOVER`: mouse enter the highlighted area\n- `EventType.HOVER_OUT`: mouse leave the highlighted area\n- `EventType.CREATE`: a highlighted area is created\n- `EventType.REMOVE`: a highlighted area is removed\n\n\nDifferent event has different `data`. Attributes below:\n\n#### `EventType.CLICK`\n\n|name|description|type|\n|---|---|---|\n|`id`|the highlight id|string|\n\n#### `EventType.HOVER`\n\n|name|description|type|\n|---|---|---|\n|`id`|the highlight id|string|\n\n#### `EventType.HOVER_OUT`\n\n|name|description|type|\n|---|---|---|\n|`id`|the highlight id|string|\n\n#### `EventType.CREATE`\n\n\u003e no parameter `e`\n\n|name|description|type|\n|---|---|---|\n|`source`|`HighlightSource` object|Array\u003cHighlightSource\u003e|\n|`type`|the reason for creating|string|\n\n`source` is a `HighlightSource` object. It is an object created by web-highlighter when highlighted area created. For persistence in backend (database), it's necessary to use a data structure which can be serialized (`JSON.stringify()`) to represent a dom node in browsers. `HighlightSource` is the data structure designed for this.\n\n`type` explains why a highlighted area is be created. Now `type` has two possible values: `from-input` and `from-store`. `from-input` shows that a highlighted area is created because of user's selection. `from-store` means it from a storage.\n\n#### `EventType.REMOVE`\n\n\u003e no parameter `e`\n\n|name|description|type|\n|---|---|---|\n|`ids`|a list of the highlight id|Array\u003cstring\u003e|\n\n### 5. Hooks\n\nHooks let you control the highlighting flow powerfully. You can almost customize any logic by hooks. See more in ['Advance' part](#Advance).\n\n## Compatibility\n\n\u003e It depends on [Selection API](https://caniuse.com/#search=selection%20api).\n\n- IE 11\n- Edge\n- Firefox 52+\n- Chrome 15+\n- Safari 5.1+\n- Opera 15+\n\n_**Mobile supports:**_ automatically detect whether mobile devices and use touch events when on mobile devices.\n\n## Advance\n\nIt provides some hooks for you so that the highlighting behaviour can be controlled better by your own.\n\nTo learn more about the hooks, read [this doc](https://github.com/alienzhou/web-highlighter/blob/master/docs/ADVANCE.md).\n\n## License\n\n[MIT](./LICENCE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falienzhou%2Fweb-highlighter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falienzhou%2Fweb-highlighter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falienzhou%2Fweb-highlighter/lists"}