summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2018-11-08 13:02:24 +0100
committerJo-Philipp Wich <jo@mein.io>2018-11-14 20:46:04 +0100
commit4791180eb3253381b4bc69342ee58605a15431dd (patch)
treefb71a1fc670d0b07114762b5692a0ed6825f44ca
parente35fb36ea59e271aa9726a73783446977ac0166e (diff)
luci-base, themes: dropdown behaviour improvements
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js83
-rw-r--r--themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css2
-rw-r--r--themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css52
3 files changed, 97 insertions, 40 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index 9c8341cc54..b3ba8259f9 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -1436,6 +1436,14 @@ if (window.NodeList && !NodeList.prototype.forEach) {
};
}
+if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = function(f) {
+ window.setTimeout(function() {
+ f(new Date().getTime())
+ }, 1000/30);
+ };
+}
+
var dummyElem, domParser;
@@ -1556,11 +1564,10 @@ CBIDropdown = {
var st = window.getComputedStyle(sb, null),
ul = sb.querySelector('ul'),
li = ul.querySelectorAll('li'),
+ fl = findParent(sb, '.cbi-value-field'),
sel = ul.querySelector('[selected]'),
rect = sb.getBoundingClientRect(),
- h = sb.clientHeight - parseFloat(st.paddingTop) - parseFloat(st.paddingBottom),
- mh = this.dropdown_items * h,
- eh = Math.min(mh, li.length * h);
+ items = Math.min(this.dropdown_items, li.length);
document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
@@ -1568,22 +1575,54 @@ CBIDropdown = {
sb.setAttribute('open', '');
+ var pv = ul.cloneNode(true);
+ pv.classList.add('preview');
+
+ if (fl)
+ fl.classList.add('cbi-dropdown-open');
+
if ('ontouchstart' in window) {
- var scroll = document.documentElement.scrollTop,
- vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
- vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+ var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
+ vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
+ scrollFrom = window.pageYOffset,
+ scrollTo = scrollFrom + rect.top - vpHeight * 0.5,
+ start = null;
- ul.style.top = h + 'px';
+ ul.style.top = sb.offsetHeight + 'px';
ul.style.left = -rect.left + 'px';
ul.style.right = (rect.right - vpWidth) + 'px';
+ ul.style.maxHeight = (vpHeight * 0.5) + 'px';
+ ul.style.WebkitOverflowScrolling = 'touch';
+
+ var scrollStep = function(timestamp) {
+ if (!start) {
+ start = timestamp;
+ ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
+ }
+
+ var duration = Math.max(timestamp - start, 1);
+ if (duration < 100) {
+ document.body.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration / 100);
+ window.requestAnimationFrame(scrollStep);
+ }
+ else {
+ document.body.scrollTop = scrollTo;
+ }
+ };
- window.scrollTo(0, (scroll + rect.top - vpHeight * 0.6));
+ window.requestAnimationFrame(scrollStep);
}
else {
- ul.style.maxHeight = mh + 'px';
- ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
+ ul.style.maxHeight = '1px';
ul.style.top = ul.style.bottom = '';
- ul.style[((rect.top + rect.height + eh) > window.innerHeight) ? 'bottom' : 'top'] = rect.height + 'px';
+
+ window.requestAnimationFrame(function() {
+ var height = items * li[Math.max(0, li.length - 2)].offsetHeight;
+
+ ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
+ ul.style[((rect.top + rect.height + height) > window.innerHeight) ? 'bottom' : 'top'] = rect.height + 'px';
+ ul.style.maxHeight = height + 'px';
+ });
}
ul.querySelectorAll('[selected] input[type="checkbox"]').forEach(function(c) {
@@ -1592,10 +1631,6 @@ CBIDropdown = {
ul.classList.add('dropdown');
- var pv = ul.cloneNode(true);
- pv.classList.remove('dropdown');
- pv.classList.add('preview');
-
sb.insertBefore(pv, ul.nextElementSibling);
li.forEach(function(l) {
@@ -1613,7 +1648,8 @@ CBIDropdown = {
var pv = sb.querySelector('ul.preview'),
ul = sb.querySelector('ul.dropdown'),
- li = ul.querySelectorAll('li');
+ li = ul.querySelectorAll('li'),
+ fl = findParent(sb, '.cbi-value-field');
li.forEach(function(l) { l.removeAttribute('tabindex'); });
sb.lastElementChild.removeAttribute('tabindex');
@@ -1623,6 +1659,10 @@ CBIDropdown = {
sb.style.width = sb.style.height = '';
ul.classList.remove('dropdown');
+ ul.style.top = ul.style.bottom = ul.style.maxHeight = '';
+
+ if (fl)
+ fl.classList.remove('cbi-dropdown-open');
if (!no_focus)
this.setFocus(sb, sb);
@@ -1817,14 +1857,13 @@ CBIDropdown = {
createItems: function(sb, value) {
var sbox = this,
- val = (value || '').trim().split(/\s+/),
+ val = (value || '').trim(),
ul = sb.querySelector('ul');
if (!sbox.multi)
- val.length = Math.min(val.length, 1);
-
- if (val.length === 1 && val[0].length === 0)
- val.length = 0;
+ val = val.length ? [ val ] : [];
+ else
+ val = val.length ? val.split(/\s+/) : [];
val.forEach(function(item) {
var new_item = null;
@@ -1881,6 +1920,8 @@ CBIDropdown = {
var li = findParent(ev.target, 'li');
if (li && li.parentNode.classList.contains('dropdown'))
this.toggleItem(sb, li);
+ else if (li && li.parentNode.classList.contains('preview'))
+ this.closeDropdown(sb);
}
ev.preventDefault();
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 22c49fdde1..e64744994e 100644
--- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
+++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
@@ -60,7 +60,6 @@ blockquote:after {
}
html {
- overflow-y: scroll;
font-size: 100%;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
@@ -1457,6 +1456,7 @@ footer {
max-width: none;
min-width: 100%;
width: auto;
+ transition: max-height .125s ease-in;
}
.cbi-dropdown > ul > li[display],
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 f24493c993..a88d678f6d 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
@@ -491,16 +491,16 @@ select:hover {
input[type=text],
input[type=password] {
- padding: 0 3px;
+ padding: .25em;
}
select,
input[type=text],
-input[type=password] {
+input[type=password],
+.cbi-dropdown {
width: 20em;
- font-size: inherit;
- line-height: 13pt;
- height: 14pt;
+ font-size: 10pt;
+ height: 22px;
}
select[multiple] {
@@ -521,7 +521,6 @@ input.cbi-input-password + img {
width: 100%;
}
-.td [data-dynlist] > input,
.td input.cbi-input-password {
width: calc(100% - 20px);
}
@@ -1050,6 +1049,7 @@ ul.cbi-tabmenu li.cbi-tab {
font-weight: bold;
text-shadow: 1px 1px 0px #fff;
display: none;
+ min-height: 22px;
}
.cbi-dropdown > ul > li {
@@ -1062,7 +1062,7 @@ ul.cbi-tabmenu li.cbi-tab {
flex-grow: 1;
align-items: center;
align-self: center;
- min-height: 20px;
+ min-height: 22px;
}
.cbi-dropdown > ul > li .hide-open { display: initial; }
@@ -1092,10 +1092,6 @@ ul.cbi-tabmenu li.cbi-tab {
margin: 0;
}
-.cbi-dropdown > ul > li input[type="text"] {
- height: 20px;
-}
-
.cbi-dropdown[open] {
position: relative;
}
@@ -1110,6 +1106,7 @@ ul.cbi-tabmenu li.cbi-tab {
max-width: none;
min-width: 100%;
width: auto;
+ transition: max-height .125s ease-in;
}
.cbi-dropdown > ul > li[display],
@@ -1125,7 +1122,6 @@ ul.cbi-tabmenu li.cbi-tab {
}
.cbi-dropdown[empty] > ul > li,
-.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder],
.cbi-dropdown[multiple][open] > ul.dropdown > li > form {
display: block;
}
@@ -1213,9 +1209,9 @@ select + .cbi-button {
padding: 0 6px;
vertical-align: top;
display: inline-block;
- height: 14pt;
+ height: 22px;
font-size: 10pt;
- line-height: 12pt;
+ line-height: 20px;
}
.cbi-tooltip-container {
@@ -1240,6 +1236,7 @@ select + .cbi-button {
left: auto;
opacity: 1;
transition: opacity .25s ease-in;
+ white-space: normal;
}
.zonebadge .cbi-tooltip {
@@ -1652,6 +1649,10 @@ select + .cbi-button {
display: inline-block;
}
+ .td.cbi-dropdown-open {
+ overflow: visible;
+ }
+
.td select {
word-wrap: normal;
}
@@ -1734,26 +1735,41 @@ select + .cbi-button {
font-size: 12pt;
}
- input, textarea, select {
+ input, textarea, select, .cbi-button {
font-size: 12pt !important;
- line-height: 1.4em;
+ line-height: 30px;
}
select, input[type="text"], input[type="password"] {
width: 100%;
- height: 1.4em;
+ height: 30px;
}
- input.cbi-input-password {
+ input[type="text"] + .cbi-button,
+ input[type="password"] + .cbi-button,
+ select + .cbi-button {
+ height: 30px;
+ line-height: 28px;
+ }
+
+ input.cbi-input-password,
+ [data-dynlist] > .add-item > input {
width: calc(100% - 20px);
}
.cbi-dynlist,
.cbi-dropdown {
min-width: 100%;
+ height: auto;
display: flex;
}
+ .cbi-dropdown > .more,
+ .cbi-dropdown > ul > li,
+ .cbi-dropdown > ul > li[placeholder] {
+ min-height: 30px;
+ }
+
.btn, .cbi-button {
font-size: 9pt !important;
line-height: 13pt;