Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/ui/Popover.js

Issue 2712063002: [DevTools] Migrate Popover to GlassPane (Closed)
Patch Set: nit Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved. 2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 10 matching lines...) Expand all
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 /** 31 UI.Popover = class extends UI.GlassPane {
32 * @unrestricted
33 */
34 UI.Popover = class extends UI.Widget {
35 /** 32 /**
36 * @param {!UI.PopoverHelper=} popoverHelper 33 * @param {!UI.PopoverHelper=} popoverHelper
37 */ 34 */
38 constructor(popoverHelper) { 35 constructor(popoverHelper) {
39 super(true); 36 super();
40 this.markAsRoot();
41 this.registerRequiredCSS('ui/popover.css'); 37 this.registerRequiredCSS('ui/popover.css');
42 this._containerElement = createElementWithClass('div', 'fill popover-contain er'); 38 this.setBlockPointerEvents(false);
43 this._popupArrowElement = this.contentElement.createChild('div', 'arrow'); 39 this.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
44 this._contentDiv = this.contentElement.createChild('div', 'popover-content') ; 40 this.setShowArrow(true);
45 this._popoverHelper = popoverHelper; 41 this._popoverHelper = popoverHelper;
46 this._hideBound = this.hide.bind(this);
47 } 42 }
48 43
49 /** 44 /**
50 * @param {!Element} element 45 * @param {!Element} element
51 * @param {!Element|!AnchorBox} anchor 46 * @param {!Element|!AnchorBox} anchor
52 * @param {?number=} preferredWidth
53 * @param {?number=} preferredHeight
54 */ 47 */
55 showForAnchor(element, anchor, preferredWidth, preferredHeight) { 48 showForAnchor(element, anchor) {
56 this._innerShow(null, element, anchor, preferredWidth, preferredHeight); 49 this._innerShow(null, element, anchor);
57 } 50 }
58 51
59 /** 52 /**
60 * @param {!UI.Widget} view 53 * @param {!UI.Widget} view
61 * @param {!Element|!AnchorBox} anchor 54 * @param {!Element|!AnchorBox} anchor
62 */ 55 */
63 showView(view, anchor) { 56 showView(view, anchor) {
64 this._innerShow(view, view.element, anchor); 57 this._innerShow(view, view.element, anchor);
65 } 58 }
66 59
67 /** 60 /**
68 * @param {?UI.Widget} view 61 * @param {?UI.Widget} widget
69 * @param {!Element} contentElement 62 * @param {!Element} contentElement
70 * @param {!Element|!AnchorBox} anchor 63 * @param {!Element|!AnchorBox} anchor
71 * @param {?number=} preferredWidth
72 * @param {?number=} preferredHeight
73 */ 64 */
74 _innerShow(view, contentElement, anchor, preferredWidth, preferredHeight) { 65 _innerShow(widget, contentElement, anchor) {
75 this._contentElement = contentElement;
76
77 // This should not happen, but we hide previous popup to be on the safe side . 66 // This should not happen, but we hide previous popup to be on the safe side .
78 if (UI.Popover._popover) 67 if (UI.Popover._popover)
79 UI.Popover._popover.hide(); 68 UI.Popover._popover.hide();
80 UI.Popover._popover = this; 69 UI.Popover._popover = this;
81 70
82 var document = anchor instanceof Element ? anchor.ownerDocument : contentEle ment.ownerDocument; 71 var document =
83 var window = document.defaultView; 72 /** @type {!Document} */ (anchor instanceof Element ? anchor.ownerDocume nt : contentElement.ownerDocument);
73 var anchorBox = anchor instanceof AnchorBox ? anchor : anchor.boxInWindow();
74 this.setContentAnchorBox(anchorBox);
84 75
85 // Temporarily attach in order to measure preferred dimensions. 76 if (widget)
86 var preferredSize = view ? view.measurePreferredSize() : UI.measurePreferred Size(this._contentElement); 77 widget.show(this.contentElement);
87 this._preferredWidth = preferredWidth || preferredSize.width; 78 else
88 this._preferredHeight = preferredHeight || preferredSize.height; 79 this.contentElement.appendChild(contentElement);
89 80
90 window.addEventListener('resize', this._hideBound, false); 81 super.show(document);
91 document.body.appendChild(this._containerElement);
92 super.show(this._containerElement);
93
94 if (view)
95 view.show(this._contentDiv);
96 else
97 this._contentDiv.appendChild(this._contentElement);
98
99 this.positionElement(anchor, this._preferredWidth, this._preferredHeight);
100 82
101 if (this._popoverHelper) { 83 if (this._popoverHelper) {
102 this._contentDiv.addEventListener( 84 this.contentElement.addEventListener(
103 'mousemove', this._popoverHelper._killHidePopoverTimer.bind(this._popo verHelper), true); 85 'mousemove', this._popoverHelper._killHidePopoverTimer.bind(this._popo verHelper), true);
104 this.element.addEventListener('mouseout', this._popoverHelper._popoverMous eOut.bind(this._popoverHelper), true); 86 this.contentElement.addEventListener(
87 'mouseout', this._popoverHelper._popoverMouseOut.bind(this._popoverHel per), true);
105 } 88 }
106 } 89 }
107 90
91 /**
92 * @override
93 */
108 hide() { 94 hide() {
109 this._containerElement.ownerDocument.defaultView.removeEventListener('resize ', this._hideBound, false); 95 super.hide();
110 this.detach();
111 this._containerElement.remove();
112 delete UI.Popover._popover; 96 delete UI.Popover._popover;
113 } 97 }
114 98
115 /** 99 /**
116 * @param {boolean} canShrink
117 */
118 setCanShrink(canShrink) {
119 this._hasFixedHeight = !canShrink;
120 }
121
122 /**
123 * @param {boolean} noPadding 100 * @param {boolean} noPadding
124 */ 101 */
125 setNoPadding(noPadding) { 102 setNoPadding(noPadding) {
126 this._hasNoPadding = noPadding; 103 // TODO(dgozman): remove this. Clients should add padding themselves.
127 this._contentDiv.classList.toggle('no-padding', this._hasNoPadding); 104 this.contentElement.classList.toggle('no-padding', noPadding);
128 }
129
130 /**
131 * @param {!Element|!AnchorBox} anchorElement
132 * @param {number=} preferredWidth
133 * @param {number=} preferredHeight
134 */
135 positionElement(anchorElement, preferredWidth, preferredHeight) {
136 const borderWidth = this._hasNoPadding ? 0 : 8;
137 const scrollerWidth = this._hasFixedHeight ? 0 : 14;
138 const arrowHeight = this._hasNoPadding ? 8 : 15;
139 const arrowOffset = 10;
140 const borderRadius = 4;
141 const arrowRadius = 6;
142 preferredWidth = preferredWidth || this._preferredWidth;
143 preferredHeight = preferredHeight || this._preferredHeight;
144
145 // Skinny tooltips are not pretty, their arrow location is not nice.
146 preferredWidth = Math.max(preferredWidth, 50);
147 // Position relative to main DevTools element.
148 const container = UI.GlassPane.container(/** @type {!Document} */ (this._con tainerElement.ownerDocument));
149 const totalWidth = container.offsetWidth;
150 const totalHeight = container.offsetHeight;
151
152 var anchorBox = anchorElement instanceof AnchorBox ? anchorElement : anchorE lement.boxInWindow(window);
153 anchorBox = anchorBox.relativeToElement(container);
154 var newElementPosition = {x: 0, y: 0, width: preferredWidth + scrollerWidth, height: preferredHeight};
155
156 var arrowAtBottom;
157 var roomAbove = anchorBox.y;
158 var roomBelow = totalHeight - anchorBox.y - anchorBox.height;
159 this._popupArrowElement.hidden = false;
160
161 if (roomAbove > roomBelow) {
162 // Positioning above the anchor.
163 if (anchorBox.y > newElementPosition.height + arrowHeight + borderRadius) {
164 newElementPosition.y = anchorBox.y - newElementPosition.height - arrowHe ight;
165 } else {
166 this._popupArrowElement.hidden = true;
167 newElementPosition.y = borderRadius;
168 newElementPosition.height = anchorBox.y - borderRadius * 2 - arrowHeight ;
169 if (this._hasFixedHeight && newElementPosition.height < preferredHeight) {
170 newElementPosition.y = borderRadius;
171 newElementPosition.height = preferredHeight;
172 }
173 }
174 arrowAtBottom = true;
175 } else {
176 // Positioning below the anchor.
177 newElementPosition.y = anchorBox.y + anchorBox.height + arrowHeight;
178 if (newElementPosition.y + newElementPosition.height + borderRadius >= tot alHeight) {
179 this._popupArrowElement.hidden = true;
180 newElementPosition.height = totalHeight - borderRadius - newElementPosit ion.y;
181 if (this._hasFixedHeight && newElementPosition.height < preferredHeight) {
182 newElementPosition.y = totalHeight - preferredHeight - borderRadius;
183 newElementPosition.height = preferredHeight;
184 }
185 }
186 // Align arrow.
187 arrowAtBottom = false;
188 }
189
190 var arrowAtLeft;
191 this._popupArrowElement.removeAttribute('style');
192 if (anchorBox.x + newElementPosition.width < totalWidth) {
193 newElementPosition.x = Math.max(borderRadius, anchorBox.x - borderRadius - arrowOffset);
194 arrowAtLeft = true;
195 this._popupArrowElement.style.left = arrowOffset + 'px';
196 } else if (newElementPosition.width + borderRadius * 2 < totalWidth) {
197 newElementPosition.x = totalWidth - newElementPosition.width - borderRadiu s - 2 * borderWidth;
198 arrowAtLeft = false;
199 // Position arrow accurately.
200 var arrowRightPosition = Math.max(0, totalWidth - anchorBox.x - anchorBox. width - borderRadius - arrowOffset);
201 arrowRightPosition += anchorBox.width / 2;
202 arrowRightPosition = Math.min(arrowRightPosition, newElementPosition.width - borderRadius - arrowOffset);
203 this._popupArrowElement.style.right = arrowRightPosition + 'px';
204 } else {
205 newElementPosition.x = borderRadius;
206 newElementPosition.width = totalWidth - borderRadius * 2;
207 newElementPosition.height += scrollerWidth;
208 arrowAtLeft = true;
209 if (arrowAtBottom)
210 newElementPosition.y -= scrollerWidth;
211 // Position arrow accurately.
212 this._popupArrowElement.style.left =
213 Math.max(0, anchorBox.x - newElementPosition.x - borderRadius - arrowR adius + anchorBox.width / 2) + 'px';
214 }
215
216 this._popupArrowElement.className =
217 `arrow ${(arrowAtBottom ? 'bottom' : 'top')}-${(arrowAtLeft ? 'left' : ' right')}-arrow`;
218 this.element.positionAt(newElementPosition.x, newElementPosition.y - borderW idth, container);
219 this.element.style.width = newElementPosition.width + borderWidth * 2 + 'px' ;
220 this.element.style.height = newElementPosition.height + borderWidth * 2 + 'p x';
221 } 105 }
222 }; 106 };
223 107
224 /** 108 /**
225 * @unrestricted 109 * @unrestricted
226 */ 110 */
227 UI.PopoverHelper = class { 111 UI.PopoverHelper = class {
228 /** 112 /**
229 * @param {!Element} panelElement 113 * @param {!Element} panelElement
230 * @param {boolean=} disableOnClick 114 * @param {boolean=} disableOnClick
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 if (this._eventInHoverElement(event)) 171 if (this._eventInHoverElement(event))
288 return; 172 return;
289 173
290 this._startHidePopoverTimer(); 174 this._startHidePopoverTimer();
291 this._handleMouseAction(event, false); 175 this._handleMouseAction(event, false);
292 } 176 }
293 177
294 _popoverMouseOut(event) { 178 _popoverMouseOut(event) {
295 if (!this.isPopoverVisible()) 179 if (!this.isPopoverVisible())
296 return; 180 return;
297 if (event.relatedTarget && !event.relatedTarget.isSelfOrDescendant(this._pop over._contentDiv)) 181 if (event.relatedTarget && !event.relatedTarget.isSelfOrDescendant(this._pop over.contentElement))
298 this._startHidePopoverTimer(); 182 this._startHidePopoverTimer();
299 } 183 }
300 184
301 _mouseOut(event) { 185 _mouseOut(event) {
302 if (!this.isPopoverVisible()) 186 if (!this.isPopoverVisible())
303 return; 187 return;
304 if (!this._eventInHoverElement(event)) 188 if (!this._eventInHoverElement(event))
305 this._startHidePopoverTimer(); 189 this._startHidePopoverTimer();
306 } 190 }
307 191
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 if (this._hidePopoverTimer) { 259 if (this._hidePopoverTimer) {
376 clearTimeout(this._hidePopoverTimer); 260 clearTimeout(this._hidePopoverTimer);
377 delete this._hidePopoverTimer; 261 delete this._hidePopoverTimer;
378 262
379 // We know that we reached the popup, but we might have moved over other e lements. 263 // We know that we reached the popup, but we might have moved over other e lements.
380 // Discard pending command. 264 // Discard pending command.
381 this._resetHoverTimer(); 265 this._resetHoverTimer();
382 } 266 }
383 } 267 }
384 }; 268 };
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/ui/Icon.js ('k') | third_party/WebKit/Source/devtools/front_end/ui/Widget.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698