summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js516
-rw-r--r--modules/luci-base/luasrc/cbi.lua9
-rw-r--r--modules/luci-base/luasrc/view/cbi/dropdown.htm42
-rw-r--r--themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css171
-rwxr-xr-xthemes/luci-theme-material/htdocs/luci-static/material/css/style.css233
-rw-r--r--themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css208
6 files changed, 1115 insertions, 64 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index 0a1961916..a7f999d87 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -465,31 +465,16 @@ function cbi_d_add(field, dep, index) {
}
function cbi_d_checkvalue(target, ref) {
- var t = document.getElementById(target);
- var value;
+ var value = null,
+ query = 'input[id="'+target+'"], input[name="'+target+'"], ' +
+ 'select[id="'+target+'"], select[name="'+target+'"]';
- if (!t) {
- var tl = document.getElementsByName(target);
-
- if( tl.length > 0 && (tl[0].type == 'radio' || tl[0].type == 'checkbox'))
- for( var i = 0; i < tl.length; i++ )
- if( tl[i].checked ) {
- value = tl[i].value;
- break;
- }
-
- value = value ? value : "";
- } else if (!t.value) {
- value = "";
- } else {
- value = t.value;
-
- if (t.type == "checkbox") {
- value = t.checked ? value : "";
- }
- }
+ document.querySelectorAll(query).forEach(function(i) {
+ if (value === null && ((i.type !== 'radio' && i.type !== 'checkbox') || i.checked === true))
+ value = i.value;
+ });
- return (value == ref)
+ return (((value !== null) ? value : "") == ref);
}
function cbi_d_check(deps) {
@@ -634,6 +619,10 @@ function cbi_init() {
node.getAttribute('data-type'));
}
+ document.querySelectorAll('.cbi-dropdown').forEach(function(s) {
+ cbi_dropdown_init(s);
+ });
+
cbi_d_update();
}
@@ -1574,3 +1563,484 @@ function E()
return elem;
}
+
+if (typeof(window.CustomEvent) !== 'function') {
+ function CustomEvent(event, params) {
+ params = params || { bubbles: false, cancelable: false, detail: undefined };
+ var evt = document.createEvent('CustomEvent');
+ evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
+ return evt;
+ }
+
+ CustomEvent.prototype = window.Event.prototype;
+ window.CustomEvent = CustomEvent;
+}
+
+CBIDropdown = {
+ openDropdown: function(sb) {
+ var st = window.getComputedStyle(sb, null),
+ ul = sb.querySelector('ul'),
+ li = ul.querySelectorAll('li'),
+ 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);
+
+ document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
+ s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
+ });
+
+ ul.style.maxHeight = mh + 'px';
+ sb.setAttribute('open', '');
+
+ ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0;
+ ul.querySelectorAll('[selected] input[type="checkbox"]').forEach(function(c) {
+ c.checked = true;
+ });
+
+ ul.style.top = ul.style.bottom = '';
+ ul.style[((sb.getBoundingClientRect().top + eh) > window.innerHeight) ? 'bottom' : 'top'] = rect.height + 'px';
+ 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) {
+ l.setAttribute('tabindex', 0);
+ });
+
+ sb.lastElementChild.setAttribute('tabindex', 0);
+
+ this.setFocus(sb, sel || li[0], true);
+ },
+
+ closeDropdown: function(sb, no_focus) {
+ if (!sb.hasAttribute('open'))
+ return;
+
+ var pv = sb.querySelector('ul.preview'),
+ ul = sb.querySelector('ul.dropdown'),
+ li = ul.querySelectorAll('li');
+
+ li.forEach(function(l) { l.removeAttribute('tabindex'); });
+ sb.lastElementChild.removeAttribute('tabindex');
+
+ sb.removeChild(pv);
+ sb.removeAttribute('open');
+ sb.style.width = sb.style.height = '';
+
+ ul.classList.remove('dropdown');
+
+ if (!no_focus)
+ this.setFocus(sb, sb);
+
+ this.saveValues(sb, ul);
+ },
+
+ toggleItem: function(sb, li, force_state) {
+ if (li.hasAttribute('unselectable'))
+ return;
+
+ if (this.multi) {
+ var cbox = li.querySelector('input[type="checkbox"]'),
+ items = li.parentNode.querySelectorAll('li'),
+ label = sb.querySelector('ul.preview'),
+ sel = li.parentNode.querySelectorAll('[selected]').length,
+ more = sb.querySelector('.more'),
+ ndisplay = this.display_items,
+ n = 0;
+
+ if (li.hasAttribute('selected')) {
+ if (force_state !== true) {
+ if (sel > 1 || this.optional) {
+ li.removeAttribute('selected');
+ cbox.checked = cbox.disabled = false;
+ sel--;
+ }
+ else {
+ cbox.disabled = true;
+ }
+ }
+ }
+ else {
+ if (force_state !== false) {
+ li.setAttribute('selected', '');
+ cbox.checked = true;
+ cbox.disabled = false;
+ sel++;
+ }
+ }
+
+ while (label.firstElementChild)
+ label.removeChild(label.firstElementChild);
+
+ for (var i = 0; i < items.length; i++) {
+ items[i].removeAttribute('display');
+ if (items[i].hasAttribute('selected')) {
+ if (ndisplay-- > 0) {
+ items[i].setAttribute('display', n++);
+ label.appendChild(items[i].cloneNode(true));
+ }
+ var c = items[i].querySelector('input[type="checkbox"]');
+ if (c)
+ c.disabled = (sel == 1 && !this.optional);
+ }
+ }
+
+ if (ndisplay < 0)
+ sb.setAttribute('more', '');
+ else
+ sb.removeAttribute('more');
+
+ if (ndisplay === this.display_items)
+ sb.setAttribute('empty', '');
+ else
+ sb.removeAttribute('empty');
+
+ more.innerHTML = (ndisplay === this.display_items) ? this.placeholder : '···';
+ }
+ else {
+ var sel = li.parentNode.querySelector('[selected]');
+ if (sel) {
+ sel.removeAttribute('display');
+ sel.removeAttribute('selected');
+ }
+
+ li.setAttribute('display', 0);
+ li.setAttribute('selected', '');
+
+ this.closeDropdown(sb, true);
+ }
+
+ this.saveValues(sb, li.parentNode);
+ },
+
+ transformItem: function(sb, li) {
+ var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })),
+ label = E('label');
+
+ while (li.firstChild)
+ label.appendChild(li.firstChild);
+
+ li.appendChild(cbox);
+ li.appendChild(label);
+ },
+
+ saveValues: function(sb, ul) {
+ var sel = ul.querySelectorAll('[selected]'),
+ div = sb.lastElementChild;
+
+ while (div.lastElementChild)
+ div.removeChild(div.lastElementChild);
+
+ sel.forEach(function (s) {
+ div.appendChild(E('input', {
+ type: 'hidden',
+ name: s.hasAttribute('name') ? s.getAttribute('name') : (sb.getAttribute('name') || ''),
+ value: s.hasAttribute('value') ? s.getAttribute('value') : s.innerText
+ }));
+ });
+
+ cbi_d_update();
+ },
+
+ setFocus: function(sb, elem, scroll) {
+ if (sb && sb.hasAttribute && sb.hasAttribute('locked-in'))
+ return;
+
+ document.querySelectorAll('.focus').forEach(function(e) {
+ if (e.nodeName.toLowerCase() !== 'input') {
+ e.classList.remove('focus');
+ e.blur();
+ }
+ });
+
+ if (elem) {
+ elem.focus();
+ elem.classList.add('focus');
+
+ if (scroll)
+ elem.parentNode.scrollTop = elem.offsetTop - elem.parentNode.offsetTop;
+ }
+ },
+
+ createItems: function(sb, value) {
+ var sbox = this,
+ val = (value || '').trim().split(/\s+/),
+ ul = sb.querySelector('ul');
+
+ if (!sbox.multi)
+ val.length = Math.min(val.length, 1);
+
+ val.forEach(function(item) {
+ var new_item = null;
+
+ ul.childNodes.forEach(function(li) {
+ if (li.getAttribute && li.getAttribute('value') === item)
+ new_item = li;
+ });
+
+ if (!new_item) {
+ var markup,
+ tpl = sb.querySelector(sbox.template);
+
+ if (tpl)
+ markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^<!--|-->$/, '').trim();
+ else
+ markup = '<li value="{{value}}">{{value}}</li>';
+
+ new_item = E(markup.replace(/{{value}}/g, item));
+
+ if (sbox.multi) {
+ sbox.transformItem(sb, new_item);
+ }
+ else {
+ var old = ul.querySelector('li[created]');
+ if (old)
+ ul.removeChild(old);
+
+ new_item.setAttribute('created', '');
+ }
+
+ new_item = ul.insertBefore(new_item, ul.lastElementChild);
+ }
+
+ sbox.toggleItem(sb, new_item, true);
+ sbox.setFocus(sb, new_item, true);
+ });
+ },
+
+ closeAllDropdowns: function() {
+ document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
+ s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
+ });
+ },
+
+ findParent: function(node, selector) {
+ while (node)
+ if (node.msMatchesSelector && node.msMatchesSelector(selector))
+ return node;
+ else if (node.matches && node.matches(selector))
+ return node;
+ else
+ node = node.parentNode;
+
+ return null;
+ }
+};
+
+function cbi_dropdown_init(sb) {
+ if (!(this instanceof cbi_dropdown_init))
+ return new cbi_dropdown_init(sb);
+
+ this.multi = sb.hasAttribute('multiple');
+ this.optional = sb.hasAttribute('optional');
+ this.placeholder = sb.getAttribute('placeholder') || '---';
+ this.display_items = parseInt(sb.getAttribute('display-items') || 3);
+ this.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || 5);
+ this.create = sb.getAttribute('item-create') || '.create-item-input';
+ this.template = sb.getAttribute('item-template') || 'script[type="item-template"]';
+
+ var sbox = this,
+ ul = sb.querySelector('ul'),
+ items = ul.querySelectorAll('li'),
+ more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')),
+ open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾')),
+ canary = sb.appendChild(E('div')),
+ create = sb.querySelector(this.create),
+ ndisplay = this.display_items,
+ n = 0;
+
+ if (this.multi) {
+ for (var i = 0; i < items.length; i++) {
+ sbox.transformItem(sb, items[i]);
+
+ if (items[i].hasAttribute('selected') && ndisplay-- > 0)
+ items[i].setAttribute('display', n++);
+ }
+ }
+ else {
+ var sel = sb.querySelectorAll('[selected]');
+
+ sel.forEach(function(s) {
+ s.removeAttribute('selected');
+ });
+
+ var s = sel[0] || items[0];
+ if (s) {
+ s.setAttribute('selected', '');
+ s.setAttribute('display', n++);
+ }
+
+ ndisplay--;
+
+ if (this.optional && !ul.querySelector('li[value=""]')) {
+ var placeholder = E('li', { placeholder: '' }, this.placeholder);
+ ul.firstChild ? ul.insertBefore(placeholder, ul.firstChild) : ul.appendChild(placeholder);
+ }
+ }
+
+ sbox.saveValues(sb, ul);
+
+ ul.setAttribute('tabindex', -1);
+ sb.setAttribute('tabindex', 0);
+
+ if (ndisplay < 0)
+ sb.setAttribute('more', '')
+ else
+ sb.removeAttribute('more');
+
+ if (ndisplay === this.display_items)
+ sb.setAttribute('empty', '')
+ else
+ sb.removeAttribute('empty');
+
+ more.innerHTML = (ndisplay === this.display_items) ? this.placeholder : '···';
+
+
+ sb.addEventListener('click', function(ev) {
+ if (!this.hasAttribute('open')) {
+ if (ev.target.nodeName.toLowerCase() !== 'input')
+ sbox.openDropdown(this);
+ }
+ else {
+ var li = sbox.findParent(ev.target, 'li');
+ if (li && li.parentNode.classList.contains('dropdown'))
+ sbox.toggleItem(this, li);
+ }
+
+ ev.preventDefault();
+ ev.stopPropagation();
+ });
+
+ sb.addEventListener('keydown', function(ev) {
+ if (ev.target.nodeName.toLowerCase() === 'input')
+ return;
+
+ if (!this.hasAttribute('open')) {
+ switch (ev.keyCode) {
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ sbox.openDropdown(this);
+ ev.preventDefault();
+ }
+ }
+ else
+ {
+ var active = sbox.findParent(document.activeElement, 'li');
+
+ switch (ev.keyCode) {
+ case 27:
+ sbox.closeDropdown(this);
+ break;
+
+ case 13:
+ if (active) {
+ if (!active.hasAttribute('selected'))
+ sbox.toggleItem(this, active);
+ sbox.closeDropdown(this);
+ ev.preventDefault();
+ }
+ break;
+
+ case 32:
+ if (active) {
+ sbox.toggleItem(this, active);
+ ev.preventDefault();
+ }
+ break;
+
+ case 38:
+ if (active && active.previousElementSibling) {
+ sbox.setFocus(this, active.previousElementSibling);
+ ev.preventDefault();
+ }
+ break;
+
+ case 40:
+ if (active && active.nextElementSibling) {
+ sbox.setFocus(this, active.nextElementSibling);
+ ev.preventDefault();
+ }
+ break;
+ }
+ }
+ });
+
+ sb.addEventListener('cbi-dropdown-close', function(ev) {
+ sbox.closeDropdown(this, true);
+ });
+
+ if ('ontouchstart' in window) {
+ sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); });
+ window.addEventListener('touchstart', sbox.closeAllDropdowns);
+ }
+ else {
+ sb.addEventListener('mouseover', function(ev) {
+ if (!this.hasAttribute('open'))
+ return;
+
+ var li = sbox.findParent(ev.target, 'li');
+ if (li) {
+ if (li.parentNode.classList.contains('dropdown'))
+ sbox.setFocus(this, li);
+
+ ev.stopPropagation();
+ }
+ });
+
+ sb.addEventListener('focus', function(ev) {
+ document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) {
+ if (s !== this || this.hasAttribute('open'))
+ s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {}));
+ });
+ });
+
+ canary.addEventListener('focus', function(ev) {
+ sbox.closeDropdown(this.parentNode);
+ });
+
+ window.addEventListener('mouseover', sbox.setFocus);
+ window.addEventListener('click', sbox.closeAllDropdowns);
+ }
+
+ if (create) {
+ create.addEventListener('keydown', function(ev) {
+ switch (ev.keyCode) {
+ case 13:
+ sbox.createItems(sb, this.value);
+ ev.preventDefault();
+ this.value = '';
+ this.blur();
+ break;
+ }
+ });
+
+ create.addEventListener('focus', function(ev) {
+ var cbox = sbox.findParent(this, 'li').querySelector('input[type="checkbox"]');
+ if (cbox) cbox.checked = true;
+ sb.setAttribute('locked-in', '');
+ });
+
+ create.addEventListener('blur', function(ev) {
+ var cbox = sbox.findParent(this, 'li').querySelector('input[type="checkbox"]');
+ if (cbox) cbox.checked = false;
+ sb.removeAttribute('locked-in');
+ });
+
+ var li = sbox.findParent(create, 'li');
+
+ li.setAttribute('unselectable', '');
+ li.addEventListener('click', function(ev) {
+ this.querySelector(sbox.create).focus();
+ });
+ }
+}
+
+cbi_dropdown_init.prototype = CBIDropdown;
diff --git a/modules/luci-base/luasrc/cbi.lua b/modules/luci-base/luasrc/cbi.lua
index 3a55eb23c..d275c5b27 100644
--- a/modules/luci-base/luasrc/cbi.lua
+++ b/modules/luci-base/luasrc/cbi.lua
@@ -1846,6 +1846,15 @@ function DynamicList.formvalue(self, section)
end
+DropDown = class(MultiValue)
+
+function DropDown.__init__(self, ...)
+ ListValue.__init__(self, ...)
+ self.template = "cbi/dropdown"
+ self.delimiter = " "
+end
+
+
--[[
TextValue - A multi-line value
rows: Rows
diff --git a/modules/luci-base/luasrc/view/cbi/dropdown.htm b/modules/luci-base/luasrc/view/cbi/dropdown.htm
new file mode 100644
index 000000000..bdf724837
--- /dev/null
+++ b/modules/luci-base/luasrc/view/cbi/dropdown.htm
@@ -0,0 +1,42 @@
+<%+cbi/valueheader%>
+
+<%-
+ local selected = { }
+
+ if self.multiple then
+ local val
+ for val in luci.util.imatch(self:cfgvalue(section)) do
+ selected[val] = true
+ end
+ else
+ selected[self:cfgvalue(section)] = true
+ end
+
+ if not next(selected) and self.default then
+ selected[self.default] = true
+ end
+-%>
+
+<div class="cbi-dropdown"<%=
+ attr("name", cbid) ..
+ attr("display-items", self.display or self.size or 3) ..
+ attr("dropdown-items", self.dropdown or self.display or self.size or 5) ..
+ attr("placeholder", self.placeholder or translate("-- please select --")) ..
+ ifattr(self.multiple, "multiple", "multiple") ..
+ ifattr(self.optional or self.rmempty, "optional", "optional")
+%>>
+ <ul>
+ <% local i, key; for i, key in pairs(self.keylist) do %>
+ <li<%=
+ attr("data-index", i) ..
+ attr("data-depends", self:deplist2json(section, self.deplist[i])) ..
+ attr("value", key) ..
+ ifattr(selected[key], "selected", "selected")
+ %>>
+ <%=pcdata(self.vallist[i])%>
+ </li>
+ <% end %>
+ </ul>
+</div>
+
+<%+cbi/valuefooter%>
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 5aff09148..4a40f6d68 100644
--- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
+++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
@@ -430,7 +430,6 @@ form .clearfix,
form .cbi-value {
margin-bottom: 18px;
zoom: 1;
- overflow: hidden;
}
form .clearfix:before, form .clearfix:after,
@@ -477,6 +476,7 @@ input[type=checkbox], input[type=radio] {
input,
textarea,
select,
+.cbi-dropdown,
.uneditable-input {
display: inline-block;
width: 210px;
@@ -487,6 +487,13 @@ select,
color: #808080;
border: 1px solid #ccc;
border-radius: 3px;
+ box-sizing: border-box;
+}
+
+.cbi-dropdown {
+ min-width: 210px;
+ max-width: 400px;
+ width: auto;
}
select {
@@ -1332,6 +1339,159 @@ footer {
background-image: url('../resources/cbi/download.gif'), linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
}
+.cbi-dropdown {
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ display: inline-flex;
+ padding: 0;
+ cursor: pointer;
+ height: auto;
+ background: linear-gradient(#fff 0%, #e9e8e6 100%);
+ position: relative;
+ color: #404040;
+}
+
+.cbi-dropdown:focus {
+ outline: 2px solid #4b6e9b;
+}
+
+.cbi-dropdown > ul {
+ margin: 0 !important;
+ padding: 0;
+ list-style: none;
+ overflow-x: hidden;
+ overflow-y: auto;
+ display: flex;
+ width: 100%;
+}
+
+.cbi-dropdown > ul.preview {
+ display: none;
+}
+
+.cbi-dropdown > .open,
+.cbi-dropdown > .more {
+ flex-grow: 0;
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+ line-height: 2em;
+ padding: 0 .25em;
+}
+
+.cbi-dropdown > .more,
+.cbi-dropdown > ul > li[placeholder] {
+ color: #777;
+ font-weight: bold;
+ text-shadow: 1px 1px 0px #fff;
+ display: none;
+}
+
+.cbi-dropdown > ul > li {
+ display: none;
+ padding: .25em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex-shrink: 1;
+ flex-grow: 1;
+ align-items: center;
+ align-self: center;
+ color: #404040;
+ min-height: 20px;
+}
+
+.cbi-dropdown > ul > li .hide-open { display: initial; }
+.cbi-dropdown > ul > li .hide-close { display: none; }
+
+.cbi-dropdown > ul > li[display]:not([display="0"]) {
+ border-left: 1px solid #ccc;
+}
+
+.cbi-dropdown[empty] > ul {
+ max-width: 1px;
+}
+
+.cbi-dropdown > ul > li > form {
+ display: none;
+ margin: 0;
+ padding: 0;
+ pointer-events: none;
+}
+
+.cbi-dropdown > ul > li img {
+ vertical-align: middle;
+ margin-right: .25em;
+}
+
+.cbi-dropdown > ul > li > form > input[type="checkbox"] {
+ margin: 0;
+}
+
+.cbi-dropdown > ul > li input[type="text"] {
+ height: 20px;
+}
+
+.cbi-dropdown[open] {
+ position: relative;
+}
+
+.cbi-dropdown[open] > ul.dropdown {
+ display: block;
+ background: #f6f6f5;
+ border: 1px solid #918e8c;
+ box-shadow: 0 0 4px #918e8c;
+ position: absolute;
+ z-index: 1000;
+ max-width: none;
+ min-width: 100%;
+ width: auto;
+}
+
+.cbi-dropdown > ul > li[display],
+.cbi-dropdown[open] > ul.preview,
+.cbi-dropdown[open] > ul.dropdown > li,
+.cbi-dropdown[multiple] > ul > li > label,
+.cbi-dropdown[multiple][open] > ul.dropdown > li,
+.cbi-dropdown[multiple][more] > .more,
+.cbi-dropdown[multiple][empty] > .more {
+ flex-grow: 1;
+ display: flex;
+}
+
+.cbi-dropdown[empty] > ul > li,
+.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder],
+.cbi-dropdown[multiple][open] > ul.dropdown > li > form {
+ display: block;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li .hide-open { display: none; }
+.cbi-dropdown[open] > ul.dropdown > li .hide-close { display: initial; }
+
+.cbi-dropdown[open] > ul.dropdown > li {
+ border-bottom: 1px solid #ccc;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li[selected] {
+ background: #b0d0f0;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li.focus {
+ background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%);
+}
+
+.cbi-dropdown[open] > ul.dropdown > li:last-child {
+ margin-bottom: 0;
+ border-bottom: none;
+}
+
+.cbi-dropdown[disabled] {
+ pointer-events: none;
+ opacity: .6;
+}
+
.btn.active, .btn:active {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
}
@@ -1423,7 +1583,7 @@ button.btn::-moz-focus-inner, input[type=submit].btn::-moz-focus-inner {
opacity: 0.4;
}
-.alert-message, .errorbox {
+.alert-message {
position: relative;
padding: 7px 15px;
margin-bottom: 18px;
@@ -1646,7 +1806,6 @@ table table td,
background-color: #FFFFFF;
border: 1px solid #CCCCCC;
padding: 2px;
- margin-left: 2px;
background-image: linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
border-radius: 4px;
@@ -1712,7 +1871,7 @@ table table td,
.zonebadge > em,
.zonebadge > strong {
- margin: 5px;
+ margin: 0 2px;
display: inline-block;
}
@@ -1720,6 +1879,10 @@ table table td,
width: 6em;
}
+.zonebadge > .ifacebadge {
+ margin-left: 2px;
+}
+
.zonebadge-empty {
border: 1px dashed #AAAAAA;
color: #AAAAAA;
diff --git a/themes/luci-theme-material/htdocs/luci-static/material/css/style.css b/themes/luci-theme-material/htdocs/luci-static/material/css/style.css
index a3b22ccf8..a9585cf40 100755
--- a/themes/luci-theme-material/htdocs/luci-static/material/css/style.css
+++ b/themes/luci-theme-material/htdocs/luci-static/material/css/style.css
@@ -107,7 +107,8 @@ select {
}
select,
-input {
+input,
+.cbi-dropdown {
background-color: transparent;
color: rgba(0, 0, 0, .87);
border: none;
@@ -157,7 +158,7 @@ header {
transition: box-shadow .2s;
float: left;
position: fixed;
- z-index: 101;
+ z-index: 2000;
}
footer {
@@ -452,11 +453,7 @@ fieldset {
font-style: normal;
line-height: 1;
font-family: inherit;
-
min-width: inherit;
- overflow-x: auto;
- overflow-y: hidden;
-
border-radius: 0;
background-color: #FFF;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .16), 0 0 2px 0 rgba(0, 0, 0, .12);
@@ -626,6 +623,7 @@ td > table > tbody > tr > td,
box-shadow: none;
}
+.btn + .btn,
form.inline + form.inline,
.cbi-button + .cbi-button {
margin-left: 0.6rem;
@@ -804,6 +802,172 @@ form.inline + form.inline,
font-size: small;
}
+
+.cbi-dropdown {
+ display: inline-flex;
+ cursor: pointer;
+ position: relative;
+ padding: 0;
+ height: auto;
+}
+
+.cbi-dropdown:focus {
+ outline: 2px solid #4b6e9b;
+}
+
+.cbi-dropdown > ul {
+ margin: 0 !important;
+ padding: 0;
+ list-style: none;
+ overflow-x: hidden;
+ overflow-y: auto;
+ display: flex;
+ width: 100%;
+}
+
+.cbi-dropdown > ul.preview {
+ display: none;
+}
+
+.cbi-dropdown > .open {
+ border: 2px outset #eee;
+ flex-basis: 15px;
+ background: #eee;
+}
+
+.cbi-dropdown > .open,
+.cbi-dropdown > .more {
+ flex-grow: 0;
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+ line-height: 2em;
+ padding: 0 .25em;
+}
+
+.cbi-dropdown > .more,
+.cbi-dropdown > ul > li[placeholder] {
+ color: #777;
+ font-weight: bold;
+ text-shadow: 1px 1px 0px #fff;
+ display: none;
+}
+
+.cbi-dropdown > ul > li {
+ display: none;
+ padding: .25em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex-shrink: 1;
+ flex-grow: 1;
+ align-items: center;
+ align-self: center;
+ min-height: 20px;
+}
+
+.cbi-dropdown > ul > li .hide-open { display: initial; }
+.cbi-dropdown > ul > li .hide-close { display: none; }
+
+.cbi-dropdown > ul > li[display]:not([display="0"]) {
+ border-left: 1px solid #ccc;
+}
+
+.cbi-dropdown[empty] > ul {
+ max-width: 1px;
+}
+
+.cbi-dropdown > ul > li > form {
+ display: none;
+ margin: 0;
+ padding: 0;
+ pointer-events: none;
+}
+
+.cbi-dropdown > ul > li img {
+ vertical-align: middle;
+ margin-right: .25em;
+}
+
+.cbi-dropdown > ul > li > form > input[type="checkbox"] {
+ margin: 0;
+ height: auto;
+}
+
+.cbi-dropdown > ul > li input[type="text"] {
+ height: 20px;
+}
+
+.cbi-dropdown[open] {
+ position: relative;
+}
+
+.cbi-dropdown[open] > ul.dropdown {
+ display: block;
+ background: #f6f6f5;
+ border: 1px solid #918e8c;
+ box-shadow: 0 0 4px #918e8c;
+ position: absolute;
+ z-index: 1000;
+ max-width: none;
+ min-width: 100%;
+ width: auto;
+}
+
+.cbi-dropdown > ul > li[display],
+.cbi-dropdown[open] > ul.preview,
+.cbi-dropdown[open] > ul.dropdown > li,
+.cbi-dropdown[multiple] > ul > li > label,
+.cbi-dropdown[multiple][open] > ul.dropdown > li,
+.cbi-dropdown[multiple][more] > .more,
+.cbi-dropdown[multiple][empty] > .more {
+ flex-grow: 1;
+ display: flex;
+ align-items: center;
+}
+
+.cbi-dropdown[empty] > ul > li,
+.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder],
+.cbi-dropdown[multiple][open] > ul.dropdown > li > form {
+ display: block;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li .hide-open { display: none; }
+.cbi-dropdown[open] > ul.dropdown > li .hide-close { display: initial; }
+
+.cbi-dropdown[open] > ul.dropdown > li {
+ border-bottom: 1px solid #ccc;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li[selected] {
+ background: #b0d0f0;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li.focus {
+ background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%);
+}
+
+.cbi-dropdown[open] > ul.dropdown > li:last-child {
+ margin-bottom: 0;
+ border-bottom: none;
+}
+
+.cbi-dropdown[disabled] {
+ pointer-events: none;
+ opacity: .6;
+}
+
+.cbi-dropdown .zonebadge {
+ width: 100%;
+}
+
+.cbi-dropdown[open] .zonebadge {
+ width: auto;
+}
+
+
/* luci */
.hidden {
@@ -839,17 +1003,20 @@ form.inline + form.inline,
}
/* select */
-.cbi-value-field .cbi-input-select {
+.cbi-value-field .cbi-dropdown {
min-width: 15rem;
}
+.cbi-value-field .cbi-input-select {
+ width: 15rem;
+}
+
.ifacebadge {
display: inline-flex;
border-bottom: 1px solid #CCCCCC;
padding: 0.5rem 1rem;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ background: #fff;
}
td > .ifacebadge,
@@ -858,12 +1025,17 @@ td > .ifacebadge,
font-size: 0.9rem;
}
+.ifacebadge > em,
.ifacebadge > img {
- float: right;
- margin: 0 0.3rem;
+ display: inline-block;
+ margin: 0 .2rem;
align-self: start;
}
+.ifacebadge > img + img {
+ margin: 0 .2rem 0 0;
+}
+
.network-status-table {
display: flex;
flex-wrap: wrap;
@@ -1038,8 +1210,8 @@ td > .ifacebadge,
}
.zonebadge > .ifacebadge {
- padding: 0.2rem 1rem;
- margin: 0.3rem;
+ padding: .2rem .3rem;
+ margin: 0.1rem 0.2rem;
border: 1px solid #6C6C6C;
}
@@ -1049,6 +1221,12 @@ td > .ifacebadge,
margin-top: 0.3rem;
}
+.zonebadge > em,
+.zonebadge > strong {
+ margin: 0 0.2rem;
+ display: inline-block;
+}
+
.cbi-value-field .cbi-input-checkbox,
.cbi-value-field .cbi-input-radio {
margin-top: 0.5rem;
@@ -1073,10 +1251,14 @@ td > .ifacebadge,
margin-top: -0.5rem;
}
-.cbi-section-table-row > .cbi-value-field .cbi-input-select {
+.cbi-section-table-row > .cbi-value-field .cbi-dropdown {
min-width: 7rem;
}
+.cbi-section-table-row > .cbi-value-field .cbi-input-select {
+ width: 7rem;
+}
+
.cbi-section-create > .cbi-button-add {
margin: 0.5rem;
}
@@ -1607,8 +1789,6 @@ body.lang_pl.node-main-login .cbi-value-title {
line-height: 1;
font-family: inherit;
min-width: inherit;
- overflow-x: auto;
- overflow-y: hidden;
border-radius: 0;
background-color: #FFF;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .16), 0 0 2px 0 rgba(0, 0, 0, .12);
@@ -1627,33 +1807,36 @@ body.lang_pl.node-main-login .cbi-value-title {
@media screen and (min-width: 992px) {
.cbi-value input[type="password"],
- .cbi-value input[type="text"] {
- min-width: 20rem;
+ .cbi-value input[type="text"],
+ .cbi-value-field .cbi-input-select {
+ width: 20rem;
}
- .cbi-value-field .cbi-input-select {
+ .cbi-value-field .cbi-dropdown {
min-width: 20rem;
}
}
@media screen and (min-width: 1280px) {
.cbi-value input[type="password"],
- .cbi-value input[type="text"] {
- min-width: 22rem;
+ .cbi-value input[type="text"],
+ .cbi-value-field .cbi-input-select {
+ width: 22rem;
}
- .cbi-value-field .cbi-input-select {
+ .cbi-value-field .cbi-dropdown {
min-width: 22rem;
}
}
@media screen and (min-width: 1600px) {
.cbi-value input[type="password"],
- .cbi-value input[type="text"] {
- min-width: 25rem;
+ .cbi-value input[type="text"],
+ .cbi-value-field .cbi-input-select {
+ width: 25rem;
}
- .cbi-value-field .cbi-input-select {
+ .cbi-value-field .cbi-dropdown {
min-width: 25rem;
}
}
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 8b359d475..1d5ac8ab2 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
@@ -27,6 +27,7 @@ body {
* {
margin: 0;
padding: 0;
+ box-sizing: border-box;
}
.table { display: table; }
@@ -456,13 +457,20 @@ select:hover {
color: #000000;
}
+input[type=text],
+input[type=password] {
+ padding: 1px 3px;
+}
+
select,
input[type=text],
input[type=password] {
+ font-size: inherit;
width: 20em;
}
.td select,
+.td .cbi-dropdown,
.td input[type=text],
.td input[type=password] {
width: 99%;
@@ -773,6 +781,7 @@ div.cbi-section-create {
vertical-align: top;
}
+div.cbi-section-create .btn,
div.cbi-section-create .cbi-button {
margin: 0.25em;
}
@@ -844,13 +853,6 @@ div.cbi-section-remove {
vertical-align: bottom;
}
-div.cbi-error {
- font-size: 95%;
- font-weight: bold;
- color: #ff0000;
- background-color: #ffffff;
-}
-
.td.cbi-value-error {
border-color: red;
}
@@ -926,6 +928,169 @@ div.cbi-tab-descr {
padding: 0.5em 0.5em 0.5em 2em;
}
+
+.cbi-dropdown {
+ border: 1px inset #000;
+ display: inline-flex;
+ cursor: pointer;
+ background: #eee;
+ position: relative;
+ padding: 0;
+ color: #000;
+ min-width: 20em;
+}
+
+.cbi-dropdown:hover {
+ background: #fff;
+}
+
+.cbi-dropdown:focus {
+ outline: 2px solid #4b6e9b;
+}
+
+.cbi-dropdown > ul {
+ margin: 0 !important;
+ padding: 0;
+ list-style: none;
+ overflow-x: hidden;
+ overflow-y: auto;
+ display: flex;
+ width: 100%;
+}
+
+.cbi-dropdown > ul.preview {
+ display: none;
+}
+
+.cbi-dropdown > .open {
+ border: 2px outset #eee;
+ flex-basis: 15px;
+}
+
+.cbi-dropdown > .open,
+.cbi-dropdown > .more {
+ flex-grow: 0;
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+ line-height: 2em;
+ padding: 0 .25em;
+}
+
+.cbi-dropdown > .more,
+.cbi-dropdown > ul > li[placeholder] {
+ color: #777;
+ font-weight: bold;
+ text-shadow: 1px 1px 0px #fff;
+ display: none;
+}
+
+.cbi-dropdown > ul > li {
+ display: none;
+ padding: .25em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex-shrink: 1;
+ flex-grow: 1;
+ align-items: center;
+ align-self: center;
+ min-height: 20px;
+}
+
+.cbi-dropdown > ul > li .hide-open { display: initial; }
+.cbi-dropdown > ul > li .hide-close { display: none; }
+
+.cbi-dropdown > ul > li[display]:not([display="0"]) {
+ border-left: 1px solid #ccc;
+}
+
+.cbi-dropdown[empty] > ul {
+ max-width: 1px;
+}
+
+.cbi-dropdown > ul > li > form {
+ display: none;
+ margin: 0;
+ padding: 0;
+ pointer-events: none;
+}
+
+.cbi-dropdown > ul > li img {
+ vertical-align: middle;
+ margin-right: .25em;
+}
+
+.cbi-dropdown > ul > li > form > input[type="checkbox"] {
+ margin: 0;
+}
+
+.cbi-dropdown > ul > li input[type="text"] {
+ height: 20px;
+}
+
+.cbi-dropdown[open] {
+ position: relative;
+}
+
+.cbi-dropdown[open] > ul.dropdown {
+ display: block;
+ background: #f6f6f5;
+ border: 1px solid #918e8c;
+ box-shadow: 0 0 4px #918e8c;
+ position: absolute;
+ z-index: 1000;
+ max-width: none;
+ min-width: 100%;
+ width: auto;
+}
+
+.cbi-dropdown > ul > li[display],
+.cbi-dropdown[open] > ul.preview,
+.cbi-dropdown[open] > ul.dropdown > li,
+.cbi-dropdown[multiple] > ul > li > label,
+.cbi-dropdown[multiple][open] > ul.dropdown > li,
+.cbi-dropdown[multiple][more] > .more,
+.cbi-dropdown[multiple][empty] > .more {
+ flex-grow: 1;
+ display: flex;
+ align-items: center;
+}
+
+.cbi-dropdown[empty] > ul > li,
+.cbi-dropdown[optional][open] > ul.dropdown > li[placeholder],
+.cbi-dropdown[multiple][open] > ul.dropdown > li > form {
+ display: block;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li .hide-open { display: none; }
+.cbi-dropdown[open] > ul.dropdown > li .hide-close { display: initial; }
+
+.cbi-dropdown[open] > ul.dropdown > li {
+ border-bottom: 1px solid #ccc;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li[selected] {
+ background: #b0d0f0;
+}
+
+.cbi-dropdown[open] > ul.dropdown > li.focus {
+ background: linear-gradient(90deg, #a3c2e8 0%, #84aad9 100%);
+}
+
+.cbi-dropdown[open] > ul.dropdown > li:last-child {
+ margin-bottom: 0;
+ border-bottom: none;
+}
+
+.cbi-dropdown[disabled] {
+ pointer-events: none;
+ opacity: .6;
+}
+
+
.left {
text-align: left !important;
}
@@ -985,9 +1150,16 @@ div.cbi-tab-descr {
background: #90c0e0;
}
-.ifacebadge > img {
+.ifacebadge, .zonebadge {
+ align-items: center;
+}
+
+.ifacebadge > img,
+.ifacebadge > em {
margin-right: 5px;
align-self: start;
+ display: inline-block;
+ height: 16px;
}
.ifacebadge-active {
@@ -1021,7 +1193,7 @@ div.cbi-tab-descr {
.network-status-table .ifacebox-body {
display: flex;
flex-direction: column;
- height: 100%;
+ flex: 1 0;
}
.network-status-table .ifacebox-body > span {
@@ -1047,12 +1219,12 @@ div.cbi-tab-descr {
display: inline-block;
white-space: nowrap;
cursor: pointer;
+ border-radius: 3px;
}
-.zonebadge em,
-.zonebadge strong {
+.zonebadge > em,
+.zonebadge > strong {
margin: 3px;
- display: inline-block;
}
.zonebadge input {
@@ -1060,6 +1232,18 @@ div.cbi-tab-descr {
height: 1.5em;
}
+.zonebadge .ifacebadge,
+.cbi-dropdown .ifacebadge {
+ margin: 0 .125em;
+}
+
+.zonebadge .ifacebadge img,
+.zonebadge .ifacebadge em,
+.cbi-dropdown .ifacebadge img,
+.cbi-dropdown .ifacebadge em {
+ margin: 0 1px;
+}
+
.zonebadge-empty {
border: 1px dashed #AAAAAA;
color: #AAAAAA;