1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | var HoverService_1;
|
18 | Object.defineProperty(exports, "__esModule", { value: true });
|
19 | exports.HoverService = exports.HoverPosition = void 0;
|
20 | const tslib_1 = require("tslib");
|
21 | const inversify_1 = require("inversify");
|
22 | const common_1 = require("../common");
|
23 | const browser_1 = require("./browser");
|
24 | const markdown_renderer_1 = require("./markdown-rendering/markdown-renderer");
|
25 | const preferences_1 = require("./preferences");
|
26 | require("../../src/browser/style/hover-service.css");
|
27 | var HoverPosition;
|
28 | (function (HoverPosition) {
|
29 | function invertIfNecessary(position, target, host, totalWidth, totalHeight) {
|
30 | if (position === 'left') {
|
31 | if (target.left - host.width - 5 < 0) {
|
32 | return 'right';
|
33 | }
|
34 | }
|
35 | else if (position === 'right') {
|
36 | if (target.right + host.width + 5 > totalWidth) {
|
37 | return 'left';
|
38 | }
|
39 | }
|
40 | else if (position === 'top') {
|
41 | if (target.top - host.height - 5 < 0) {
|
42 | return 'bottom';
|
43 | }
|
44 | }
|
45 | else if (position === 'bottom') {
|
46 | if (target.bottom + host.height + 5 > totalHeight) {
|
47 | return 'top';
|
48 | }
|
49 | }
|
50 | return position;
|
51 | }
|
52 | HoverPosition.invertIfNecessary = invertIfNecessary;
|
53 | })(HoverPosition = exports.HoverPosition || (exports.HoverPosition = {}));
|
54 | let HoverService = HoverService_1 = class HoverService {
|
55 | constructor() {
|
56 | this.lastHidHover = Date.now();
|
57 | this.disposeOnHide = new common_1.DisposableCollection();
|
58 | }
|
59 | get markdownRenderer() {
|
60 | this._markdownRenderer || (this._markdownRenderer = this.markdownRendererFactory());
|
61 | return this._markdownRenderer;
|
62 | }
|
63 | get hoverHost() {
|
64 | if (!this._hoverHost) {
|
65 | this._hoverHost = document.createElement('div');
|
66 | this._hoverHost.classList.add(HoverService_1.hostClassName);
|
67 | this._hoverHost.style.position = 'absolute';
|
68 | }
|
69 | return this._hoverHost;
|
70 | }
|
71 | requestHover(request) {
|
72 | if (request.target !== this.hoverTarget) {
|
73 | this.cancelHover();
|
74 | this.pendingTimeout = (0, common_1.disposableTimeout)(() => this.renderHover(request), this.getHoverDelay());
|
75 | }
|
76 | }
|
77 | getHoverDelay() {
|
78 | return Date.now() - this.lastHidHover < 200
|
79 | ? 0
|
80 | : this.preferences.get('workbench.hover.delay', common_1.isOSX ? 1500 : 500);
|
81 | }
|
82 | async renderHover(request) {
|
83 | const host = this.hoverHost;
|
84 | let firstChild;
|
85 | const { target, content, position, cssClasses } = request;
|
86 | if (cssClasses) {
|
87 | host.classList.add(...cssClasses);
|
88 | }
|
89 | this.hoverTarget = target;
|
90 | if (content instanceof HTMLElement) {
|
91 | host.appendChild(content);
|
92 | firstChild = content;
|
93 | }
|
94 | else if (typeof content === 'string') {
|
95 | host.textContent = content;
|
96 | }
|
97 | else {
|
98 | const renderedContent = this.markdownRenderer.render(content);
|
99 | this.disposeOnHide.push(renderedContent);
|
100 | host.appendChild(renderedContent.element);
|
101 | firstChild = renderedContent.element;
|
102 | }
|
103 |
|
104 |
|
105 | host.style.left = '0px';
|
106 | host.style.top = '0px';
|
107 | document.body.append(host);
|
108 | if (request.visualPreview) {
|
109 |
|
110 | const width = firstChild ? firstChild.offsetWidth : this.hoverHost.offsetWidth;
|
111 | const visualPreview = request.visualPreview(width);
|
112 | if (visualPreview) {
|
113 | host.appendChild(visualPreview);
|
114 | }
|
115 | }
|
116 | await (0, browser_1.animationFrame)();
|
117 | const updatedPosition = this.setHostPosition(target, host, position);
|
118 | this.disposeOnHide.push({
|
119 | dispose: () => {
|
120 | this.lastHidHover = Date.now();
|
121 | host.classList.remove(updatedPosition);
|
122 | if (cssClasses) {
|
123 | host.classList.remove(...cssClasses);
|
124 | }
|
125 | }
|
126 | });
|
127 | this.listenForMouseOut();
|
128 | }
|
129 | setHostPosition(target, host, position) {
|
130 | const targetDimensions = target.getBoundingClientRect();
|
131 | const hostDimensions = host.getBoundingClientRect();
|
132 | const documentWidth = document.body.getBoundingClientRect().width;
|
133 |
|
134 |
|
135 | const documentHeight = document.documentElement.scrollHeight;
|
136 | position = HoverPosition.invertIfNecessary(position, targetDimensions, hostDimensions, documentWidth, documentHeight);
|
137 | if (position === 'top' || position === 'bottom') {
|
138 | const targetMiddleWidth = targetDimensions.left + (targetDimensions.width / 2);
|
139 | const middleAlignment = targetMiddleWidth - (hostDimensions.width / 2);
|
140 | const furthestRight = Math.min(documentWidth - hostDimensions.width, middleAlignment);
|
141 | const left = Math.max(0, furthestRight);
|
142 | const top = position === 'top'
|
143 | ? targetDimensions.top - hostDimensions.height - 5
|
144 | : targetDimensions.bottom + 5;
|
145 | host.style.setProperty('--theia-hover-before-position', `${targetMiddleWidth - left - 5}px`);
|
146 | host.style.top = `${top}px`;
|
147 | host.style.left = `${left}px`;
|
148 | }
|
149 | else {
|
150 | const targetMiddleHeight = targetDimensions.top + (targetDimensions.height / 2);
|
151 | const middleAlignment = targetMiddleHeight - (hostDimensions.height / 2);
|
152 | const furthestTop = Math.min(documentHeight - hostDimensions.height, middleAlignment);
|
153 | const top = Math.max(0, furthestTop);
|
154 | const left = position === 'left'
|
155 | ? targetDimensions.left - hostDimensions.width - 5
|
156 | : targetDimensions.right + 5;
|
157 | host.style.setProperty('--theia-hover-before-position', `${targetMiddleHeight - top - 5}px`);
|
158 | host.style.left = `${left}px`;
|
159 | host.style.top = `${top}px`;
|
160 | }
|
161 | host.classList.add(position);
|
162 | return position;
|
163 | }
|
164 | listenForMouseOut() {
|
165 | const handleMouseMove = (e) => {
|
166 | var _a;
|
167 | if (e.target instanceof Node && !this.hoverHost.contains(e.target) && !((_a = this.hoverTarget) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
|
168 | this.cancelHover();
|
169 | }
|
170 | };
|
171 | document.addEventListener('mousemove', handleMouseMove);
|
172 | this.disposeOnHide.push({ dispose: () => document.removeEventListener('mousemove', handleMouseMove) });
|
173 | }
|
174 | cancelHover() {
|
175 | var _a;
|
176 | (_a = this.pendingTimeout) === null || _a === void 0 ? void 0 : _a.dispose();
|
177 | this.unRenderHover();
|
178 | this.disposeOnHide.dispose();
|
179 | this.hoverTarget = undefined;
|
180 | }
|
181 | unRenderHover() {
|
182 | this.hoverHost.remove();
|
183 | this.hoverHost.replaceChildren();
|
184 | }
|
185 | };
|
186 | HoverService.hostClassName = 'theia-hover';
|
187 | HoverService.styleSheetId = 'theia-hover-style';
|
188 | (0, tslib_1.__decorate)([
|
189 | (0, inversify_1.inject)(preferences_1.PreferenceService),
|
190 | (0, tslib_1.__metadata)("design:type", Object)
|
191 | ], HoverService.prototype, "preferences", void 0);
|
192 | (0, tslib_1.__decorate)([
|
193 | (0, inversify_1.inject)(markdown_renderer_1.MarkdownRendererFactory),
|
194 | (0, tslib_1.__metadata)("design:type", Function)
|
195 | ], HoverService.prototype, "markdownRendererFactory", void 0);
|
196 | HoverService = HoverService_1 = (0, tslib_1.__decorate)([
|
197 | (0, inversify_1.injectable)()
|
198 | ], HoverService);
|
199 | exports.HoverService = HoverService;
|
200 |
|
\ | No newline at end of file |