Bug 1379208 - Position the tooltips using only one layout flush and no modifications to the surrounding DOM of the tooltip nodes. r?mconley,rickychien
MozReview-Commit-ID: JtFJA6dyNb
--- a/browser/components/preferences/in-content-new/findInPage.js
+++ b/browser/components/preferences/in-content-new/findInPage.js
@@ -20,29 +20,16 @@ var gSearchResultsPane = {
this.searchInput = document.getElementById("searchInput");
this.searchInput.hidden = !Services.prefs.getBoolPref("browser.preferences.search");
if (!this.searchInput.hidden) {
this.searchInput.addEventListener("command", this);
window.addEventListener("load", () => {
this.searchInput.focus();
this.initializeCategories();
});
-
- // Throttling the resize event to reduce the callback frequency
- let callbackId;
- window.addEventListener("resize", () => {
- if (!callbackId) {
- callbackId = window.requestAnimationFrame(() => {
- this.listSearchTooltips.forEach((anchorNode) => {
- this.calculateTooltipPosition(anchorNode);
- });
- callbackId = null;
- });
- }
- });
}
},
handleEvent(event) {
if (event.type === "command") {
this.searchFunction(event);
}
},
@@ -268,16 +255,27 @@ var gSearchResultsPane = {
let helpUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "preferences";
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
// eslint-disable-next-line no-unsanitized/property
document.getElementById("need-help").innerHTML =
strings.getFormattedString("searchResults.needHelp2", [helpUrl, brandName]);
} else {
// Creating tooltips for all the instances found
this.listSearchTooltips.forEach((anchorNode) => this.createSearchTooltip(anchorNode, this.query));
+
+ // Find width of search tooltips and adjust offset of arrow accordingly.
+ let oldStyle = document.querySelector("#search-tooltip-style");
+ if (oldStyle) {
+ oldStyle.remove();
+ }
+ // Add 20px to the width for the left and right padding.
+ let tooltipWidth = parseFloat(getComputedStyle(document.querySelector("[search-tooltip]"), ":before").width) + 20 + "px";
+ // This calc() centers the arrow on the tooltip (need to add 13px since the tooltip has a 20px offset and the arrow is 7px wide).
+ let style = document.createProcessingInstruction("xml-stylesheet", `href="data:text/css,[search-tooltip]::after { left: calc(${tooltipWidth} / 2 + 13px); }" id="search-tooltip-style" type="text/css"`);
+ document.insertBefore(style, document.firstChild);
}
} else {
this.searchResultsCategory.hidden = true;
document.getElementById("sorry-message").textContent = "";
// Going back to General when cleared
gotoPref("paneGeneral");
}
},
@@ -404,57 +402,27 @@ var gSearchResultsPane = {
* Then calculation the offsets to position the tooltip in the correct place.
*
* @param Node anchorNode
* DOM Element
* @param String query
* Word or words that are being searched for
*/
createSearchTooltip(anchorNode, query) {
- let searchTooltip = anchorNode.ownerDocument.createElement("span");
- searchTooltip.setAttribute("class", "search-tooltip");
- searchTooltip.textContent = query;
-
- // Set tooltipNode property to track corresponded tooltip node.
- anchorNode.tooltipNode = searchTooltip;
- anchorNode.parentElement.classList.add("search-tooltip-parent");
- anchorNode.parentElement.appendChild(searchTooltip);
-
- this.calculateTooltipPosition(anchorNode);
- },
-
- calculateTooltipPosition(anchorNode) {
- let searchTooltip = anchorNode.tooltipNode;
- // In order to get the up-to-date position of each of the nodes that we're
- // putting tooltips on, we have to flush layout intentionally, and that
- // this is the result of a XUL limitation (bug 1363730).
- let anchorRect = anchorNode.getBoundingClientRect();
- let tooltipRect = searchTooltip.getBoundingClientRect();
- let parentRect = anchorNode.parentElement.getBoundingClientRect();
-
- let offSetLeft = (anchorRect.width / 2) - (tooltipRect.width / 2);
- let relativeOffset = anchorRect.left - parentRect.left;
- offSetLeft += relativeOffset > 0 ? relativeOffset : 0;
- // 20.5 is reserved for tooltip position
- let offSetTop = anchorRect.top - parentRect.top - 20.5;
-
- searchTooltip.style.setProperty("left", `${offSetLeft}px`);
- searchTooltip.style.setProperty("top", `${offSetTop}px`);
+ anchorNode.setAttribute("search-tooltip", query);
},
/**
* Remove all search tooltips that were created.
*/
removeAllSearchTooltips() {
- let searchTooltips = Array.from(document.querySelectorAll(".search-tooltip"));
+ let searchTooltips = Array.from(document.querySelectorAll("[search-tooltip]"));
for (let searchTooltip of searchTooltips) {
- searchTooltip.parentElement.classList.remove("search-tooltip-parent");
- searchTooltip.remove();
+ searchTooltip.removeAttribute("search-tooltip");
}
- this.listSearchTooltips.forEach((anchorNode) => anchorNode.tooltipNode.remove());
this.listSearchTooltips.clear();
},
/**
* Remove all indicators on menuitem.
*/
removeAllSearchMenuitemIndicators() {
this.listSearchMenuitemIndicators.forEach((node) => node.removeAttribute("indicator"));
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -614,50 +614,53 @@ groupbox {
}
.help-button:link,
.help-button:visited {
color: var(--in-content-category-text);
text-decoration: none;
}
-.search-tooltip {
+[search-tooltip] {
+ /* Setting a transform creates a stacking context and containing
+ block for fixed position descendants. */
+ transform: translateZ(0);
+}
+
+[search-tooltip]::before {
+ content: attr(search-tooltip);
font-size: 1.25rem;
- position: absolute;
+ position: fixed;
padding: 0 10px;
background-color: #ffe900;
- border: 1px solid #d7b600;
-moz-user-select: none;
+ display: block;
+ /* Showing the tooltip above (in the Y context) the node is
+ causing it to get clipped. The tooltip doesn't clip below
+ the element, so this patch positions them below the anchor. */
+ top: -45px;
+ left: 20px;
}
-.search-tooltip:hover,
-.search-tooltip:hover::before {
+[search-tooltip]:hover::before,
+[search-tooltip]:hover::after {
opacity: .1;
}
-.search-tooltip::before {
- position: absolute;
+/* Note, since ::before is used for the tooltip text, we only
+ have one more pseudo-element that can be used for creating the
+ tooltip arrow, thus we cannot show a border on the tooltip. */
+[search-tooltip]::after {
+ position: fixed;
content: "";
border: 7px solid transparent;
- border-top-color: #d7b600;
- top: 100%;
- offset-inline-start: calc(50% - 7px);
-}
-
-.search-tooltip::after {
- position: absolute;
- content: "";
- border: 6px solid transparent;
- border-top-color: #ffe900;
- top: 100%;
- offset-inline-start: calc(50% - 6px);
-}
-
-.search-tooltip-parent {
- position: relative;
+ border-bottom-color: #ffe900;
+ /* The offset needs to be one pixel less than the tooltip text
+ to properly overlap the text and prevent a 1 pixel gap. */
+ top: calc(-44px - 1em);
}
menulist[indicator=true] > menupopup menuitem:not([image]) > .menu-iconic-left {
display: -moz-box;
width: 8px;
min-width: auto; /* Override the min-width defined in menu.css */
height: 10px;
margin-inline-end: 6px;