luci-base, themes: dropdown behaviour improvements

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2018-11-08 13:02:24 +01:00
parent e35fb36ea5
commit 4791180eb3
3 changed files with 98 additions and 41 deletions

View file

@ -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', '');
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 pv = ul.cloneNode(true);
pv.classList.add('preview');
ul.style.top = h + 'px';
if (fl)
fl.classList.add('cbi-dropdown-open');
if ('ontouchstart' in window) {
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 = 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';
window.scrollTo(0, (scroll + rect.top - vpHeight * 0.6));
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.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();

View file

@ -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],

View file

@ -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;