Merge "Listen to token highlights"
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index 26701e8..1453fd0 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -209,6 +209,18 @@
line_wrapping?: boolean;
}
+/**
+ * Listens to changes in token highlighting - when a new token starts or stopped being highlighted.
+ * Examples:
+ * - Token highlighted: ('myFunctionName', 12, [Element]).
+ * - Token unhighlighted: (undefined, 0, undefined).
+ */
+export type TokenHighlightedListener = (
+ newHighlight: string | undefined,
+ newLineNumber: number,
+ hoveredElement?: Element
+) => void;
+
export declare interface ImageDiffPreferences {
automatic_blink?: boolean;
}
diff --git a/polygerrit-ui/app/api/embed.ts b/polygerrit-ui/app/api/embed.ts
index ba378e2..fed724e 100644
--- a/polygerrit-ui/app/api/embed.ts
+++ b/polygerrit-ui/app/api/embed.ts
@@ -20,14 +20,24 @@
* limitations under the License.
*/
-import {DiffLayer, GrAnnotation, GrDiffCursor} from './diff';
+import {
+ DiffLayer,
+ GrAnnotation,
+ GrDiffCursor,
+ TokenHighlightedListener,
+} from './diff';
declare global {
interface Window {
grdiff: {
GrAnnotation: GrAnnotation;
GrDiffCursor: {new (): GrDiffCursor};
- TokenHighlightLayer: {new (container?: HTMLElement): DiffLayer};
+ TokenHighlightLayer: {
+ new (
+ container?: HTMLElement,
+ listener?: TokenHighlightedListener
+ ): DiffLayer;
+ };
};
}
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
index 56bb073..480e26c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import {DiffLayer, DiffLayerListener} from '../../../types/types';
-import {GrDiffLine, Side} from '../../../api/diff';
+import {GrDiffLine, Side, TokenHighlightedListener} from '../../../api/diff';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
import {debounce, DelayedTask} from '../../../utils/async-util';
import {
@@ -65,6 +65,9 @@
/** The currently highlighted token. */
private currentHighlight?: string;
+ /** Trigger when a new token starts or stoped being highlighted.*/
+ private readonly tokenHighlightedListener?: TokenHighlightedListener;
+
/**
* The line of the currently highlighted token. We store this in order to
* re-render only relevant lines of the diff. Only lines visible on the screen
@@ -95,7 +98,11 @@
private updateTokenTask?: DelayedTask;
- constructor(container: HTMLElement = document.documentElement) {
+ constructor(
+ container: HTMLElement = document.documentElement,
+ tokenHighlightedListener?: TokenHighlightedListener
+ ) {
+ this.tokenHighlightedListener = tokenHighlightedListener;
container.addEventListener('click', e => {
this.handleContainerClick(e);
});
@@ -188,7 +195,7 @@
this.updateTokenTask = debounce(
this.updateTokenTask,
() => {
- this.updateTokenHighlight(newHighlight, line);
+ this.updateTokenHighlight(newHighlight, line, element);
},
HOVER_DELAY_MS
);
@@ -203,7 +210,7 @@
if (element) return;
this.hoveredElement = undefined;
this.updateTokenTask?.cancel();
- this.updateTokenHighlight(undefined, 0);
+ this.updateTokenHighlight(undefined, 0, undefined);
}
private interferesWithSelection() {
@@ -241,7 +248,8 @@
private updateTokenHighlight(
newHighlight: string | undefined,
- newLineNumber: number
+ newLineNumber: number,
+ newHoveredElement: Element | undefined
) {
if (
this.currentHighlight === newHighlight &&
@@ -253,6 +261,13 @@
this.currentHighlight = newHighlight;
this.currentHighlightLineNumber = newLineNumber;
+ if (this.tokenHighlightedListener) {
+ this.tokenHighlightedListener(
+ newHighlight,
+ newLineNumber,
+ newHoveredElement
+ );
+ }
this.notifyForToken(oldHighlight, oldLineNumber);
this.notifyForToken(newHighlight, newLineNumber);
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts
index 9fc69b5..2cb08d6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts
@@ -66,12 +66,22 @@
let container: HTMLElement;
let listener: MockListener;
let highlighter: TokenHighlightLayer;
+ let tokenHighlightingCalls: any[] = [];
+
+ function tokenHighlightedListener(
+ newHighlight: string | undefined,
+ newLineNumber: number,
+ hoveredElement?: Element
+ ) {
+ tokenHighlightingCalls.push({newHighlight, newLineNumber, hoveredElement});
+ }
setup(async () => {
listener = new MockListener();
+ tokenHighlightingCalls = [];
container = document.createElement('div');
document.body.appendChild(container);
- highlighter = new TokenHighlightLayer(container);
+ highlighter = new TokenHighlightLayer(container, tokenHighlightedListener);
highlighter.addListener((...args) => listener.notify(...args));
});
@@ -251,6 +261,37 @@
assert.equal(_testOnly_allTasks.size, 0);
});
+ test('triggers listener for applying and clearing highlighting', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words', 2);
+ annotate(line2, Side.RIGHT, 2);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+ assert.equal(tokenHighlightingCalls.length, 0);
+ clock.tick(HOVER_DELAY_MS);
+ assert.equal(tokenHighlightingCalls.length, 1);
+ assert.deepEqual(tokenHighlightingCalls[0], {
+ newHighlight: 'words',
+ newLineNumber: 1,
+ hoveredElement: words1,
+ });
+
+ MockInteractions.click(container);
+ assert.equal(tokenHighlightingCalls.length, 2);
+ assert.deepEqual(tokenHighlightingCalls[1], {
+ newHighlight: undefined,
+ newLineNumber: 0,
+ hoveredElement: undefined,
+ });
+ });
+
test('clicking clears highlight', async () => {
const clock = sinon.useFakeTimers();
const line1 = createLine('two words');