diff options
author | Jo-Philipp Wich <jo@mein.io> | 2018-11-08 13:02:24 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2018-11-14 20:46:04 +0100 |
commit | 4791180eb3253381b4bc69342ee58605a15431dd (patch) | |
tree | fb71a1fc670d0b07114762b5692a0ed6825f44ca /modules | |
parent | e35fb36ea59e271aa9726a73783446977ac0166e (diff) |
luci-base, themes: dropdown behaviour improvements
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'modules')
-rw-r--r-- | modules/luci-base/htdocs/luci-static/resources/cbi.js | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js index 9c8341cc5..b3ba8259f 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(); |