Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 UI.Popover = class extends UI.GlassPane { | |
| 32 /** | |
| 33 * @param {!UI.PopoverHelper=} popoverHelper | |
| 34 */ | |
| 35 constructor(popoverHelper) { | |
| 36 super(); | |
| 37 this.registerRequiredCSS('ui/popover.css'); | |
| 38 this.setBlockPointerEvents(false); | |
| 39 this.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent); | |
| 40 this.setShowArrow(true); | |
| 41 this._popoverHelper = popoverHelper; | |
| 42 } | |
| 43 | |
| 44 /** | |
| 45 * @param {!Element} element | |
| 46 * @param {!Element|!AnchorBox} anchor | |
| 47 */ | |
| 48 showForAnchor(element, anchor) { | |
| 49 this._innerShow(null, element, anchor); | |
| 50 } | |
| 51 | |
| 52 /** | |
| 53 * @param {!UI.Widget} view | |
| 54 * @param {!Element|!AnchorBox} anchor | |
| 55 */ | |
| 56 showView(view, anchor) { | |
| 57 this._innerShow(view, view.element, anchor); | |
| 58 } | |
| 59 | |
| 60 /** | |
| 61 * @param {?UI.Widget} widget | |
| 62 * @param {!Element} contentElement | |
| 63 * @param {!Element|!AnchorBox} anchor | |
| 64 */ | |
| 65 _innerShow(widget, contentElement, anchor) { | |
| 66 // This should not happen, but we hide previous popup to be on the safe side . | |
| 67 if (UI.Popover._popover) | |
| 68 UI.Popover._popover.hide(); | |
| 69 UI.Popover._popover = this; | |
| 70 | |
| 71 var document = | |
| 72 /** @type {!Document} */ (anchor instanceof Element ? anchor.ownerDocume nt : contentElement.ownerDocument); | |
| 73 var anchorBox = anchor instanceof AnchorBox ? anchor : anchor.boxInWindow(); | |
| 74 this.setContentAnchorBox(anchorBox); | |
| 75 | |
| 76 if (widget) | |
| 77 widget.show(this.contentElement); | |
| 78 else | |
| 79 this.contentElement.appendChild(contentElement); | |
| 80 | |
| 81 super.show(document); | |
| 82 | |
| 83 if (this._popoverHelper) { | |
| 84 this.contentElement.addEventListener( | |
| 85 'mousemove', this._popoverHelper._killHidePopoverTimer.bind(this._popo verHelper), true); | |
| 86 this.contentElement.addEventListener( | |
| 87 'mouseout', this._popoverHelper._popoverMouseOut.bind(this._popoverHel per), true); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 /** | |
| 92 * @override | |
| 93 */ | |
| 94 hide() { | |
| 95 super.hide(); | |
| 96 delete UI.Popover._popover; | |
| 97 } | |
| 98 | |
| 99 /** | |
| 100 * @param {boolean} noPadding | |
| 101 */ | |
| 102 setNoPadding(noPadding) { | |
| 103 // TODO(dgozman): remove this. Clients should add padding themselves. | |
| 104 this.contentElement.classList.toggle('no-padding', noPadding); | |
| 105 } | |
| 106 }; | |
| 107 | |
| 108 /** | 31 /** |
| 109 * @unrestricted | 32 * @unrestricted |
| 110 */ | 33 */ |
| 111 UI.PopoverHelper = class { | 34 UI.PopoverHelper = class { |
| 112 /** | 35 /** |
| 113 * @param {!Element} panelElement | 36 * @param {!Element} panelElement |
| 114 * @param {boolean=} disableOnClick | 37 * @param {boolean=} disableOnClick |
| 115 */ | 38 */ |
| 116 constructor(panelElement, disableOnClick) { | 39 constructor(panelElement, disableOnClick) { |
| 117 this._disableOnClick = !!disableOnClick; | 40 this._disableOnClick = !!disableOnClick; |
| 41 this._hasPadding = false; | |
| 118 panelElement.addEventListener('mousedown', this._mouseDown.bind(this), false ); | 42 panelElement.addEventListener('mousedown', this._mouseDown.bind(this), false ); |
| 119 panelElement.addEventListener('mousemove', this._mouseMove.bind(this), false ); | 43 panelElement.addEventListener('mousemove', this._mouseMove.bind(this), false ); |
| 120 panelElement.addEventListener('mouseout', this._mouseOut.bind(this), false); | 44 panelElement.addEventListener('mouseout', this._mouseOut.bind(this), false); |
| 121 this.setTimeout(1000, 500); | 45 this.setTimeout(1000, 500); |
| 122 } | 46 } |
| 123 | 47 |
| 124 /** | 48 /** |
| 125 * @param {function(!Element, !Event):(!Element|!AnchorBox|undefined)} getAnch or | 49 * @param {function(!Element, !Event):(!Element|!AnchorBox|undefined)} getAnch or |
| 126 * @param {function(!Element, !UI.Popover):undefined} showPopover | 50 * @param {function(!Element, !UI.GlassPane):!Promise<boolean>} showPopover |
| 127 * @param {function()=} onHide | 51 * @param {function()=} onHide |
| 128 */ | 52 */ |
| 129 initializeCallbacks(getAnchor, showPopover, onHide) { | 53 initializeCallbacks(getAnchor, showPopover, onHide) { |
| 130 this._getAnchor = getAnchor; | 54 this._getAnchor = getAnchor; |
| 131 this._showPopover = showPopover; | 55 this._showPopover = showPopover; |
| 132 this._onHide = onHide; | 56 this._onHide = onHide; |
| 133 } | 57 } |
| 134 | 58 |
| 135 /** | 59 /** |
| 136 * @param {number} timeout | 60 * @param {number} timeout |
| 137 * @param {number=} hideTimeout | 61 * @param {number=} hideTimeout |
| 138 */ | 62 */ |
| 139 setTimeout(timeout, hideTimeout) { | 63 setTimeout(timeout, hideTimeout) { |
| 140 this._timeout = timeout; | 64 this._timeout = timeout; |
| 141 if (typeof hideTimeout === 'number') | 65 if (typeof hideTimeout === 'number') |
| 142 this._hideTimeout = hideTimeout; | 66 this._hideTimeout = hideTimeout; |
| 143 else | 67 else |
| 144 this._hideTimeout = timeout / 2; | 68 this._hideTimeout = timeout / 2; |
| 145 } | 69 } |
| 146 | 70 |
| 147 /** | 71 /** |
| 72 * @param {boolean} hasPadding | |
| 73 */ | |
| 74 setHasPadding(hasPadding) { | |
| 75 this._hasPadding = hasPadding; | |
| 76 } | |
| 77 | |
| 78 /** | |
| 148 * @param {!MouseEvent} event | 79 * @param {!MouseEvent} event |
| 149 * @return {boolean} | 80 * @return {boolean} |
| 150 */ | 81 */ |
| 151 _eventInHoverElement(event) { | 82 _eventInHoverElement(event) { |
| 152 if (!this._hoverElement) | 83 if (!this._hoverElement) |
| 153 return false; | 84 return false; |
| 154 var box = this._hoverElement instanceof AnchorBox ? this._hoverElement : thi s._hoverElement.boxInWindow(); | 85 var box = this._hoverElement instanceof AnchorBox ? this._hoverElement : thi s._hoverElement.boxInWindow(); |
| 155 return ( | 86 return ( |
| 156 box.x <= event.clientX && event.clientX <= box.x + box.width && box.y <= event.clientY && | 87 box.x <= event.clientX && event.clientX <= box.x + box.width && box.y <= event.clientY && |
| 157 event.clientY <= box.y + box.height); | 88 event.clientY <= box.y + box.height); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 } | 136 } |
| 206 | 137 |
| 207 _handleMouseAction(event, isMouseDown) { | 138 _handleMouseAction(event, isMouseDown) { |
| 208 this._resetHoverTimer(); | 139 this._resetHoverTimer(); |
| 209 if (event.which && this._disableOnClick) | 140 if (event.which && this._disableOnClick) |
| 210 return; | 141 return; |
| 211 this._hoverElement = this._getAnchor(event.target, event); | 142 this._hoverElement = this._getAnchor(event.target, event); |
| 212 if (!this._hoverElement) | 143 if (!this._hoverElement) |
| 213 return; | 144 return; |
| 214 const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout); | 145 const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout); |
| 215 this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement ), toolTipDelay); | 146 this._hoverTimer = |
| 147 setTimeout(this._mouseHover.bind(this, this._hoverElement, event.target. ownerDocument), toolTipDelay); | |
| 216 } | 148 } |
| 217 | 149 |
| 218 _resetHoverTimer() { | 150 _resetHoverTimer() { |
| 219 if (this._hoverTimer) { | 151 if (this._hoverTimer) { |
| 220 clearTimeout(this._hoverTimer); | 152 clearTimeout(this._hoverTimer); |
| 221 delete this._hoverTimer; | 153 delete this._hoverTimer; |
| 222 } | 154 } |
| 223 } | 155 } |
| 224 | 156 |
| 225 /** | 157 /** |
| 226 * @return {boolean} | 158 * @return {boolean} |
| 227 */ | 159 */ |
| 228 isPopoverVisible() { | 160 isPopoverVisible() { |
| 229 return !!this._popover; | 161 return !!this._popover; |
| 230 } | 162 } |
| 231 | 163 |
| 232 hidePopover() { | 164 hidePopover() { |
| 233 this._resetHoverTimer(); | 165 this._resetHoverTimer(); |
| 234 this._hidePopover(); | 166 this._hidePopover(); |
| 235 } | 167 } |
| 236 | 168 |
| 237 _hidePopover() { | 169 _hidePopover() { |
| 238 if (!this._popover) | 170 if (!this._popover) |
| 239 return; | 171 return; |
| 240 | 172 |
| 173 delete UI.PopoverHelper._popover; | |
| 241 if (this._onHide) | 174 if (this._onHide) |
| 242 this._onHide(); | 175 this._onHide(); |
| 243 | 176 |
| 244 if (this._popover.isShowing()) | 177 if (this._popover.isShowing()) |
| 245 this._popover.hide(); | 178 this._popover.hide(); |
| 246 delete this._popover; | 179 delete this._popover; |
| 247 this._hoverElement = null; | 180 this._hoverElement = null; |
| 248 } | 181 } |
| 249 | 182 |
| 250 _mouseHover(element) { | 183 _mouseHover(element, document) { |
| 251 delete this._hoverTimer; | 184 delete this._hoverTimer; |
| 252 this._hoverElement = element; | 185 this._hoverElement = element; |
| 253 this._hidePopover(); | 186 this._hidePopover(); |
| 254 this._popover = new UI.Popover(this); | 187 |
| 255 this._showPopover(element, this._popover); | 188 this._popover = new UI.GlassPane(); |
| 189 this._popover.registerRequiredCSS('ui/popover.css'); | |
| 190 this._popover.setBlockPointerEvents(false); | |
| 191 this._popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent); | |
| 192 this._popover.setShowArrow(true); | |
| 193 this._popover.contentElement.classList.toggle('has-padding', this._hasPaddin g); | |
| 194 this._popover.contentElement.addEventListener('mousemove', this._killHidePop overTimer.bind(this), true); | |
| 195 this._popover.contentElement.addEventListener('mouseout', this._popoverMouse Out.bind(this), true); | |
| 196 this._popover.setContentAnchorBox( | |
| 197 this._hoverElement instanceof AnchorBox ? this._hoverElement : this._hov erElement.boxInWindow()); | |
| 198 | |
| 199 // This should not happen, but we hide previous popover to be on the safe si de. | |
| 200 if (UI.PopoverHelper._popover) | |
|
lushnikov
2017/03/10 22:07:14
let's console.error as well to track and investiga
dgozman
2017/03/11 00:00:44
Done.
| |
| 201 UI.PopoverHelper._popover.hide(); | |
| 202 UI.PopoverHelper._popover = this._popover; | |
| 203 var popover = this._popover; | |
| 204 this._showPopover(element, this._popover).then(success => { | |
| 205 if (success && this._popover === popover && this._hoverElement === element ) | |
| 206 popover.show(document); | |
| 207 }); | |
| 256 } | 208 } |
| 257 | 209 |
| 258 _killHidePopoverTimer() { | 210 _killHidePopoverTimer() { |
| 259 if (this._hidePopoverTimer) { | 211 if (this._hidePopoverTimer) { |
| 260 clearTimeout(this._hidePopoverTimer); | 212 clearTimeout(this._hidePopoverTimer); |
| 261 delete this._hidePopoverTimer; | 213 delete this._hidePopoverTimer; |
| 262 | 214 |
| 263 // We know that we reached the popup, but we might have moved over other e lements. | 215 // We know that we reached the popup, but we might have moved over other e lements. |
| 264 // Discard pending command. | 216 // Discard pending command. |
| 265 this._resetHoverTimer(); | 217 this._resetHoverTimer(); |
| 266 } | 218 } |
| 267 } | 219 } |
| 268 }; | 220 }; |
| OLD | NEW |