From d66c64b9d76553a9518ae6a3141714519d65d796 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 24 May 2023 20:19:16 +0300 Subject: [PATCH 1/3] Optimize tooltip checks * Instead of traversing tens of thousands of text nodes, only look at elements and their children * Debounce the checks to happen only every one second --- javascript/hints.js | 61 ++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index 46f342cb..a8c72976 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -116,17 +116,17 @@ var titles = { "Negative Guidance minimum sigma": "Skip negative prompt for steps where image is already mostly denoised; the higher this value, the more skips there will be; provides increased performance in exchange for minor quality reduction." }; -function updateTooltipForSpan(span) { - if (span.title) return; // already has a title +function updateTooltip(element) { + if (element.title) return; // already has a title - let tooltip = localization[titles[span.textContent]] || titles[span.textContent]; + let tooltip = localization[titles[element.textContent]] || titles[element.textContent]; if (!tooltip) { - tooltip = localization[titles[span.value]] || titles[span.value]; + tooltip = localization[titles[element.value]] || titles[element.value]; } if (!tooltip) { - for (const c of span.classList) { + for (const c of element.classList) { if (c in titles) { tooltip = localization[titles[c]] || titles[c]; break; @@ -135,34 +135,39 @@ function updateTooltipForSpan(span) { } if (tooltip) { - span.title = tooltip; + element.title = tooltip; } } -function updateTooltipForSelect(select) { - if (select.onchange != null) return; +// Nodes to check for adding tooltips. +const tooltipCheckNodes = new Set(); +// Timer for debouncing tooltip check. +let tooltipCheckTimer = null; - select.onchange = function() { - select.title = localization[titles[select.value]] || titles[select.value] || ""; - }; +function processTooltipCheckNodes() { + for (const node of tooltipCheckNodes) { + updateTooltip(node); + } + tooltipCheckNodes.clear(); } -var observedTooltipElements = {SPAN: 1, BUTTON: 1, SELECT: 1, P: 1}; - -onUiUpdate(function(m) { - m.forEach(function(record) { - record.addedNodes.forEach(function(node) { - if (observedTooltipElements[node.tagName]) { - updateTooltipForSpan(node); +onUiUpdate(function(mutationRecords) { + for (const record of mutationRecords) { + for (const node of record.addedNodes) { + if (node.nodeType === Node.ELEMENT_NODE && !node.classList.contains("hide")) { + if ( + node.tagName === "SPAN" || + node.tagName === "BUTTON" || + node.tagName === "P" + ) { + tooltipCheckNodes.add(node); + } + node.querySelectorAll('span, button, p').forEach(n => tooltipCheckNodes.add(n)); } - if (node.tagName == "SELECT") { - updateTooltipForSelect(node); - } - - if (node.querySelectorAll) { - node.querySelectorAll('span, button, select, p').forEach(updateTooltipForSpan); - node.querySelectorAll('select').forEach(updateTooltipForSelect); - } - }); - }); + } + } + if (tooltipCheckNodes.size) { + clearTimeout(tooltipCheckTimer); + tooltipCheckTimer = setTimeout(processTooltipCheckNodes, 1000); + } }); From b82d4a65fe9b025e9da1b8c7a72ed9d56b96315d Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 24 May 2023 20:34:57 +0300 Subject: [PATCH 2/3] Restore support for dropdown tooltips --- javascript/hints.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index a8c72976..7f8885bc 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -153,14 +153,27 @@ function processTooltipCheckNodes() { onUiUpdate(function(mutationRecords) { for (const record of mutationRecords) { + if (record.type === "childList" && record.target.classList.contains("options")) { + // This smells like a Gradio dropdown menu having changed, + // so let's enqueue an update for the input element that shows the current value. + let wrap = record.target.parentNode; + let input = wrap?.querySelector("input"); + if (input) { + input.title = ""; // So we'll even have a chance to update it. + tooltipCheckNodes.add(input); + } + } for (const node of record.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE && !node.classList.contains("hide")) { - if ( - node.tagName === "SPAN" || - node.tagName === "BUTTON" || - node.tagName === "P" - ) { - tooltipCheckNodes.add(node); + if (!node.title) { + if ( + node.tagName === "SPAN" || + node.tagName === "BUTTON" || + node.tagName === "P" || + node.tagName === "INPUT" + ) { + tooltipCheckNodes.add(node); + } } node.querySelectorAll('span, button, p').forEach(n => tooltipCheckNodes.add(n)); } From 32b0f7c9bbb908b870c2e0d488bd63a9c71ba078 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Wed, 24 May 2023 20:45:05 +0300 Subject: [PATCH 3/3] Add support for tooltips on dropdown options --- javascript/hints.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index 7f8885bc..05ae5f22 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -119,10 +119,18 @@ var titles = { function updateTooltip(element) { if (element.title) return; // already has a title - let tooltip = localization[titles[element.textContent]] || titles[element.textContent]; + let text = element.textContent; + let tooltip = localization[titles[text]] || titles[text]; if (!tooltip) { - tooltip = localization[titles[element.value]] || titles[element.value]; + let value = element.value; + if (value) tooltip = localization[titles[value]] || titles[value]; + } + + if (!tooltip) { + // Gradio dropdown options have `data-value`. + let dataValue = element.dataset.value; + if (dataValue) tooltip = localization[titles[dataValue]] || titles[dataValue]; } if (!tooltip) { @@ -170,7 +178,8 @@ onUiUpdate(function(mutationRecords) { node.tagName === "SPAN" || node.tagName === "BUTTON" || node.tagName === "P" || - node.tagName === "INPUT" + node.tagName === "INPUT" || + (node.tagName === "LI" && node.classList.contains("item")) // Gradio dropdown item ) { tooltipCheckNodes.add(node); }