From 7f613be5000e753e99ce5b829748fb43fca78754 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 18 Oct 2018 16:14:35 +0200 Subject: [PATCH] luci-base, themes: add tooltip helpers & styles Add the required JS and CSS infrastructure to support rich hover/focus tooltips for element. Signed-off-by: Jo-Philipp Wich --- .../htdocs/luci-static/resources/cbi.js | 52 +++++++++++++++++++ .../htdocs/luci-static/bootstrap/cascade.css | 19 ++++--- .../luci-static/freifunk-generic/cascade.css | 13 ++++- .../htdocs/luci-static/material/cascade.css | 6 ++- .../luci-static/openwrt.org/cascade.css | 16 ++++-- 5 files changed, 93 insertions(+), 13 deletions(-) diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js index b1fc26c74..b92b86f52 100644 --- a/modules/luci-base/htdocs/luci-static/resources/cbi.js +++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js @@ -2191,6 +2191,58 @@ function cbi_update_table(table, data, placeholder) { }); } +var tooltipDiv = null, tooltipTimeout = null; + +function showTooltip(ev) { + if (!matchesElem(ev.target, '[data-tooltip]')) + return; + + if (tooltipTimeout !== null) { + window.clearTimeout(tooltipTimeout); + tooltipTimeout = null; + } + + var rect = ev.target.getBoundingClientRect(), + x = rect.left + window.pageXOffset, + y = rect.top + rect.height + window.pageYOffset; + + tooltipDiv.className = 'cbi-tooltip'; + tooltipDiv.innerHTML = '▲ '; + tooltipDiv.firstChild.data += ev.target.getAttribute('data-tooltip'); + + if (ev.target.hasAttribute('data-tooltip-style')) + tooltipDiv.classList.add(ev.target.getAttribute('data-tooltip-style')); + + if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset)) { + y -= (tooltipDiv.offsetHeight + ev.target.offsetHeight); + tooltipDiv.firstChild.data = '▼ ' + tooltipDiv.firstChild.data.substr(2); + } + + tooltipDiv.style.top = y + 'px'; + tooltipDiv.style.left = x + 'px'; + tooltipDiv.style.opacity = 1; +} + +function hideTooltip(ev) { + if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv) + return; + + if (tooltipTimeout !== null) { + window.clearTimeout(tooltipTimeout); + tooltipTimeout = null; + } + + tooltipDiv.style.opacity = 0; + tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250); +} + document.addEventListener('DOMContentLoaded', function() { + tooltipDiv = document.body.appendChild(E('div', { 'class': 'cbi-tooltip' })); + + document.addEventListener('mouseover', showTooltip, true); + document.addEventListener('mouseout', hideTooltip, true); + document.addEventListener('focus', showTooltip, true); + document.addEventListener('blur', hideTooltip, true); + document.querySelectorAll('.table').forEach(cbi_update_table); }); diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css index a30dc45b7..690fd2ad4 100644 --- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css +++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css @@ -1168,7 +1168,8 @@ footer { .btn.info, .alert-message.info, .btn.info:hover, -.alert-message.info:hover { +.alert-message.info:hover, +.cbi-tooltip.error, .cbi-tooltip.success, .cbi-tooltip.info { color: #fff; } @@ -1180,25 +1181,26 @@ footer { .btn.danger, .alert-message.danger, .btn.error, -.alert-message.error { +.alert-message.error, +.cbi-tooltip.error { background: linear-gradient(to bottom, #ee5f5b, #c43c35) repeat-x; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); } -.btn.success, .alert-message.success { +.btn.success, .alert-message.success, .cbi-tooltip.success { background: linear-gradient(to bottom, #62c462, #57a957) repeat-x; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); } -.btn.info, .alert-message.info { +.btn.info, .alert-message.info, .cbi-tooltip.info { background: linear-gradient(to bottom, #5bc0de, #339bb9) repeat-x; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); } -.alert-message.notice { +.alert-message.notice, .cbi-tooltip.notice { background: linear-gradient(to bottom, #efefef, #fefefe) repeat-x; text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25); border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); @@ -1491,8 +1493,13 @@ select + .cbi-button { position: absolute; z-index: 1000; left: -1000px; + box-shadow: 0 0 2px #ccc; + border-radius: 3px; + background: #fff; + white-space: pre; + padding: 2px 5px; opacity: 0; - transition: opacity .25s ease-out; + transition: opacity .25s ease-in; } .cbi-tooltip-container:hover .cbi-tooltip:not(:empty) { diff --git a/themes/luci-theme-freifunk-generic/htdocs/luci-static/freifunk-generic/cascade.css b/themes/luci-theme-freifunk-generic/htdocs/luci-static/freifunk-generic/cascade.css index 3e1b1cd2f..b9ac0f033 100644 --- a/themes/luci-theme-freifunk-generic/htdocs/luci-static/freifunk-generic/cascade.css +++ b/themes/luci-theme-freifunk-generic/htdocs/luci-static/freifunk-generic/cascade.css @@ -156,12 +156,17 @@ a img { color: #000; } -.alert-message.notice { +.alert-message, .cbi-tooltip.error { + background: #fee; + color: #a22; +} + +.alert-message.notice, .cbi-tooltip.notice { background: linear-gradient(#ccc 0%, #eee 100%); color: #4a6b7c; } -.alert-message.warning { +.alert-message.warning, .cbi-tooltip.warning { background: linear-gradient(#dda 0%, #dd8 100%); color: #c00; } @@ -1354,6 +1359,10 @@ td.cbi-value-error { position: absolute; z-index: 1000; left: -1000px; + border-radius: 3px; + background: #fff; + padding: 2px 5px; + white-space: pre; opacity: 0; transition: opacity .25s ease-out; pointer-events: none; diff --git a/themes/luci-theme-material/htdocs/luci-static/material/cascade.css b/themes/luci-theme-material/htdocs/luci-static/material/cascade.css index 6961bfe2d..a4d71eeb6 100644 --- a/themes/luci-theme-material/htdocs/luci-static/material/cascade.css +++ b/themes/luci-theme-material/htdocs/luci-static/material/cascade.css @@ -291,7 +291,7 @@ header { } header > .fill > .container { - padding-top: 0.25rem; + padding-top: 0.25rem; padding-right: 1rem; padding-bottom: 0.25rem; display: flex; @@ -1481,6 +1481,10 @@ small { position: absolute; z-index: 1000; left: -1000px; + border-radius: 3px; + background: #fff; + padding: 2px 5px; + white-space: pre; opacity: 0; transition: opacity .25s ease-out; pointer-events: none; diff --git a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css index 5becfc5ba..94d6b5729 100644 --- a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css +++ b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css @@ -231,18 +231,22 @@ hr { padding: .5em; border-radius: 3px; border: 1px solid #a22; - color: #a22; - background: #fee; margin: 0 0 .5em 0; } -.alert-message.notice { +.alert-message, .cbi-tooltip.error { + border-color: #a22; + background: #fee; + color: #a22; +} + +.alert-message.notice, .cbi-tooltip.notice { border-color: #15a; background: #e6f6ff; color: #15a; } -.alert-message.warning { +.alert-message.warning, .cbi-tooltip.warning { border-color: #ed5; background: #fe9; color: #650; @@ -1173,6 +1177,10 @@ select + .cbi-button { position: absolute; z-index: 1000; left: -1000px; + border-radius: 3px; + background: #fff; + padding: 2px 5px; + white-space: pre; opacity: 0; transition: opacity .25s ease-out; pointer-events: none; -- 2.25.1