TextHighlighter allows you to highlight text on web pages. Just select it!
Install the library by running:
$ npm install @perlego/text-highlighter
Then you can use it like so:
import TextHighlighter from '@perlego/text-highlighter';
// Example using a React ref if you are building a react application.
const highlighter = new TextHighlighter(sandboxRef.current);
// Example using an element accessed directly from the DOM.
const highlighter = new TextHighlighter(document.getElementById("sandbox"));
const TextHighlighter = require('@perlego/text-highlighter/cjs');
// Example using a React ref if you are building a react application.
const highlighter = new TextHighlighter(sandboxRef.current);
// Example using an element accessed directly from the DOM.
const highlighter = new TextHighlighter(document.getElementById("sandbox"));
One thing to note when using this library as a package, you are responsible for providing the polyfills for the core JavaScript features outlined in the latest ECMAScript specifications.
Within this library we use features such as Array.prototype.includes and Array.prototype.find which aren't support by IE11 without polyfills.
You will need to install core-js and regenerator-runtime.
npm install --save core-js regenerator-runtime
You can add the following two lines at the BEGINNING of your application's entrypoint file (index.js or main.js):
import "core-js/stable";
import "regenerator-runtime/runtime";
Clone down this repository, checkout to the release tag representing the version you would like to use. (2.x.x + only, this won't work for 1.x.x, please refer to the documentation provided with 1.x.x releases)
Ensure grunt is installed globally:
npm install -g grunt
Build the minified version of the library using the following command:
npm run build
Copy the script file from build/prod/TextHighlighter.min.js
to the head section of your web page:
<script type="text/javascript" src="TextHighlighter.min.js"></script>
And use it!
var hltr = new TextHighlighter(document.body);
- Highlighting of selected text.
- Highlighting all occurrences of given text (find & highlight).
- Removing highlights.
- Selecting highlight color.
- Serialization & deserialization.
- Focusing & deselecting overlapping highlights.
- Works well in iframes.
- Keeps DOM clean.
- No dependencies (apart from core-js and regenerator-runtime for IE11). No jQuery or other libraries needed.
You can find the API reference here which details the interface for the highlighter and the utility functionality that you could also make use of in your project.
import TextHighlighter from '@perlego/text-highlighter';
import { isDuplicate } from './utils';
import highlightsApi from './services/highlights-api';
class ArticleView {
constructor(data) {
this.data = data;
const pageElement = document.getElementById("article");
this.highlighter = new TextHighlighter(
pageElement,
{
version: "independencia",
onBeforeHighlight: this.onBeforeHighlight,
onAfterHighlight: this.onAfterHighlight,
preprocessDescriptors: this.preprocessDescriptors,
onRemoveHighlight: this.onRemoveHighlight
});
}
onBeforeHighlight = (range) => {
return !isDuplicate(range)
}
onRemoveHighlight = (highlightElement) => {
const proceed = window.confirm("Are you sure you want to remove this highlight?");
return proceed;
}
preprocessDescriptors = (range, descriptors, timestamp) => {
// Add an ID to the class list to identify each highlight
// (A highlight can be represented by a group of elements in the DOM).
const uniqueId = `hlt-${Math.random()
.toString(36)
.substring(2, 15) +
Math.random()
.toString(36)
.substring(2, 15)}`;
const descriptorsWithIds = descriptors.map(descriptor => {
const [wrapper, ...rest] = descriptor;
return [
wrapper.replace(
'class="highlighted"',
`class="highlighted ${uniqueId}"`
),
...rest
];
});
return { descriptors: descriptorsWithIds, meta: { id: uniqueId } };
}
onAfterHighlight = (range, descriptors, timestamp, meta) => {
highlightsApi.saveBatch(meta.id, descriptorsWithIds)
.then((result) => {
// Do something with the highlights that have been saved.
})
.catch((err) => console.error(err));
}
render = () => {
// Code that takes the data for the article and adds it to the DOM
// based on a html template here.
}
}
For the case where you want to trigger the process of creating highlights from a custom event fired in your application you can do something like the following:
import TextHighlighter from '@perlego/text-highlighter';
import { isDuplicate } from './utils';
import highlightsApi from './services/highlights-api';
class ArticleView {
constructor(data) {
this.data = data;
const pageElement = document.getElementById("article");
this.createButton = document.getElementById("create-highlight");
this.highlighter = new TextHighlighter(
pageElement,
{
version: "independencia",
useDefaultEvents: false,
onBeforeHighlight: this.onBeforeHighlight,
onAfterHighlight: this.onAfterHighlight,
preprocessDescriptors: this.preprocessDescriptors,
onRemoveHighlight: this.onRemoveHighlight
});
// Add your custom event handler.
this.highlightHandler = highlighter.highlightHandler.bind(highlighter);
createButton.addEventListener("click", this.highlightHandler);
}
// Your custom method that ensures the event handler is removed from the button click.
destroy() {
createButton.removeEventListener("click", this.highlightHanlder);
}
onBeforeHighlight = (range) => {
return !isDuplicate(range)
}
onRemoveHighlight = (highlightElement) => {
const proceed = window.confirm("Are you sure you want to remove this highlight?");
return proceed;
}
preprocessDescriptors = (range, descriptors, timestamp) => {
// Add an ID to the class list to identify each highlight
// (A highlight can be represented by a group of elements in the DOM).
const uniqueId = `hlt-${Math.random()
.toString(36)
.substring(2, 15) +
Math.random()
.toString(36)
.substring(2, 15)}`;
const descriptorsWithIds = descriptors.map(descriptor => {
const [wrapper, ...rest] = descriptor;
return [
wrapper.replace(
'class="highlighted"',
`class="highlighted ${uniqueId}"`
),
...rest
];
});
return { descriptors: descriptorsWithIds, meta: { id: uniqueId } };
}
onAfterHighlight = (range, descriptors, timestamp, meta) => {
highlightsApi.saveBatch(meta.id, descriptorsWithIds)
.then((result) => {
// Do something with the highlights that have been saved.
})
.catch((err) => console.error(err));
}
render = () => {
// Code that takes the data for the article and adds it to the DOM
// based on a html template here.
}
}
See the TextHighlighter API Reference for the list of all the options, their default values and detailed descriptions.
Should work in all decent browsers and IE 11.
First run npm install
from the root directory of the repo to install all the test runner dependencies.
To run both integration and unit tests at once use the following:
npm run test:all
The integration tests covers the integration of the larger components that make up the highlighting functionality such as serialisation + deserialisation, focusing, deselecting, normalisation and interaction with callbacks.
To run the integration tests use the following command:
npm run test:integration
The unit tests cover functions that make up the smaller components that query, manipulate the DOM along with pure utility pieces.
To run the unit tests use the following command:
npm run test:unit
The first version of the highlighter contains tests in a standalone jasmine runner that runs in the browser.
To run those tests, first set up the server:
node webserver.js
Then go to http://localhost:5002/test/test.html
and the tests will run on page load.
There is a cjs version of the library that gets tracked in version control that is built whenever changes are made.
This is done automatically through a commit hook whenever you make a commit to the repo.
If you need to build this version of the library manually, you can use the following:
npm run build:cjs
And then commit the changes in the cjs folder to version control.
Ensure all dev dependencies are installed using:
npm install
Ensure grunt is installed globally:
npm install -g grunt
To build the documentation, run the following command:
grunt jsdoc
Ensure the test server is running:
node webserver.js
Then go to http://localhost:5002/doc
to see the API reference for the library.
You may check API reference or Wiki pages on GitHub.