From b30cb58ff42419e406c6abb1492101f7fb4e6c21 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 3 Sep 2017 12:47:04 -0700 Subject: [PATCH] Support hover callback in links --- src/Interfaces.ts | 4 ++++ src/Linkifier.ts | 12 ++++++------ src/Terminal.ts | 8 ++++---- src/input/Interfaces.ts | 2 +- src/input/MouseZoneManager.ts | 27 +++++++++++++++++++++++---- 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 7ebf6983..ace4012e 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -236,6 +236,10 @@ export interface ILinkMatcherOptions { * false if invalid. */ validationCallback?: LinkMatcherValidationCallback; + /** + * A callback that fired when the mouse hovers over a link. + */ + hoverCallback?: LinkMatcherHandler; /** * 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 diff --git a/src/Linkifier.ts b/src/Linkifier.ts index f92badcf..20c5b713 100644 --- a/src/Linkifier.ts +++ b/src/Linkifier.ts @@ -65,7 +65,6 @@ export class Linkifier { * @param rows The array of rows to apply links to. */ public attachToDom(mouseZoneManager: IMouseZoneManager): void { - console.log('attachToDom', mouseZoneManager); this._mouseZoneManager = mouseZoneManager; } @@ -147,6 +146,7 @@ export class Linkifier { handler, matchIndex: options.matchIndex, validationCallback: options.validationCallback, + hoverCallback: options.hoverCallback, priority: options.priority || 0 }; this._addLinkMatcherToList(matcher); @@ -250,16 +250,16 @@ export class Linkifier { x + 1, x + 1 + uri.length, y + 1, - e => { - if (matcher.hoverCallback) { - return matcher.hoverCallback(e, uri); - } - }, e => { if (matcher.handler) { return matcher.handler(e, uri); } window.open(uri, '_blink'); + }, + e => { + if (matcher.hoverCallback) { + return matcher.hoverCallback(e, uri); + } } )); } diff --git a/src/Terminal.ts b/src/Terminal.ts index 6f93ca2d..c3d360bb 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1223,7 +1223,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT } this.linkifier.setHypertextLinkHandler(handler); // Refresh to force links to refresh - // this.refresh(0, this.rows - 1); + this.refresh(0, this.rows - 1); } /** @@ -1238,7 +1238,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT } this.linkifier.setHypertextValidationCallback(callback); // // Refresh to force links to refresh - // this.refresh(0, this.rows - 1); + this.refresh(0, this.rows - 1); } /** @@ -1254,7 +1254,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT public registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options?: ILinkMatcherOptions): number { if (this.linkifier) { const matcherId = this.linkifier.registerLinkMatcher(regex, handler, options); - // this.refresh(0, this.rows - 1); + this.refresh(0, this.rows - 1); return matcherId; } return 0; @@ -1267,7 +1267,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT public deregisterLinkMatcher(matcherId: number): void { if (this.linkifier) { if (this.linkifier.deregisterLinkMatcher(matcherId)) { - // this.refresh(0, this.rows - 1); + this.refresh(0, this.rows - 1); } } } diff --git a/src/input/Interfaces.ts b/src/input/Interfaces.ts index d0c0e480..15dcbae9 100644 --- a/src/input/Interfaces.ts +++ b/src/input/Interfaces.ts @@ -7,6 +7,6 @@ export interface IMouseZone { x1: number; x2: number; y: number; - hoverCallback: (e: MouseEvent) => any; clickCallback: (e: MouseEvent) => any; + hoverCallback?: (e: MouseEvent) => any; } diff --git a/src/input/MouseZoneManager.ts b/src/input/MouseZoneManager.ts index 6d8f017a..37a6647d 100644 --- a/src/input/MouseZoneManager.ts +++ b/src/input/MouseZoneManager.ts @@ -2,6 +2,8 @@ import { IMouseZoneManager, IMouseZone } from './Interfaces'; import { ITerminal } from '../Interfaces'; import { getCoords } from '../utils/Mouse'; +const HOVER_DURATION = 500; + /** * The MouseZoneManager allows components to register zones within the terminal * that trigger hover and click callbacks. @@ -18,6 +20,9 @@ export class MouseZoneManager implements IMouseZoneManager { private _mouseDownListener: (e: MouseEvent) => any; private _clickListener: (e: MouseEvent) => any; + private _hoverTimeout: number; + private _lastHoverCoords: [number, number] = [null, null]; + constructor( private _terminal: ITerminal ) { @@ -55,7 +60,21 @@ export class MouseZoneManager implements IMouseZoneManager { } private _onMouseMove(e: MouseEvent): void { - // TODO: Handle hover + if (this._lastHoverCoords[0] !== e.pageX && this._lastHoverCoords[1] !== e.pageY) { + if (this._hoverTimeout) { + clearTimeout(this._hoverTimeout); + } + this._hoverTimeout = setTimeout(() => this._onHover(e), HOVER_DURATION); + this._lastHoverCoords = [e.pageX, e.pageY]; + } + } + + private _onHover(e: MouseEvent): void { + const coords = getCoords(e, this._terminal.element, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows); + const zone = this._findZoneEventAt(e); + if (zone && zone.hoverCallback) { + zone.hoverCallback(e); + } } private _onClick(e: MouseEvent): void { @@ -67,7 +86,7 @@ export class MouseZoneManager implements IMouseZoneManager { } private _findZoneEventAt(e: MouseEvent): IMouseZone { - const coords = getCoords(e, this._terminal.element, this._terminal.charMeasure,this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows); + const coords = getCoords(e, this._terminal.element, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows); for (let i = 0; i < this._zones.length; i++) { const zone = this._zones[i]; if (zone.y === coords[1] && zone.x1 <= coords[0] && zone.x2 > coords[0]) { @@ -83,8 +102,8 @@ export class MouseZone implements IMouseZone { public x1: number, public x2: number, public y: number, - public hoverCallback: (e: MouseEvent) => any, - public clickCallback: (e: MouseEvent) => any + public clickCallback: (e: MouseEvent) => any, + public hoverCallback?: (e: MouseEvent) => any ) { } }