diff --git a/chrome/content/zotero/components/button.jsx b/chrome/content/zotero/components/button.jsx index e9f4485c5e..41ea8a65b3 100644 --- a/chrome/content/zotero/components/button.jsx +++ b/chrome/content/zotero/components/button.jsx @@ -99,8 +99,23 @@ class Button extends PureComponent { } if (!this.props.isDisabled) { - attr.onMouseDown = this.handleMouseDown + attr.onMouseDown = (event) => { + // Hide tooltip on mousedown + if (this.title) { + window.Zotero_Tooltip.stop(); + } + return this.handleMouseDown(event); + }; attr.onClick = this.handleClick + // Fake tooltip behavior as long as 'title' doesn't work for HTML-in-XUL elements + if (this.title) { + attr.onMouseOver = () => { + window.Zotero_Tooltip.start(this.title); + }; + attr.onMouseOut = () => { + window.Zotero_Tooltip.stop(); + }; + } } return attr diff --git a/chrome/content/zotero/tooltip.js b/chrome/content/zotero/tooltip.js new file mode 100644 index 0000000000..9ad98c94ba --- /dev/null +++ b/chrome/content/zotero/tooltip.js @@ -0,0 +1,78 @@ +/* + ***** BEGIN LICENSE BLOCK ***** + + Copyright © 2020 Corporation for Digital Scholarship + Vienna, Virginia, USA + https://www.zotero.org + + This file is part of Zotero. + + Zotero is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Zotero is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with Zotero. If not, see . + + ***** END LICENSE BLOCK ***** +*/ + +/** + * Fake tooltip implementation for HTML-in-XUL elements where neither 'title' nor 'tooltiptext' works + */ +// eslint-disable-next-line camelcase,no-unused-vars +var Zotero_Tooltip = new function () { + // On macOS, the tooltip appears even if the mouse keeps moving over the element, but Mozilla + // shows it only once the mouse stops, so follow that as long as there are XUL elements. + const MOUSE_STOP_DELAY = 500; + + var text; + var timeoutID; + var x; + var y; + + /** + * Start tracking the mouse and show a tooltip after it stops + */ + this.start = function (tooltipText) { + window.addEventListener('mousemove', handleMouseMove); + text = tooltipText; + }; + + /** + * Stop tracking the mouse and hide the tooltip if it's showing + */ + this.stop = function () { + window.removeEventListener('mousemove', handleMouseMove); + clearTimeout(timeoutID); + // Mozilla hides the tooltip as soon as the mouse leaves the element, which is also different + // from macOS behavior + hidePopup(); + }; + + function handleMouseMove(event) { + if (timeoutID) { + clearTimeout(timeoutID); + } + x = event.screenX; + y = event.screenY; + timeoutID = setTimeout(handleMouseStop, MOUSE_STOP_DELAY); + } + + function handleMouseStop() { + var tooltipElem = document.getElementById('fake-tooltip'); + tooltipElem.setAttribute('label', text); + tooltipElem.openPopupAtScreen(x, y, false, null); + } + + function hidePopup() { + var tooltipElem = document.getElementById('fake-tooltip'); + tooltipElem.hidePopup(); + } +}; diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul index 661dc59396..4d20c0ad9a 100644 --- a/chrome/content/zotero/zoteroPane.xul +++ b/chrome/content/zotero/zoteroPane.xul @@ -49,6 +49,7 @@