@theia/core 1.75.0 → 1.76.0-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,18 +54,54 @@ var HoverPosition;
54
54
  return position;
55
55
  }
56
56
  HoverPosition.invertIfNecessary = invertIfNecessary;
57
+ /**
58
+ * Tests whether a hover of the given dimensions fits next to its target in the given
59
+ * position without extending beyond the window bounds.
60
+ */
61
+ function fits(position, target, host, totalWidth, totalHeight) {
62
+ if (position === 'left') {
63
+ return target.left - host.width - 5 >= 0;
64
+ }
65
+ else if (position === 'right') {
66
+ return target.right + host.width + 5 <= totalWidth;
67
+ }
68
+ else if (position === 'top') {
69
+ return target.top - host.height - 5 >= 0;
70
+ }
71
+ else {
72
+ return target.bottom + host.height + 5 <= totalHeight;
73
+ }
74
+ }
75
+ HoverPosition.fits = fits;
57
76
  })(HoverPosition || (exports.HoverPosition = HoverPosition = {}));
58
77
  let HoverService = class HoverService {
59
78
  constructor() {
79
+ /** Identifies the latest render so that superseded renders can detect they are stale. */
80
+ this.renderSequence = 0;
60
81
  this.lastHidHover = Date.now();
61
82
  this.disposeOnHide = new common_1.DisposableCollection();
62
83
  }
63
84
  static { HoverService_1 = this; }
64
85
  static { this.hostClassName = 'theia-hover'; }
65
86
  static { this.styleSheetId = 'theia-hover-style'; }
87
+ /**
88
+ * The host of the current hover, which may live in a secondary window's document.
89
+ * Resolving against the main document here instead would silently replace the host
90
+ * whenever the current hover lives in another document, detaching the dismissal
91
+ * listeners and `unRenderHover` from the host that is actually rendered.
92
+ */
66
93
  get hoverHost() {
67
- if (!this._hoverHost) {
68
- this._hoverHost = document.createElement('div');
94
+ return this._hoverHost ?? this.getOrCreateHoverHost(document);
95
+ }
96
+ /**
97
+ * Returns the host element to render hovers into for the given document, creating it if the
98
+ * current one belongs to a different document. A host is always created in the document it is
99
+ * shown in: adopting a host into another document would let it outlive its window, and touching
100
+ * it after that window was closed breaks (and in Electron crashes) the application.
101
+ */
102
+ getOrCreateHoverHost(targetDocument) {
103
+ if (!this._hoverHost || this._hoverHost.ownerDocument !== targetDocument) {
104
+ this._hoverHost = targetDocument.createElement('div');
69
105
  this._hoverHost.classList.add(HoverService_1.hostClassName);
70
106
  this._hoverHost.style.position = 'absolute';
71
107
  this._hoverHost.setAttribute('popover', 'hint');
@@ -74,21 +110,51 @@ let HoverService = class HoverService {
74
110
  }
75
111
  requestHover(request) {
76
112
  this.cancelHover();
113
+ const targetWindow = request.target.ownerDocument.defaultView;
114
+ if (!targetWindow || targetWindow.closed) {
115
+ // the window hosting the target is already gone, e.g. a closed secondary window:
116
+ // its document must not be touched anymore
117
+ return;
118
+ }
77
119
  const delay = request.skipHoverDelay ? 0 : this.getHoverDelay();
78
120
  this.pendingTimeout = (0, common_1.disposableTimeout)(() => this.renderHover(request), delay);
79
121
  this.hoverTarget = request.target;
122
+ // resolve the host for the target's document up front so that the listeners below attach to the host that will be rendered
123
+ this.getOrCreateHoverHost(request.target.ownerDocument);
124
+ this.listenForWindowClose(request.target);
80
125
  this.listenForMouseOut();
81
126
  this.listenForMouseClick(request);
82
127
  }
128
+ /**
129
+ * Cancels the hover when the window hosting the target element goes away, e.g. when the
130
+ * secondary window containing the target is closed: neither the hover host nor any listeners
131
+ * may outlive the document they belong to.
132
+ */
133
+ listenForWindowClose(target) {
134
+ const targetWindow = target.ownerDocument.defaultView;
135
+ if (!targetWindow || targetWindow === window) {
136
+ return;
137
+ }
138
+ const handlePageHide = () => this.cancelHover();
139
+ targetWindow.addEventListener('pagehide', handlePageHide);
140
+ this.disposeOnHide.push({ dispose: () => targetWindow.removeEventListener('pagehide', handlePageHide) });
141
+ }
83
142
  getHoverDelay() {
84
143
  return Date.now() - this.lastHidHover < quickMouseThresholdMillis
85
144
  ? 0
86
145
  : this.preferences.get('workbench.hover.delay', common_1.isOSX ? 1500 : 500);
87
146
  }
88
147
  async renderHover(request) {
89
- const host = this.hoverHost;
90
- let firstChild;
91
148
  const { target, content, position, cssClasses, interactive, onHide } = request;
149
+ const targetWindow = target.ownerDocument.defaultView;
150
+ if (!targetWindow || targetWindow.closed) {
151
+ // the window hosting the target is already gone, e.g. a closed secondary window:
152
+ // its document must not be touched anymore
153
+ return;
154
+ }
155
+ const host = this.getOrCreateHoverHost(target.ownerDocument);
156
+ const sequence = ++this.renderSequence;
157
+ let firstChild;
92
158
  if (onHide) {
93
159
  this.disposeOnHide.push({ dispose: onHide.bind(request) });
94
160
  }
@@ -119,7 +185,9 @@ let HoverService = class HoverService {
119
185
  // handler then cancels the hover, and the cycle repeats: the tooltip flickers and never settles.
120
186
  // `visibility: hidden` still lays the host out (so it can be measured) but is not hit-tested.
121
187
  host.style.visibility = 'hidden';
122
- document.body.append(host);
188
+ // Render the hover in the document of the target: it may be hosted in a secondary window,
189
+ // whose coordinate space is unrelated to the main window's.
190
+ target.ownerDocument.body.append(host);
123
191
  if (!host.matches(':popover-open')) {
124
192
  host.showPopover();
125
193
  }
@@ -141,7 +209,12 @@ let HoverService = class HoverService {
141
209
  host.appendChild(visualPreview);
142
210
  }
143
211
  }
144
- await (0, browser_1.animationFrame)(); // Allow the browser to size the host
212
+ await this.hostAnimationFrame(target); // Allow the browser to size the host
213
+ if (sequence !== this.renderSequence || !host.isConnected) {
214
+ // this hover was cancelled or superseded by a newer one while waiting for the animation
215
+ // frame: it must neither reposition nor reveal the host
216
+ return;
217
+ }
145
218
  const updatedPosition = this.setHostPosition(target, host, position);
146
219
  // Reveal the host only once it sits at its final position, so it never overlaps the target while
147
220
  // parked at (0,0). Dropping the declaration rather than assigning a value hands `visibility` back
@@ -157,14 +230,36 @@ let HoverService = class HoverService {
157
230
  }
158
231
  });
159
232
  }
233
+ /**
234
+ * Waits for an animation frame in the window hosting the given target element,
235
+ * which may be a secondary window whose rendering is independent of the main window's.
236
+ */
237
+ hostAnimationFrame(target) {
238
+ const targetWindow = target.ownerDocument.defaultView;
239
+ if (!targetWindow || targetWindow === window) {
240
+ return (0, browser_1.animationFrame)();
241
+ }
242
+ return new Promise(resolve => targetWindow.requestAnimationFrame(() => resolve()));
243
+ }
160
244
  setHostPosition(target, host, position) {
245
+ const hostDocument = target.ownerDocument;
161
246
  const targetDimensions = target.getBoundingClientRect();
162
247
  const hostDimensions = host.getBoundingClientRect();
163
- const documentWidth = document.body.getBoundingClientRect().width;
248
+ const documentWidth = hostDocument.body.getBoundingClientRect().width;
164
249
  // document.body.getBoundingClientRect().height doesn't work as expected
165
250
  // scrollHeight will always be accurate here: https://stackoverflow.com/a/44077777
166
- const documentHeight = document.documentElement.scrollHeight;
251
+ const documentHeight = hostDocument.documentElement.scrollHeight;
167
252
  position = HoverPosition.invertIfNecessary(position, targetDimensions, hostDimensions, documentWidth, documentHeight);
253
+ if (!HoverPosition.fits(position, targetDimensions, hostDimensions, documentWidth, documentHeight)) {
254
+ // The hover fits on neither side of the target in the requested direction, e.g. when the
255
+ // target spans the full width of a narrow secondary window. Try the perpendicular direction
256
+ // so that the target and the hover both remain visible. If that does not fit either,
257
+ // keep the requested direction; the clamping below keeps the hover inside the viewport.
258
+ const fallback = HoverPosition.invertIfNecessary(position === 'left' || position === 'right' ? 'bottom' : 'right', targetDimensions, hostDimensions, documentWidth, documentHeight);
259
+ if (HoverPosition.fits(fallback, targetDimensions, hostDimensions, documentWidth, documentHeight)) {
260
+ position = fallback;
261
+ }
262
+ }
168
263
  if (position === 'top' || position === 'bottom') {
169
264
  const targetMiddleWidth = targetDimensions.left + (targetDimensions.width / 2);
170
265
  const middleAlignment = targetMiddleWidth - (hostDimensions.width / 2);
@@ -182,9 +277,13 @@ let HoverService = class HoverService {
182
277
  const middleAlignment = targetMiddleHeight - (hostDimensions.height / 2);
183
278
  const furthestTop = Math.min(documentHeight - hostDimensions.height, middleAlignment);
184
279
  const top = Math.max(0, furthestTop);
185
- const left = position === 'left'
280
+ const desiredLeft = position === 'left'
186
281
  ? targetDimensions.left - hostDimensions.width - 5
187
282
  : targetDimensions.right + 5;
283
+ // the hover may not fit on either side of the target, e.g. when the target
284
+ // spans the full width of a narrow (secondary) window: keep it in the viewport
285
+ const furthestRight = Math.min(documentWidth - hostDimensions.width, desiredLeft);
286
+ const left = Math.max(0, furthestRight);
188
287
  host.style.setProperty('--theia-hover-before-position', `${targetMiddleHeight - top - 5}px`);
189
288
  host.style.left = `${left}px`;
190
289
  host.style.top = `${top}px`;
@@ -229,18 +328,44 @@ let HoverService = class HoverService {
229
328
  this.cancelHover();
230
329
  }
231
330
  };
232
- document.addEventListener('mousedown', handleMouseDown, true);
233
- this.disposeOnHide.push({ dispose: () => document.removeEventListener('mousedown', handleMouseDown, true) });
331
+ // Listen in the document of the target, which may be hosted in a secondary window
332
+ const targetDocument = request.target.ownerDocument;
333
+ targetDocument.addEventListener('mousedown', handleMouseDown, true);
334
+ this.disposeOnHide.push({ dispose: () => targetDocument.removeEventListener('mousedown', handleMouseDown, true) });
234
335
  }
235
336
  unRenderHover() {
236
- if (this.hoverHost.matches(':popover-open')) {
237
- this.hoverHost.hidePopover();
337
+ const host = this._hoverHost;
338
+ if (!host) {
339
+ return;
238
340
  }
239
- this.hoverHost.remove();
240
- this.hoverHost.replaceChildren();
341
+ const hostWindow = host.ownerDocument.defaultView;
342
+ if (!hostWindow || hostWindow.closed) {
343
+ // the window hosting the hover is already gone, e.g. a closed secondary window:
344
+ // its DOM must not be touched anymore; abandon the host and start from scratch
345
+ this._hoverHost = undefined;
346
+ return;
347
+ }
348
+ try {
349
+ if (host.matches(':popover-open')) {
350
+ host.hidePopover();
351
+ }
352
+ }
353
+ catch {
354
+ // hidePopover throws for popovers in documents that are no longer fully active,
355
+ // e.g. while the secondary window hosting the hover is being closed
356
+ }
357
+ host.remove();
358
+ host.replaceChildren();
359
+ // drop the classes added for the rendered hover (position and request classes): a render
360
+ // aborted because it was superseded must not leak its classes into the next hover
361
+ host.className = HoverService_1.hostClassName;
241
362
  // The host is reused across hovers; drop the transient hidden state set during measurement so a
242
363
  // hover cancelled before it was revealed does not leave the next one invisible.
243
- this.hoverHost.style.removeProperty('visibility');
364
+ host.style.removeProperty('visibility');
365
+ if (host.ownerDocument !== document) {
366
+ // never keep a host from another document: it must not outlive its window
367
+ this._hoverHost = undefined;
368
+ }
244
369
  }
245
370
  };
246
371
  exports.HoverService = HoverService;
@@ -1 +1 @@
1
- {"version":3,"file":"hover-service.js","sourceRoot":"","sources":["../../src/browser/hover-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hover-service.js","sourceRoot":"","sources":["../../src/browser/hover-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hover-service.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover-service.spec.d.ts","sourceRoot":"","sources":["../../src/browser/hover-service.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,326 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 Safi Seid-Ahmad, K2view and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const jsdom_1 = require("./test/jsdom");
19
+ let disableJSDOM = (0, jsdom_1.enableJSDOM)();
20
+ const inversify_1 = require("inversify");
21
+ const chai_1 = require("chai");
22
+ const hover_service_1 = require("./hover-service");
23
+ const common_1 = require("../common");
24
+ const markdown_renderer_1 = require("./markdown-rendering/markdown-renderer");
25
+ const opener_service_1 = require("./opener-service");
26
+ disableJSDOM();
27
+ /* eslint-disable @typescript-eslint/no-explicit-any */
28
+ describe('HoverService', () => {
29
+ let container;
30
+ let hoverService;
31
+ let originalMatches;
32
+ before(() => {
33
+ disableJSDOM = (0, jsdom_1.enableJSDOM)();
34
+ // The hover service positions its host after waiting for an animation frame.
35
+ // JSDOM (without pretendToBeVisual) does not provide requestAnimationFrame.
36
+ global.requestAnimationFrame = (cb) => setTimeout(cb, 0);
37
+ // JSDOM implements neither the Popover API (showPopover/hidePopover) nor the
38
+ // `:popover-open` pseudo-class: stub them, tracking the open state in an attribute.
39
+ const elementPrototype = window.HTMLElement.prototype;
40
+ elementPrototype.showPopover = function () { this.setAttribute('data-test-popover-open', 'true'); };
41
+ elementPrototype.hidePopover = function () { this.removeAttribute('data-test-popover-open'); };
42
+ originalMatches = elementPrototype.matches;
43
+ elementPrototype.matches = function (selectors) {
44
+ return selectors === ':popover-open' ? this.hasAttribute('data-test-popover-open') : originalMatches.call(this, selectors);
45
+ };
46
+ });
47
+ after(() => {
48
+ const elementPrototype = window.HTMLElement.prototype;
49
+ delete elementPrototype.showPopover;
50
+ delete elementPrototype.hidePopover;
51
+ elementPrototype.matches = originalMatches;
52
+ delete global.requestAnimationFrame;
53
+ disableJSDOM();
54
+ });
55
+ beforeEach(() => {
56
+ container = new inversify_1.Container();
57
+ container.bind(hover_service_1.HoverService).toSelf().inSingletonScope();
58
+ container.bind(common_1.PreferenceService).toConstantValue({ get: () => 0 });
59
+ container.bind(markdown_renderer_1.CoreMarkdownRenderer).toConstantValue({ render: () => ({ element: document.createElement('div'), dispose: () => { } }) });
60
+ container.bind(opener_service_1.OpenerService).toConstantValue({});
61
+ hoverService = container.get(hover_service_1.HoverService);
62
+ });
63
+ afterEach(() => {
64
+ hoverService.cancelHover();
65
+ });
66
+ function waitForHover() {
67
+ // hover delay (0ms timeout) + animation frame (0ms timeout stub)
68
+ return new Promise(resolve => setTimeout(resolve, 20));
69
+ }
70
+ function waitForMouseOutDismissal() {
71
+ // the mouse-out handler re-checks the hover state after quickMouseThresholdMillis (200ms)
72
+ return new Promise(resolve => setTimeout(resolve, 250));
73
+ }
74
+ /**
75
+ * Creates a document simulating one hosted in a secondary window: unlike a document from
76
+ * `createHTMLDocument`, it has a `defaultView` window on which the hover service can listen
77
+ * for the window going away.
78
+ */
79
+ function createSecondaryWindowDocument(options) {
80
+ const secondaryDocument = document.implementation.createHTMLDocument('secondary window');
81
+ const listeners = new Map();
82
+ const fakeWindow = {
83
+ closed: options?.closed ?? false,
84
+ requestAnimationFrame: (cb) => setTimeout(cb, 0),
85
+ addEventListener: (type, listener) => {
86
+ const forType = listeners.get(type) ?? [];
87
+ forType.push(listener);
88
+ listeners.set(type, forType);
89
+ },
90
+ removeEventListener: (type, listener) => {
91
+ const forType = listeners.get(type);
92
+ const index = forType?.indexOf(listener) ?? -1;
93
+ if (forType && index > -1) {
94
+ forType.splice(index, 1);
95
+ }
96
+ }
97
+ };
98
+ Object.defineProperty(secondaryDocument, 'defaultView', { value: fakeWindow, configurable: true });
99
+ return {
100
+ secondaryDocument,
101
+ fireEvent: type => [...(listeners.get(type) ?? [])].forEach(listener => listener({ type }))
102
+ };
103
+ }
104
+ it('renders the hover in the document of the target element', async () => {
105
+ const target = document.createElement('div');
106
+ document.body.appendChild(target);
107
+ hoverService.requestHover({ content: 'main window hover', target, position: 'right', skipHoverDelay: true });
108
+ await waitForHover();
109
+ (0, chai_1.expect)(document.querySelector('.theia-hover'), 'hover should be in the main document').to.exist;
110
+ target.remove();
111
+ });
112
+ it('renders the hover in a secondary window document if the target lives there', async () => {
113
+ const { secondaryDocument } = createSecondaryWindowDocument();
114
+ const target = secondaryDocument.createElement('div');
115
+ secondaryDocument.body.appendChild(target);
116
+ hoverService.requestHover({ content: 'secondary window hover', target, position: 'right', skipHoverDelay: true });
117
+ await waitForHover();
118
+ (0, chai_1.expect)(document.querySelector('.theia-hover'), 'hover should not be in the main document').to.not.exist;
119
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be in the secondary document').to.exist;
120
+ target.remove();
121
+ });
122
+ it('creates the hover host in the document of the target instead of adopting it across documents', async () => {
123
+ const mainTarget = document.createElement('div');
124
+ document.body.appendChild(mainTarget);
125
+ hoverService.requestHover({ content: 'main', target: mainTarget, position: 'right', skipHoverDelay: true });
126
+ await waitForHover();
127
+ const mainHost = document.querySelector('.theia-hover');
128
+ (0, chai_1.expect)(mainHost, 'hover should be in the main document').to.exist;
129
+ const { secondaryDocument } = createSecondaryWindowDocument();
130
+ const secondaryTarget = secondaryDocument.createElement('div');
131
+ secondaryDocument.body.appendChild(secondaryTarget);
132
+ hoverService.requestHover({ content: 'secondary', target: secondaryTarget, position: 'right', skipHoverDelay: true });
133
+ await waitForHover();
134
+ const secondaryHost = secondaryDocument.querySelector('.theia-hover');
135
+ (0, chai_1.expect)(secondaryHost, 'hover should be in the secondary document').to.exist;
136
+ // moving a host into another document would make it outlive its window; a host must be
137
+ // created in the document it is shown in
138
+ (0, chai_1.expect)(secondaryHost, 'the secondary host must not be the adopted main host').to.not.equal(mainHost);
139
+ (0, chai_1.expect)(secondaryHost.ownerDocument).to.equal(secondaryDocument);
140
+ mainTarget.remove();
141
+ secondaryTarget.remove();
142
+ });
143
+ it('cancels the hover when the window hosting it is closed', async () => {
144
+ const { secondaryDocument, fireEvent } = createSecondaryWindowDocument();
145
+ const target = secondaryDocument.createElement('div');
146
+ secondaryDocument.body.appendChild(target);
147
+ hoverService.requestHover({ content: 'secondary window hover', target, position: 'right', skipHoverDelay: true });
148
+ await waitForHover();
149
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be in the secondary document').to.exist;
150
+ fireEvent('pagehide');
151
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be removed when its window closes').to.not.exist;
152
+ // hovers in the main window must keep working afterwards
153
+ const mainTarget = document.createElement('div');
154
+ document.body.appendChild(mainTarget);
155
+ hoverService.requestHover({ content: 'after window close', target: mainTarget, position: 'right', skipHoverDelay: true });
156
+ await waitForHover();
157
+ (0, chai_1.expect)(document.querySelector('.theia-hover'), 'hover should be rendered in the main document afterwards').to.exist;
158
+ target.remove();
159
+ mainTarget.remove();
160
+ });
161
+ it('dismisses the hover when the pointer leaves its target in a secondary window', async () => {
162
+ const { secondaryDocument } = createSecondaryWindowDocument();
163
+ const target = secondaryDocument.createElement('div');
164
+ secondaryDocument.body.appendChild(target);
165
+ hoverService.requestHover({ content: 'secondary window hover', target, position: 'right', skipHoverDelay: true });
166
+ await waitForHover();
167
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be shown in the secondary document').to.exist;
168
+ target.dispatchEvent(new window.Event('mouseout'));
169
+ await waitForMouseOutDismissal();
170
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be dismissed after the pointer left its target').to.not.exist;
171
+ target.remove();
172
+ });
173
+ it('dismisses a non-interactive hover on mousedown in a secondary window', async () => {
174
+ const { secondaryDocument } = createSecondaryWindowDocument();
175
+ const target = secondaryDocument.createElement('div');
176
+ secondaryDocument.body.appendChild(target);
177
+ hoverService.requestHover({ content: 'secondary window hover', target, position: 'right', skipHoverDelay: true });
178
+ await waitForHover();
179
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be shown in the secondary document').to.exist;
180
+ secondaryDocument.body.dispatchEvent(new window.Event('mousedown'));
181
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'hover should be dismissed on mousedown outside of it').to.not.exist;
182
+ target.remove();
183
+ });
184
+ it('shows at most one hover box in a secondary window across repeated hovers', async () => {
185
+ const { secondaryDocument } = createSecondaryWindowDocument();
186
+ const target = secondaryDocument.createElement('div');
187
+ secondaryDocument.body.appendChild(target);
188
+ for (let i = 0; i < 2; i++) {
189
+ hoverService.requestHover({ content: `hover ${i}`, target, position: 'right', skipHoverDelay: true });
190
+ await waitForHover();
191
+ target.dispatchEvent(new window.Event('mouseout'));
192
+ await waitForMouseOutDismissal();
193
+ }
194
+ hoverService.requestHover({ content: 'final hover', target, position: 'right', skipHoverDelay: true });
195
+ await waitForHover();
196
+ (0, chai_1.expect)(secondaryDocument.querySelectorAll('.theia-hover').length, 'stale hover hosts must not pile up').to.equal(1);
197
+ target.remove();
198
+ });
199
+ it('does not render a hover for a target in an already closed window', async () => {
200
+ const { secondaryDocument } = createSecondaryWindowDocument({ closed: true });
201
+ const target = secondaryDocument.createElement('div');
202
+ secondaryDocument.body.appendChild(target);
203
+ hoverService.requestHover({ content: 'closed window hover', target, position: 'right', skipHoverDelay: true });
204
+ await waitForHover();
205
+ (0, chai_1.expect)(secondaryDocument.querySelector('.theia-hover'), 'no hover should be rendered in a closed window').to.not.exist;
206
+ (0, chai_1.expect)(document.querySelector('.theia-hover'), 'no hover should be rendered in the main document either').to.not.exist;
207
+ target.remove();
208
+ });
209
+ it('keeps the hover host hidden until it has been positioned', async () => {
210
+ // the host is appended (and the popover shown) at (0, 0) first and only positioned after an
211
+ // animation frame; it must not be hittable in the meantime: a visible popover at (0, 0) can
212
+ // cover the target, kick it out of the hover chain and retrigger mouseenter hovers in an
213
+ // endless show/hide loop (e.g. for tabs at the top-left corner of a secondary window)
214
+ const target = document.createElement('div');
215
+ document.body.appendChild(target);
216
+ const rendering = hoverService.renderHover({ content: 'positioning', target, position: 'right' });
217
+ const host = document.querySelector('.theia-hover');
218
+ (0, chai_1.expect)(host, 'hover should be appended synchronously').to.exist;
219
+ (0, chai_1.expect)(host.style.visibility, 'hover must not be visible before it has been positioned').to.equal('hidden');
220
+ await rendering;
221
+ (0, chai_1.expect)(host.style.visibility, 'hover should be revealed once positioned').to.not.equal('hidden');
222
+ target.remove();
223
+ });
224
+ it('does not reveal a hover that was superseded while waiting to be positioned', async () => {
225
+ const target = document.createElement('div');
226
+ document.body.appendChild(target);
227
+ const service = hoverService;
228
+ const first = service.renderHover({ content: 'first', target, position: 'right' });
229
+ const second = service.renderHover({ content: 'second', target, position: 'right' });
230
+ await first;
231
+ const host = document.querySelector('.theia-hover');
232
+ (0, chai_1.expect)(host.style.visibility, 'the superseded render must not reveal the host').to.equal('hidden');
233
+ await second;
234
+ (0, chai_1.expect)(host.style.visibility, 'the latest render reveals the host').to.not.equal('hidden');
235
+ target.remove();
236
+ });
237
+ it('does not leak css classes from a hover that was superseded while waiting to be positioned', async () => {
238
+ const service = hoverService;
239
+ // keep the first render stuck waiting for its animation frame so that a second hover supersedes it mid-render
240
+ const originalAnimationFrame = service.hostAnimationFrame.bind(service);
241
+ let releaseFirst;
242
+ let animationFrameCalls = 0;
243
+ service.hostAnimationFrame = (element) => ++animationFrameCalls === 1
244
+ ? new Promise(resolve => { releaseFirst = resolve; })
245
+ : originalAnimationFrame(element);
246
+ const target = document.createElement('div');
247
+ document.body.appendChild(target);
248
+ hoverService.requestHover({ content: 'first', target, position: 'right', skipHoverDelay: true, cssClasses: ['first-hover-class'] });
249
+ await waitForHover();
250
+ hoverService.requestHover({ content: 'second', target, position: 'right', skipHoverDelay: true });
251
+ await waitForHover();
252
+ releaseFirst(); // let the superseded render finish
253
+ await waitForHover();
254
+ const host = document.querySelector('.theia-hover');
255
+ (0, chai_1.expect)(host, 'second hover should be rendered').to.exist;
256
+ (0, chai_1.expect)(host.classList.contains('first-hover-class'), 'the superseded hover must not leak its css classes').to.equal(false);
257
+ target.remove();
258
+ });
259
+ it('recovers if the open hover can no longer be hidden', async () => {
260
+ // simulate a hover whose document is no longer fully active, e.g. because the secondary
261
+ // window hosting it was closed: hidePopover throws and must not break subsequent hovers
262
+ const target = document.createElement('div');
263
+ document.body.appendChild(target);
264
+ hoverService.requestHover({ content: 'first', target, position: 'right', skipHoverDelay: true });
265
+ await waitForHover();
266
+ const host = document.querySelector('.theia-hover');
267
+ (0, chai_1.expect)(host, 'first hover should be rendered').to.exist;
268
+ host.hidePopover = () => { throw new Error('InvalidStateError: not fully active'); };
269
+ const secondTarget = document.createElement('div');
270
+ document.body.appendChild(secondTarget);
271
+ hoverService.requestHover({ content: 'second', target: secondTarget, position: 'right', skipHoverDelay: true });
272
+ await waitForHover();
273
+ const secondHost = document.querySelector('.theia-hover');
274
+ (0, chai_1.expect)(secondHost, 'hover should be rendered again in the main document').to.exist;
275
+ (0, chai_1.expect)(secondHost.textContent).to.equal('second');
276
+ target.remove();
277
+ secondTarget.remove();
278
+ });
279
+ describe('position fallback', () => {
280
+ // simulated window: 400px wide, 600px high
281
+ const windowWidth = 400;
282
+ const windowHeight = 600;
283
+ let target;
284
+ let originalBodyRect;
285
+ function rect(left, top, width, height) {
286
+ return { left, top, width, height, right: left + width, bottom: top + height, x: left, y: top, toJSON: () => '' };
287
+ }
288
+ beforeEach(() => {
289
+ target = document.createElement('div');
290
+ document.body.appendChild(target);
291
+ const host = hoverService.hoverHost;
292
+ host.getBoundingClientRect = () => rect(0, 0, 300, 50);
293
+ originalBodyRect = document.body.getBoundingClientRect.bind(document.body);
294
+ document.body.getBoundingClientRect = () => rect(0, 0, windowWidth, windowHeight);
295
+ Object.defineProperty(document.documentElement, 'scrollHeight', { value: windowHeight, configurable: true });
296
+ });
297
+ afterEach(() => {
298
+ document.body.getBoundingClientRect = originalBodyRect;
299
+ delete document.documentElement.scrollHeight;
300
+ target.remove();
301
+ });
302
+ function setHostPosition(position) {
303
+ const service = hoverService;
304
+ return service.setHostPosition(target, service.hoverHost, position);
305
+ }
306
+ it('keeps the requested position when the hover fits', () => {
307
+ target.getBoundingClientRect = () => rect(320, 100, 60, 20); // plenty of room on the left
308
+ (0, chai_1.expect)(setHostPosition('left')).to.equal('left');
309
+ });
310
+ it('falls back to bottom when a left hover fits on neither side of a full-width target', () => {
311
+ target.getBoundingClientRect = () => rect(0, 100, windowWidth, 20);
312
+ (0, chai_1.expect)(setHostPosition('left')).to.equal('bottom');
313
+ });
314
+ it('falls back to top when the full-width target is near the bottom of the window', () => {
315
+ target.getBoundingClientRect = () => rect(0, windowHeight - 30, windowWidth, 20);
316
+ (0, chai_1.expect)(setHostPosition('right')).to.equal('top');
317
+ });
318
+ it('keeps the requested direction when the perpendicular direction does not fit either', () => {
319
+ const host = hoverService.hoverHost;
320
+ host.getBoundingClientRect = () => rect(0, 0, 300, windowHeight); // hover as tall as the window
321
+ target.getBoundingClientRect = () => rect(0, 100, windowWidth, 20);
322
+ (0, chai_1.expect)(setHostPosition('left')).to.equal('right');
323
+ });
324
+ });
325
+ });
326
+ //# sourceMappingURL=hover-service.spec.js.map