* false if invalid.
*/
validationCallback?: LinkMatcherValidationCallback;
+ /**
+ * The priority of the link matcher, this defines the order in which the link
+ * matcher is evaluated relative to others, from highest to lowest. The
+ * default value is 0.
+ */
+ priority?: number;
}
/**
import { assert } from 'chai';
import { ITerminal, ILinkifier } from './Interfaces';
import { Linkifier } from './Linkifier';
+import { LinkMatcher } from './Types';
class TestLinkifier extends Linkifier {
constructor(document: Document, rows: HTMLElement[]) {
Linkifier.TIME_BEFORE_LINKIFY = 0;
super(document, rows);
}
+
+ public get linkMatchers(): LinkMatcher[] { return this._linkMatchers; }
}
describe('Linkifier', () => {
let container: HTMLElement;
let rows: HTMLElement[];
- let linkifier: ILinkifier;
+ let linkifier: TestLinkifier;
beforeEach(done => {
rows = [];
jsdom.env('', (err, w) => {
window = w;
document = window.document;
- linkifier = new Linkifier(document, rows);
+ linkifier = new TestLinkifier(document, rows);
container = document.createElement('div');
document.body.appendChild(container);
done();
setTimeout(() => done(), 10);
});
});
+
+ describe('priority', () => {
+ it('should order the list from highest priority to lowest #1', () => {
+ const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 1 });
+ const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: -1 });
+ assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [aId, 0, bId]);
+ });
+
+ it('should order the list from highest priority to lowest #2', () => {
+ const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: -1 });
+ const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 1 });
+ assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [bId, 0, aId]);
+ });
+
+ it('should order items of equal priority in the order they are added', () => {
+ const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 0 });
+ const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 0 });
+ assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [0, aId, bId]);
+ });
+ });
});
*/
import { LinkMatcherOptions } from './Interfaces';
-import { LinkMatcherHandler, LinkMatcherValidationCallback } from './Types';
-
-type LinkMatcher = {
- id: number,
- regex: RegExp,
- handler: LinkMatcherHandler,
- matchIndex?: number,
- validationCallback?: LinkMatcherValidationCallback;
-};
+import { LinkMatcher, LinkMatcherHandler, LinkMatcherValidationCallback } from './Types';
const INVALID_LINK_CLASS = 'xterm-invalid-link';
*/
protected static TIME_BEFORE_LINKIFY = 200;
+ protected _linkMatchers: LinkMatcher[];
+
private _document: Document;
private _rows: HTMLElement[];
private _rowTimeoutIds: number[];
- private _linkMatchers: LinkMatcher[];
private _nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID;
constructor(document: Document, rows: HTMLElement[]) {
regex,
handler,
matchIndex: options.matchIndex,
- validationCallback: options.validationCallback
+ validationCallback: options.validationCallback,
+ priority: options.priority || 0
};
- this._linkMatchers.push(matcher);
+ this._addLinkMatcherToList(matcher);
return matcher.id;
}
+ /**
+ * Inserts a link matcher to the list in the correct position based on the
+ * priority of each link matcher. New link matchers of equal priority are
+ * considered after older link matchers.
+ * @param matcher The link matcher to be added.
+ */
+ private _addLinkMatcherToList(matcher: LinkMatcher): void {
+ if (this._linkMatchers.length === 0) {
+ this._linkMatchers.push(matcher);
+ return;
+ }
+
+ for (let i = this._linkMatchers.length - 1; i >= 0; i--) {
+ if (matcher.priority === this._linkMatchers[i].priority) {
+ this._linkMatchers.splice(i + 1, 0, matcher);
+ return;
+ }
+ }
+
+ if (matcher.priority > this._linkMatchers[0].priority) {
+ this._linkMatchers.splice(0, 0, matcher);
+ } else {
+ this._linkMatchers.push(matcher);
+ }
+ }
+
/**
* Deregisters a link matcher if it has been registered.
* @param {number} matcherId The link matcher's ID (returned after register)
return;
}
const text = row.textContent;
- // TODO: Onl execute handler if isValid
for (let i = 0; i < this._linkMatchers.length; i++) {
const matcher = this._linkMatchers[i];
const uri = this._findLinkMatch(text, matcher.regex, matcher.matchIndex);
* @license MIT
*/
+export type LinkMatcher = {
+ id: number,
+ regex: RegExp,
+ handler: LinkMatcherHandler,
+ matchIndex?: number,
+ validationCallback?: LinkMatcherValidationCallback,
+ priority?: number
+};
export type LinkMatcherHandler = (uri: string) => void;
export type LinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void;