diff options
Diffstat (limited to 'modules/luci-base/htdocs/luci-static')
6 files changed, 253 insertions, 135 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/form.js b/modules/luci-base/htdocs/luci-static/resources/form.js index 58a31dddb2..52506d30e8 100644 --- a/modules/luci-base/htdocs/luci-static/resources/form.js +++ b/modules/luci-base/htdocs/luci-static/resources/form.js @@ -1862,6 +1862,9 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa if (cval == null) cval = this.default; + if (Array.isArray(cval)) + cval = cval.join(' '); + return (cval != null) ? '%h'.format(cval) : null; }, @@ -2032,10 +2035,32 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * The configuration section ID */ remove: function(section_id) { - return this.map.data.unset( - this.uciconfig || this.section.uciconfig || this.map.config, - this.ucisection || section_id, - this.ucioption || this.option); + var this_cfg = this.uciconfig || this.section.uciconfig || this.map.config, + this_sid = this.ucisection || section_id, + this_opt = this.ucioption || this.option; + + for (var i = 0; i < this.section.children.length; i++) { + var sibling = this.section.children[i]; + + if (sibling === this || sibling.ucioption == null) + continue; + + var sibling_cfg = sibling.uciconfig || sibling.section.uciconfig || sibling.map.config, + sibling_sid = sibling.ucisection || section_id, + sibling_opt = sibling.ucioption || sibling.option; + + if (this_cfg != sibling_cfg || this_sid != sibling_sid || this_opt != sibling_opt) + continue; + + if (!sibling.isActive(section_id)) + continue; + + /* found another active option aliasing the same uci option name, + * so we can't remove the value */ + return; + } + + this.map.data.unset(this_cfg, this_sid, this_opt); } }); @@ -3929,11 +3954,21 @@ var CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ * @default null */ + /** + * Render the UCI option value as hidden using the HTML display: none style property. + * + * By default, the value is displayed + * + * @name LuCI.form.DummyValue.prototype#hidden + * @type boolean + * @default null + */ + /** @private */ renderWidget: function(section_id, option_index, cfgvalue) { var value = (cfgvalue != null) ? cfgvalue : this.default, hiddenEl = new ui.Hiddenfield(value, { id: this.cbid(section_id) }), - outputEl = E('div'); + outputEl = E('div', { 'style': this.hidden ? 'display:none' : null }); if (this.href && !((this.readonly != null) ? this.readonly : this.map.readonly)) outputEl.appendChild(E('a', { 'href': this.href })); diff --git a/modules/luci-base/htdocs/luci-static/resources/network.js b/modules/luci-base/htdocs/luci-static/resources/network.js index 33b48b259c..17dd055e25 100644 --- a/modules/luci-base/htdocs/luci-static/resources/network.js +++ b/modules/luci-base/htdocs/luci-static/resources/network.js @@ -101,6 +101,15 @@ var _init = null, _protocols = {}, _protospecs = {}; +function strcmp(a, b) { + if (a > b) + return 1; + else if (a < b) + return -1; + else + return 0; +} + function getProtocolHandlers(cache) { return callNetworkProtoHandlers().then(function(protos) { /* Register "none" protocol */ @@ -384,6 +393,7 @@ function initNetworkState(refresh) { name: name, rawname: name, flags: dev.flags, + link: dev.link, stats: dev.stats, macaddr: dev.mac, type: dev.type, @@ -552,7 +562,7 @@ function ifnameOf(obj) { } function networkSort(a, b) { - return a.getName() > b.getName(); + return strcmp(a.getName(), b.getName()); } function deviceSort(a, b) { @@ -563,7 +573,7 @@ function deviceSort(a, b) { if (weightA != weightB) return weightA - weightB; - return a.getName() > b.getName(); + return strcmp(a.getName(), b.getName()); } function formatWifiEncryption(enc) { @@ -1421,7 +1431,7 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ { rv.push(this.lookupWifiNetwork(wifiIfaces[i]['.name'])); rv.sort(function(a, b) { - return (a.getID() > b.getID()); + return strcmp(a.getID(), b.getID()); }); return rv; @@ -1522,12 +1532,7 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ { if (a.metric != b.metric) return (a.metric - b.metric); - if (a.interface < b.interface) - return -1; - else if (a.interface > b.interface) - return 1; - - return 0; + return strcmp(a.interface, b.interface); }); return rv; @@ -1805,7 +1810,9 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getHostnameByMACAddr: function(mac) { - return this.hosts[mac] ? this.hosts[mac].name : null; + return this.hosts[mac] + ? (this.hosts[mac].name || null) + : null; }, /** @@ -1820,7 +1827,9 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getIPAddrByMACAddr: function(mac) { - return this.hosts[mac] ? this.hosts[mac].ipv4 : null; + return this.hosts[mac] + ? (L.toArray(this.hosts[mac].ipaddrs || this.hosts[mac].ipv4)[0] || null) + : null; }, /** @@ -1835,7 +1844,9 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getIP6AddrByMACAddr: function(mac) { - return this.hosts[mac] ? this.hosts[mac].ipv6 : null; + return this.hosts[mac] + ? (L.toArray(this.hosts[mac].ip6addrs || this.hosts[mac].ipv6)[0] || null) + : null; }, /** @@ -1850,9 +1861,17 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getHostnameByIPAddr: function(ipaddr) { - for (var mac in this.hosts) - if (this.hosts[mac].ipv4 == ipaddr && this.hosts[mac].name != null) - return this.hosts[mac].name; + for (var mac in this.hosts) { + if (this.hosts[mac].name == null) + continue; + + var addrs = L.toArray(this.hosts[mac].ipaddrs || this.hosts[mac].ipv4); + + for (var i = 0; i < addrs.length; i++) + if (addrs[i] == ipaddr) + return this.hosts[mac].name; + } + return null; }, @@ -1868,16 +1887,21 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getMACAddrByIPAddr: function(ipaddr) { - for (var mac in this.hosts) - if (this.hosts[mac].ipv4 == ipaddr) - return mac; + for (var mac in this.hosts) { + var addrs = L.toArray(this.hosts[mac].ipaddrs || this.hosts[mac].ipv4); + + for (var i = 0; i < addrs.length; i++) + if (addrs[i] == ipaddr) + return mac; + } + return null; }, /** * Lookup the hostname associated with the given IPv6 address. * - * @param {string} ipaddr + * @param {string} ip6addr * The IPv6 address to lookup. * * @returns {null|string} @@ -1886,16 +1910,24 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getHostnameByIP6Addr: function(ip6addr) { - for (var mac in this.hosts) - if (this.hosts[mac].ipv6 == ip6addr && this.hosts[mac].name != null) - return this.hosts[mac].name; + for (var mac in this.hosts) { + if (this.hosts[mac].name == null) + continue; + + var addrs = L.toArray(this.hosts[mac].ip6addrs || this.hosts[mac].ipv6); + + for (var i = 0; i < addrs.length; i++) + if (addrs[i] == ip6addr) + return this.hosts[mac].name; + } + return null; }, /** * Lookup the MAC address associated with the given IPv6 address. * - * @param {string} ipaddr + * @param {string} ip6addr * The IPv6 address to lookup. * * @returns {null|string} @@ -1904,9 +1936,14 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { * the corresponding host. */ getMACAddrByIP6Addr: function(ip6addr) { - for (var mac in this.hosts) - if (this.hosts[mac].ipv6 == ip6addr) - return mac; + for (var mac in this.hosts) { + var addrs = L.toArray(this.hosts[mac].ip6addrs || this.hosts[mac].ipv6); + + for (var i = 0; i < addrs.length; i++) + if (addrs[i] == ip6addr) + return mac; + } + return null; }, @@ -1933,14 +1970,18 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ { */ getMACHints: function(preferIp6) { var rv = []; + for (var mac in this.hosts) { var hint = this.hosts[mac].name || - this.hosts[mac][preferIp6 ? 'ipv6' : 'ipv4'] || - this.hosts[mac][preferIp6 ? 'ipv4' : 'ipv6']; + L.toArray(this.hosts[mac][preferIp6 ? 'ip6addrs' : 'ipaddrs'] || this.hosts[mac][preferIp6 ? 'ipv6' : 'ipv4'])[0] || + L.toArray(this.hosts[mac][preferIp6 ? 'ipaddrs' : 'ip6addrs'] || this.hosts[mac][preferIp6 ? 'ipv4' : 'ipv6'])[0]; rv.push([mac, hint]); } - return rv.sort(function(a, b) { return a[0] > b[0] }); + + return rv.sort(function(a, b) { + return strcmp(a[0], b[0]); + }); } }); @@ -2496,14 +2537,14 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { * * Alias interfaces are interfaces layering on top of another interface * and are denoted by a special `@interfacename` notation in the - * underlying `ifname` option. + * underlying `device` option. * * @returns {null|string} * Returns the name of the parent interface if this logical interface * is an alias or `null` if it is not an alias interface. */ isAlias: function() { - var ifnames = L.toArray(uci.get('network', this.sid, 'ifname')), + var ifnames = L.toArray(uci.get('network', this.sid, 'device')), parent = null; for (var i = 0; i < ifnames.length; i++) @@ -2527,9 +2568,9 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { return false; var empty = true, - ifname = this._get('ifname'); + device = this._get('device'); - if (ifname != null && ifname.match(/\S+/)) + if (device != null && device.match(/\S+/)) empty = false; if (empty == true && getWifiNetidBySid(this.sid) != null) @@ -2561,18 +2602,18 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { * argument was invalid, if the device was already part of the logical * interface or if the logical interface is virtual. */ - addDevice: function(ifname) { - ifname = ifnameOf(ifname); + addDevice: function(device) { + device = ifnameOf(device); - if (ifname == null || this.isFloating()) + if (device == null || this.isFloating()) return false; - var wif = getWifiSidByIfname(ifname); + var wif = getWifiSidByIfname(device); if (wif != null) return appendValue('wireless', wif, 'network', this.sid); - return appendValue('network', this.sid, 'ifname', ifname); + return appendValue('network', this.sid, 'device', device); }, /** @@ -2588,20 +2629,20 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { * argument was invalid, if the device was already part of the logical * interface or if the logical interface is virtual. */ - deleteDevice: function(ifname) { + deleteDevice: function(device) { var rv = false; - ifname = ifnameOf(ifname); + device = ifnameOf(device); - if (ifname == null || this.isFloating()) + if (device == null || this.isFloating()) return false; - var wif = getWifiSidByIfname(ifname); + var wif = getWifiSidByIfname(device); if (wif != null) rv = removeValue('wireless', wif, 'network', this.sid); - if (removeValue('network', this.sid, 'ifname', ifname)) + if (removeValue('network', this.sid, 'device', device)) rv = true; return rv; @@ -2627,7 +2668,7 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { return new Device(ifname, this); } else { - var ifnames = L.toArray(uci.get('network', this.sid, 'ifname')); + var ifnames = L.toArray(uci.get('network', this.sid, 'device')); for (var i = 0; i < ifnames.length; i++) { var m = ifnames[i].match(/^([^:/]+)/); @@ -2682,13 +2723,10 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { if (!this.isBridge() && !(this.isVirtual() && !this.isFloating())) return null; - var ifnames = L.toArray(uci.get('network', this.sid, 'ifname')); + var device = uci.get('network', this.sid, 'device'); - for (var i = 0; i < ifnames.length; i++) { - if (ifnames[i].charAt(0) == '@') - continue; - - var m = ifnames[i].match(/^([^:/]+)/); + if (device && device.charAt(0) != '@') { + var m = device.match(/^([^:/]+)/); if (m != null) rv.push(Network.prototype.instantiateDevice(m[1], this)); } @@ -2730,25 +2768,24 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { * Returns `true` when this logical interface contains the given network * device or `false` if not. */ - containsDevice: function(ifname) { - ifname = ifnameOf(ifname); + containsDevice: function(device) { + device = ifnameOf(device); - if (ifname == null) + if (device == null) return false; - else if (this.isVirtual() && '%s-%s'.format(this.getProtocol(), this.sid) == ifname) + else if (this.isVirtual() && '%s-%s'.format(this.getProtocol(), this.sid) == device) return true; - else if (this.isBridge() && 'br-%s'.format(this.sid) == ifname) + else if (this.isBridge() && 'br-%s'.format(this.sid) == device) return true; - var ifnames = L.toArray(uci.get('network', this.sid, 'ifname')); - - for (var i = 0; i < ifnames.length; i++) { - var m = ifnames[i].match(/^([^:/]+)/); - if (m != null && m[1] == ifname) + var name = uci.get('network', this.sid, 'device'); + if (name) { + var m = name.match(/^([^:/]+)/); + if (m != null && m[1] == device) return true; } - var wif = getWifiSidByIfname(ifname); + var wif = getWifiSidByIfname(device); if (wif != null) { var networks = L.toArray(uci.get('wireless', wif, 'network')); @@ -2791,19 +2828,19 @@ Protocol = baseclass.extend(/** @lends LuCI.network.Protocol.prototype */ { * device and allows querying device details such as packet statistics or MTU. */ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { - __init__: function(ifname, network) { - var wif = getWifiSidByIfname(ifname); + __init__: function(device, network) { + var wif = getWifiSidByIfname(device); if (wif != null) { var res = getWifiStateBySid(wif) || [], netid = getWifiNetidBySid(wif) || []; - this.wif = new WifiNetwork(wif, res[0], res[1], netid[0], res[2], { ifname: ifname }); - this.ifname = this.wif.getIfname(); + this.wif = new WifiNetwork(wif, res[0], res[1], netid[0], res[2], { ifname: device }); + this.device = this.wif.getIfname(); } - this.ifname = this.ifname || ifname; - this.dev = Object.assign({}, _state.netdevs[this.ifname]); + this.device = this.device || device; + this.dev = Object.assign({}, _state.netdevs[this.device]); this.network = network; }, @@ -2826,7 +2863,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { * Returns the name of the device, e.g. `eth0` or `wlan0`. */ getName: function() { - return (this.wif != null ? this.wif.getIfname() : this.ifname); + return (this.wif != null ? this.wif.getIfname() : this.device); }, /** @@ -2887,17 +2924,17 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { * - `ethernet` for all other device types */ getType: function() { - if (this.ifname != null && this.ifname.charAt(0) == '@') + if (this.device != null && this.device.charAt(0) == '@') return 'alias'; - else if (this.dev.devtype == 'wlan' || this.wif != null || isWifiIfname(this.ifname)) + else if (this.dev.devtype == 'wlan' || this.wif != null || isWifiIfname(this.device)) return 'wifi'; - else if (this.dev.devtype == 'bridge' || _state.isBridge[this.ifname]) + else if (this.dev.devtype == 'bridge' || _state.isBridge[this.device]) return 'bridge'; - else if (_state.isTunnel[this.ifname]) + else if (_state.isTunnel[this.device]) return 'tunnel'; - else if (this.dev.devtype == 'vlan' || this.ifname.indexOf('.') > -1) + else if (this.dev.devtype == 'vlan' || this.device.indexOf('.') > -1) return 'vlan'; - else if (this.dev.devtype == 'dsa' || _state.isSwitch[this.ifname]) + else if (this.dev.devtype == 'dsa' || _state.isSwitch[this.device]) return 'switch'; else return 'ethernet'; @@ -2914,7 +2951,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { if (this.wif != null) return this.wif.getShortName(); - return this.ifname; + return this.device; }, /** @@ -2954,11 +2991,11 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { return _('Bridge'); case 'switch': - return (_state.netdevs[this.ifname] && _state.netdevs[this.ifname].devtype == 'dsa') + return (_state.netdevs[this.device] && _state.netdevs[this.device].devtype == 'dsa') ? _('Switch port') : _('Ethernet Switch'); case 'vlan': - return (_state.isSwitch[this.ifname] ? _('Switch VLAN') : _('Software VLAN')); + return (_state.isSwitch[this.device] ? _('Switch VLAN') : _('Software VLAN')); case 'tunnel': return _('Tunnel Interface'); @@ -2977,7 +3014,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { * a Linux bridge. */ getPorts: function() { - var br = _state.bridges[this.ifname], + var br = _state.bridges[this.device], rv = []; if (br == null || !Array.isArray(br.ifnames)) @@ -2999,7 +3036,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { * device is not a Linux bridge. */ getBridgeID: function() { - var br = _state.bridges[this.ifname]; + var br = _state.bridges[this.device]; return (br != null ? br.id : null); }, @@ -3011,7 +3048,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { * enabled, else `false`. */ getBridgeSTP: function() { - var br = _state.bridges[this.ifname]; + var br = _state.bridges[this.device]; return (br != null ? !!br.stp : false); }, @@ -3098,6 +3135,47 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { }, /** + * Get the carrier state of the network device. + * + * @returns {boolean} + * Returns true if the device has a carrier, e.g. when a cable is + * inserted into an ethernet port of false if there is none. + */ + getCarrier: function() { + var link = this._devstate('link'); + return (link != null ? link.carrier || false : false); + }, + + /** + * Get the current link speed of the network device if available. + * + * @returns {number|null} + * Returns the current speed of the network device in Mbps. If the + * device supports no ethernet speed levels, null is returned. + * If the device supports ethernet speeds but has no carrier, -1 is + * returned. + */ + getSpeed: function() { + var link = this._devstate('link'); + return (link != null ? link.speed || null : null); + }, + + /** + * Get the current duplex mode of the network device if available. + * + * @returns {string|null} + * Returns the current duplex mode of the network device. Returns + * either "full" or "half" if the device supports duplex modes or + * null if the duplex mode is unknown or unsupported. + */ + getDuplex: function() { + var link = this._devstate('link'), + duplex = link ? link.duplex : null; + + return (duplex != 'unknown') ? duplex : null; + }, + + /** * Get the primary logical interface this device is assigned to. * * @returns {null|LuCI.network.Protocol} @@ -3123,7 +3201,7 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ { var networks = enumerateNetworks.apply(L.network); for (var i = 0; i < networks.length; i++) - if (networks[i].containsDevice(this.ifname) || networks[i].getIfname() == this.ifname) + if (networks[i].containsDevice(this.device) || networks[i].getIfname() == this.device) this.networks.push(networks[i]); this.networks.sort(networkSort); @@ -3267,6 +3345,7 @@ WifiDevice = baseclass.extend(/** @lends LuCI.network.WifiDevice.prototype */ { * - `g` - Legacy 802.11g mode, 2.4 GHz, up to 54 Mbit/s * - `n` - IEEE 802.11n mode, 2.4 or 5 GHz, up to 600 Mbit/s * - `ac` - IEEE 802.11ac mode, 5 GHz, up to 6770 Mbit/s + * - `ax` - IEEE 802.11ax mode, 2.4 or 5 GHz */ getHWModes: function() { var hwmodes = this.ubus('dev', 'iwinfo', 'hwmodes'); @@ -3288,6 +3367,10 @@ WifiDevice = baseclass.extend(/** @lends LuCI.network.WifiDevice.prototype */ { * - `VHT40` - applicable to IEEE 802.11ac, 40 MHz wide channels * - `VHT80` - applicable to IEEE 802.11ac, 80 MHz wide channels * - `VHT160` - applicable to IEEE 802.11ac, 160 MHz wide channels + * - `HE20` - applicable to IEEE 802.11ax, 20 MHz wide channels + * - `HE40` - applicable to IEEE 802.11ax, 40 MHz wide channels + * - `HE80` - applicable to IEEE 802.11ax, 80 MHz wide channels + * - `HE160` - applicable to IEEE 802.11ax, 160 MHz wide channels */ getHTModes: function() { var htmodes = this.ubus('dev', 'iwinfo', 'htmodes'); @@ -3311,7 +3394,10 @@ WifiDevice = baseclass.extend(/** @lends LuCI.network.WifiDevice.prototype */ { modestr = ''; hwmodes.sort(function(a, b) { - return (a.length != b.length ? a.length > b.length : a > b); + if (a.length != b.length) + return a.length - b.length; + + return strcmp(a, b); }); modestr = hwmodes.join(''); @@ -3982,6 +4068,17 @@ WifiNetwork = baseclass.extend(/** @lends LuCI.network.WifiNetwork.prototype */ * @property {number} [nss] * Specifies the number of spatial streams used by the transmission. * Only applicable to VHT rates. + * + * @property {boolean} [he] + * Specifies whether this rate is an HE (IEEE 802.11ax) rate. + * + * @property {number} [he_gi] + * Specifies whether the guard interval used for the transmission. + * Only applicable to HE rates. + * + * @property {number} [he_dcm] + * Specifies whether dual concurrent modulation is used for the transmission. + * Only applicable to HE rates. */ /** diff --git a/modules/luci-base/htdocs/luci-static/resources/protocol/dhcp.js b/modules/luci-base/htdocs/luci-static/resources/protocol/dhcp.js index 9a63a107cf..71adc235ca 100644 --- a/modules/luci-base/htdocs/luci-static/resources/protocol/dhcp.js +++ b/modules/luci-base/htdocs/luci-static/resources/protocol/dhcp.js @@ -17,7 +17,7 @@ return network.registerProtocol('dhcp', { }, renderFormOptions: function(s) { - var dev = this.getL2Device() || this.getDevice(), o; + var o; o = s.taboption('general', form.Value, 'hostname', _('Hostname to send when requesting DHCP')); o.default = ''; @@ -38,13 +38,5 @@ return network.registerProtocol('dhcp', { o.datatype = 'hexstring'; s.taboption('advanced', form.Value, 'vendorid', _('Vendor Class to send when requesting DHCP')); - - o = s.taboption('advanced', form.Value, 'macaddr', _('Override MAC address')); - o.datatype = 'macaddr'; - o.placeholder = dev ? (dev.getMAC() || '') : ''; - - o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU')); - o.placeholder = dev ? (dev.getMTU() || '1500') : '1500'; - o.datatype = 'max(9200)'; } }); diff --git a/modules/luci-base/htdocs/luci-static/resources/protocol/static.js b/modules/luci-base/htdocs/luci-static/resources/protocol/static.js index 82f499d6b9..42ebcefba4 100644 --- a/modules/luci-base/htdocs/luci-static/resources/protocol/static.js +++ b/modules/luci-base/htdocs/luci-static/resources/protocol/static.js @@ -173,7 +173,7 @@ return network.registerProtocol('static', { }, renderFormOptions: function(s) { - var dev = this.getL2Device() || this.getDevice(), o; + var o; s.taboption('general', this.CBIIPValue, 'ipaddr', _('IPv4 address')); s.taboption('general', this.CBINetmaskValue, 'netmask', _('IPv4 netmask')); @@ -192,13 +192,5 @@ return network.registerProtocol('static', { o = s.taboption('general', form.Value, 'ip6prefix', _('IPv6 routed prefix'), _('Public prefix routed to this device for distribution to clients.')); o.datatype = 'ip6addr'; o.depends('ip6assign', ''); - - o = s.taboption('advanced', form.Value, 'macaddr', _('Override MAC address')); - o.datatype = 'macaddr'; - o.placeholder = dev ? (dev.getMAC() || '') : ''; - - o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU')); - o.datatype = 'max(9200)'; - o.placeholder = dev ? (dev.getMTU() || '1500') : '1500'; } }); diff --git a/modules/luci-base/htdocs/luci-static/resources/ui.js b/modules/luci-base/htdocs/luci-static/resources/ui.js index 3a991be9ac..0e909b6dcc 100644 --- a/modules/luci-base/htdocs/luci-static/resources/ui.js +++ b/modules/luci-base/htdocs/luci-static/resources/ui.js @@ -1202,6 +1202,28 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ + getScrollParent: function(element) { + var parent = element, + style = getComputedStyle(element), + excludeStaticParent = (style.position === 'absolute'); + + if (style.position === 'fixed') + return document.body; + + while ((parent = parent.parentElement) != null) { + style = getComputedStyle(parent); + + if (excludeStaticParent && style.position === 'static') + continue; + + if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)) + return parent; + } + + return document.body; + }, + + /** @private */ openDropdown: function(sb) { var st = window.getComputedStyle(sb, null), ul = sb.querySelector('ul'), @@ -1209,7 +1231,8 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { fl = findParent(sb, '.cbi-value-field'), sel = ul.querySelector('[selected]'), rect = sb.getBoundingClientRect(), - items = Math.min(this.options.dropdown_items, li.length); + items = Math.min(this.options.dropdown_items, li.length), + scrollParent = this.getScrollParent(sb); document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) { s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {})); @@ -1234,29 +1257,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { ul.style.maxHeight = (vpHeight * 0.5) + 'px'; ul.style.WebkitOverflowScrolling = 'touch'; - var getScrollParent = function(element) { - var parent = element, - style = getComputedStyle(element), - excludeStaticParent = (style.position === 'absolute'); - - if (style.position === 'fixed') - return document.body; - - while ((parent = parent.parentElement) != null) { - style = getComputedStyle(parent); - - if (excludeStaticParent && style.position === 'static') - continue; - - if (/(auto|scroll)/.test(style.overflow + style.overflowY + style.overflowX)) - return parent; - } - - return document.body; - } - - var scrollParent = getScrollParent(sb), - scrollFrom = scrollParent.scrollTop, + var scrollFrom = scrollParent.scrollTop, scrollTo = scrollFrom + rect.top - vpHeight * 0.5; var scrollStep = function(timestamp) { @@ -1282,10 +1283,11 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { ul.style.top = ul.style.bottom = ''; window.requestAnimationFrame(function() { - var itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height, + var containerRect = scrollParent.getBoundingClientRect(), + itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height, fullHeight = 0, - spaceAbove = rect.top, - spaceBelow = window.innerHeight - rect.height - rect.top; + spaceAbove = rect.top - containerRect.top, + spaceBelow = containerRect.bottom - rect.bottom; for (var i = 0; i < (items == -1 ? li.length : items); i++) fullHeight += li[i].getBoundingClientRect().height; @@ -4063,7 +4065,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { E('button', { 'class': 'btn', 'click': UI.prototype.hideModal - }, [ _('Dismiss') ]), ' ', + }, [ _('Close') ]), ' ', E('button', { 'class': 'cbi-button cbi-button-positive important', 'click': L.bind(this.apply, this, true) diff --git a/modules/luci-base/htdocs/luci-static/resources/validation.js b/modules/luci-base/htdocs/luci-static/resources/validation.js index 0d2157bee0..28042ba8cd 100644 --- a/modules/luci-base/htdocs/luci-static/resources/validation.js +++ b/modules/luci-base/htdocs/luci-static/resources/validation.js @@ -361,8 +361,8 @@ var ValidatorFactory = baseclass.extend({ }, network: function() { - return this.assert(this.apply('uciname') || this.apply('host'), - _('valid UCI identifier, hostname or IP address')); + return this.assert(this.apply('uciname') || this.apply('hostname') || this.apply('ip4addr') || this.apply('ip6addr'), + _('valid UCI identifier, hostname or IP address range')); }, hostport: function(ipv4only) { |