IndexManager

Type: Class

How to get indexManager?

JavaScript

import indexManager from 'fontoxml-indices/src/indexManager.js'

Provides a way to continuously run XPath queries on the loaded documents in an efficient way.

Properties

changesProcessedNotifier

Type: Notifier

Notifier which can be used to be notified when all changes for a transaction have been processed.

If other indexed values are queried synchronously inside an invalidation callback, performance may suffer when a transaction invalidates multiple values. The recommended way to handle such situations is to collect invalidations and use a timeout or animation frame to schedule querying the updated values, effectively "debouncing" the invalidation signals.

However, in some cases this asynchronous approach is not an option. In those cases this notifier may be used as a synchronous point at which all indices have been invalidated as a result of the changes made by some transaction.

Methods

observeQueryResults

Type: Function

Add a query for which results should be observed, the result of which may be a boolean, a string or a number of nodes. Observed queries will signal possible changes to the results. When the notifier triggers, the results of the query may have changed. Note that re-evaluating the query when the notifier is triggered may yield the same result as before. It may happen that the query has been evaluated differently to yield the same result. However, the results are guaranteed not to have changed if the notifier is not triggered.

Note that the notifier will not be triggered before the first call to getResults.

For the more specific problem of returning descendants of a node matching a selector, consider using the methods on DescendantIndexManager, which provide increased performance by imposing some restrictions on the query.

Example

JavaScript

import indexManager from 'fontoxml-indices/src/indexManager.js';

const observer = indexManager.observeQueryResults('//fn => count()', documentNode, {
	expectedResultType: evaluateXPath.NUMBER_TYPE
});
const removeCallback = observer.resultsChangedNotifier.addCallback(function() {
	console.log('Currently #' + observer.getResults() + ' footnotes present in this document');
});

function destroy() {
	observer.stopObservingQueryResults();
	removeCallback();
}

Performance

Due to the nature of this API, it may heavily impact performance when used incorrectly. Please follow these guidelines to prevent this:

Debouncing

The notifier returned by this API will trigger every time the value for getResults may change. Calling getResults will evaluate the query immediately.

This frequency of updates is not always needed, especially for queries that invalidate on every keystroke. Consider to either make the usage a pull-based system, where another component decides the timing, or use a debounce to limit these updates.

Dependencies

Whether an XML change will cause the resultsChangedNotifier to be fired is determined by the dependencies of the query, as well as the XML changes that were just made.

Some queries have more dependencies than others. Take for example the query ./div. This query will only invalidate when the childNodes of the context node change. Contrast this with the ./descendant::div, which is invalidated whenever the childNodes of any descendant of the context node change, which is way more often. Even worse is the .//div query, which is per spec expanded to ./descendant-or-self::node()/child::div. The descendant-or-self::node() part may be invalidated by every keystroke a user performs, especially when the fontoxml-track-changes add-on is enabled.

In general, try to limit the dependencies for your query. When in doubt, please use the Dependencies tab in the XPath plaground..

The dependency tracking framework is discussed in more detail in the proceedings of XML Prague 2017, Soft validation in an editor environment: https://archive.xmlprague.cz/2017/files/xmlprague-2017-proceedings.pdf#page=31

Arguments

Returns