luci-mod: js linting fixes / ES6 treatment

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
This commit is contained in:
Paul Donald
2026-02-14 04:59:49 +01:00
parent 50a8d5325d
commit 95b01600e3
27 changed files with 970 additions and 1061 deletions

View File

@@ -4,24 +4,24 @@
'require poll';
'require baseclass';
var callBatteryStatus = rpc.declare({
const callBatteryStatus = rpc.declare({
object: 'luci.battstatus',
method: 'getBatteryStatus',
expect: { '': {} }
});
var devices = {};
const devices = {};
return baseclass.extend({
__init__: function() {
__init__() {
this.updateIndicator();
poll.add(L.bind(this.updateIndicator, this), 5);
},
updateIndicator: function() {
updateIndicator() {
return callBatteryStatus().then(L.bind(function(devs) {
for (var dev in devs) {
var info = devs[dev];
for (let dev in devs) {
let info = devs[dev];
if (info.valid) {
info.status = (info.charging ? _('Charging') : _('Not Charging')) + ": " + info.percentage + "%";
info.state = "active";
@@ -44,7 +44,7 @@ return baseclass.extend({
devices[dev] = info;
}
for (var dev in devices) {
for (let dev in devices) {
if (!devs.hasOwnProperty(dev)) {
ui.hideIndicator('battery-%s'.format(dev));
delete devices[dev];

View File

@@ -2,7 +2,7 @@
// Rendering of DSL spectrum graphs showing
// US/DS SNR and US/DS bits/tone
//
// This version does depend on an ubus version that support DSL line stattiscis but
// This version does depend on an ubus version that support DSL line statistics but
// does not depend on chart.js or any other package
class DataSet {
@@ -221,7 +221,7 @@ let hLogChart = {
]
};
function drawChart (info) {
function drawChart(info) {
drawAxisX(info.config, info.config.minX, info.config.maxX, info.config.stepX, info.config.titleX);
drawAxisY(info.config, info.config.minY, info.config.maxY, info.config.stepY, info.config.titleY);
@@ -236,17 +236,10 @@ function drawChart (info) {
}
}
function drawBlocks(config, dataPoints, color, borders) {
borders.map(drawBlock, {config, dataPoints, color, borders});
}
function drawLines(config, dataPoints, color) {
let ctx = config.ctx;
let len = dataPoints.length;
let minX = config.minX;
let maxX = config.maxX;
let minY = config.minY;
let maxY = config.maxY;
ctx.strokeStyle = color;
ctx.beginPath();
@@ -292,7 +285,6 @@ function drawData(config, dataPoints, color) {
function drawLegend(config, dataSet){
let ctx = config.ctx;
let graphWidth = config.graphWidth;
let graphHeight = config.graphHeight;
ctx.font = "12px Arial";
@@ -329,7 +321,6 @@ function drawLegend(config, dataSet){
function drawAxisX(config, minValue, maxValue, step, title) {
let ctx = config.ctx;
let graphWidth = config.graphWidth;
let graphHeight = config.graphHeight;
ctx.font = "12px Arial";
ctx.textAlign = "center";
@@ -360,7 +351,6 @@ function drawAxisX(config, minValue, maxValue, step, title) {
function drawAxisY(config, minValue, maxValue, step, title) {
let ctx = config.ctx
let graphWidth = config.graphWidth;
let graphHeight = config.graphHeight;
ctx.font = "12px Arial";

View File

@@ -4,23 +4,23 @@
'require ui';
'require rpc';
var callDSLStatistics = rpc.declare({
const callDSLStatistics = rpc.declare({
object: 'dsl',
method: 'statistics',
expect: { '': {} }
});
return view.extend({
load: function() {
load() {
return Promise.all([
callDSLStatistics()
]);
},
render: function(data) {
render(data) {
window.json = data[0];
var v = E('div', {'class': 'cbi-map'}, [
const v = E('div', {'class': 'cbi-map'}, [
E('h2', {'style': "height: 40px"}, [ _('DSL line spectrum') ]),
E('div', {'class': 'cbi-map-descr'}, _('The following diagrams show graphically prepared DSL characteristics that are important for evaluating the DSL connection.')),

View File

@@ -4,7 +4,7 @@
'require poll';
'require rpc';
var callDSLMetrics = rpc.declare({
const callDSLMetrics = rpc.declare({
object: 'dsl',
method: 'metrics',
expect: { '': {} }
@@ -19,11 +19,11 @@ function format_latency(val) {
}
return view.extend({
load: function() {
load() {
return L.resolveDefault(callDSLMetrics(), {});
},
pollData: function(container) {
pollData(container) {
poll.add(L.bind(function() {
return L.resolveDefault(callDSLMetrics(), {}).then(L.bind(function(data) {
dom.content(container, this.renderContent(data));
@@ -31,7 +31,7 @@ return view.extend({
}, this));
},
formatHelper: function(format, val) {
formatHelper(format, val) {
if (val != null) {
if (format instanceof Function) {
return format(val);
@@ -44,14 +44,14 @@ return view.extend({
return '-';
},
renderSimpleTable: function(data) {
var table = E('table', { 'class': 'table' });
renderSimpleTable(data) {
const table = E('table', { 'class': 'table' });
for (var [i, item] of data.entries()) {
var label = item[0];
var val = item[1];
for (let [i, item] of data.entries()) {
const label = item[0];
const val = item[1];
var rowstyle = (i % 2 == 0) ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2';
const rowstyle = (i % 2 == 0) ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2';
table.appendChild(E('tr', { 'class': 'tr ' + rowstyle }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ label ]),
@@ -62,16 +62,16 @@ return view.extend({
return E('div', { 'class': 'cbi-section' }, table);
},
renderTable: function(data) {
var table = E('table', { 'class': 'table' });
renderTable(data) {
const table = E('table', { 'class': 'table' });
for (var [i, item] of data.entries()) {
var label = item[0];
var format = item[1];
var val1 = item[2];
var val2 = item[3];
for (let [i, item] of data.entries()) {
const label = item[0];
const format = item[1];
const val1 = item[2];
const val2 = item[3];
var rowstyle = (i % 2 == 0) ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2';
const rowstyle = (i % 2 == 0) ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2';
table.appendChild(E('tr', { 'class': 'tr ' + rowstyle }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ label ]),
@@ -83,7 +83,7 @@ return view.extend({
return E('div', { 'class': 'cbi-section' }, table);
},
renderContent: function(data) {
renderContent(data) {
return E([], [
E('h3', {}, [ _('Connection State') ]),
@@ -169,13 +169,13 @@ return view.extend({
]);
},
render: function(data) {
var v = E([], [
render(data) {
const v = E([], [
E('h2', {}, [ _('DSL stats') ]),
E('div')
]);
var container = v.lastElementChild;
const container = v.lastElementChild;
dom.content(container, this.renderContent(data));
this.pollData(container);

View File

@@ -146,10 +146,11 @@ return baseclass.extend({
},
encodeSvcParamValue(key, value) {
const seen = new Set();
let keys, port;
switch (key) {
case 'mandatory':
const seen = new Set();
const keys = value.split(',')
keys = value.split(',')
.map(k => k.trim())
.filter(k => {
if (seen.has(k)) return false; // D3 Figure 16
@@ -176,7 +177,7 @@ return baseclass.extend({
return []; // zero-length value - D3 Figure 13
case 'port': // D2 Figure 4
const port = parseInt(value, 10);
port = parseInt(value, 10);
return [(port >> 8) & 0xff, port & 0xff];
case 'ipv4hint':
@@ -311,9 +312,11 @@ return baseclass.extend({
},
decodeSvcParamValue(key, buf) {
const keys = [];
const addrs = [];
switch (key) {
case 'mandatory':
const keys = [];
for (let i = 0; i + 1 < buf.length; i += 2) {
const k = (buf[i] << 8) | buf[i + 1];
keys.push(this.svcParamKeyFromNumber(k));
@@ -351,7 +354,6 @@ return baseclass.extend({
// return Array.from(buf).map(b => b.toString(16).padStart(2, '0')).join('');
case 'ipv6hint':
const addrs = [];
for (let i = 0; i + 15 <= buf.length; i += 16) {
let addr = [];
for (let j = 0; j < 16; j += 2) {

View File

@@ -9,21 +9,11 @@
'require validation';
'require tools.widgets as widgets';
function validateAddr(section_id, value) {
if (value == '')
return true;
var ipv6 = /6$/.test(this.section.formvalue(section_id, 'mode')),
addr = ipv6 ? validation.parseIPv6(value) : validation.parseIPv4(value);
return addr ? true : (ipv6 ? _('Expecting a valid IPv6 address') : _('Expecting a valid IPv4 address'));
}
function validateQoSMap(section_id, value) {
if (value == '')
return true;
var m = value.match(/^(\d+):(\d+)$/);
const m = value.match(/^(\d+):(\d+)$/);
if (!m || +m[1] > 0xFFFFFFFF || +m[2] > 0xFFFFFFFF)
return _('Expecting two priority values separated by a colon');
@@ -32,7 +22,7 @@ function validateQoSMap(section_id, value) {
}
function deviceSectionExists(section_id, devname) {
var exists = false;
let exists = false;
uci.sections('network', 'device', function(ss) {
exists = exists || (
@@ -51,7 +41,7 @@ function isBridgePort(dev) {
if (dev.isBridgePort())
return true;
var isPort = false;
let isPort = false;
uci.sections('network', null, function(s) {
if (s['.type'] != 'interface' && s['.type'] != 'device')
@@ -65,8 +55,8 @@ function isBridgePort(dev) {
}
function updateDevBadge(node, dev) {
var type = dev.getType(),
up = dev.getCarrier();
const type = dev.getType();
const up = dev.getCarrier();
dom.content(node, [
E('img', {
@@ -88,10 +78,10 @@ function renderDevBadge(dev) {
}
function updatePortStatus(node, dev) {
var carrier = dev.getCarrier(),
duplex = dev.getDuplex(),
speed = dev.getSpeed(),
desc, title;
const carrier = dev.getCarrier();
const duplex = dev.getDuplex();
const speed = dev.getSpeed();
let desc, title;
if (carrier && speed > 0 && duplex != null) {
desc = '%d%s'.format(speed, duplex == 'full' ? 'FD' : 'HD');
@@ -130,7 +120,7 @@ function renderPortStatus(dev) {
function updatePlaceholders(opt, section_id) {
var dev = network.instantiateDevice(opt.getUIElement(section_id).getValue());
for (var i = 0, co; (co = opt.section.children[i]) != null; i++) {
for (let i = 0, co; (co = opt.section.children[i]) != null; i++) {
if (co !== opt) {
switch (co.option) {
case 'mtu':
@@ -151,14 +141,14 @@ function updatePlaceholders(opt, section_id) {
}
var cbiFlagTristate = form.ListValue.extend({
__init__: function(/* ... */) {
__init__(/* ... */) {
this.super('__init__', arguments);
this.keylist = [ '', '0!', '1!' ];
this.vallist = [ _('automatic'), _('disabled'), _('enabled') ];
},
load: function(section_id) {
var invert = false, sysfs = this.sysfs;
load(section_id) {
let invert = false, sysfs = this.sysfs;
if (sysfs) {
if (sysfs.charAt(0) == '!') {
@@ -181,7 +171,7 @@ var cbiFlagTristate = form.ListValue.extend({
return this.super('load', [section_id]);
},
write: function(section_id, formvalue) {
write(section_id, formvalue) {
if (formvalue == '1!')
return this.super('write', [section_id, '1']);
else if (formvalue == '0!')
@@ -190,8 +180,8 @@ var cbiFlagTristate = form.ListValue.extend({
return this.super('remove', [section_id]);
},
renderWidget: function(section_id, option_index, cfgvalue) {
var sysdef = this.sysfs_default;
renderWidget(section_id, option_index, cfgvalue) {
const sysdef = this.sysfs_default;
if (this.sysfs_default !== null) {
this.keylist[0] = sysdef ? '1' : '0';
@@ -203,9 +193,9 @@ var cbiFlagTristate = form.ListValue.extend({
});
var cbiTagValue = form.Value.extend({
renderWidget: function(section_id, option_index, cfgvalue) {
var widget = new ui.Dropdown(cfgvalue || ['-'], {
const cbiTagValue = form.Value.extend({
renderWidget(section_id, option_index, cfgvalue) {
const widget = new ui.Dropdown(cfgvalue || ['-'], {
'-': E([], [
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '—' ]),
E('span', { 'class': 'hide-close' }, [ _('Not Member', 'VLAN port state') ])
@@ -229,11 +219,11 @@ var cbiTagValue = form.Value.extend({
multiple: true
});
var field = this;
const field = this;
widget.toggleItem = function(sb, li, force_state) {
var lis = li.parentNode.querySelectorAll('li'),
toggle = ui.Dropdown.prototype.toggleItem;
const lis = li.parentNode.querySelectorAll('li');
const toggle = ui.Dropdown.prototype.toggleItem;
toggle.apply(this, [sb, li, force_state]);
@@ -244,7 +234,7 @@ var cbiTagValue = form.Value.extend({
{
case '-':
if (li.hasAttribute('selected')) {
for (var i = 0; i < lis.length; i++) {
for (let i = 0; i < lis.length; i++) {
switch (lis[i].getAttribute('data-value')) {
case '-':
break;
@@ -264,7 +254,7 @@ var cbiTagValue = form.Value.extend({
case 't':
case 'u':
if (li.hasAttribute('selected')) {
for (var i = 0; i < lis.length; i++) {
for (let i = 0; i < lis.length; i++) {
switch (lis[i].getAttribute('data-value')) {
case li.getAttribute('data-value'):
break;
@@ -285,16 +275,16 @@ var cbiTagValue = form.Value.extend({
case '*':
if (li.hasAttribute('selected')) {
var section_ids = field.section.cfgsections();
const section_ids = field.section.cfgsections();
for (var i = 0; i < section_ids.length; i++) {
var other_widget = field.getUIElement(section_ids[i]),
other_value = L.toArray(other_widget.getValue());
for (let i = 0; i < section_ids.length; i++) {
const other_widget = field.getUIElement(section_ids[i]);
const other_value = L.toArray(other_widget.getValue());
if (other_widget === this)
continue;
var new_value = other_value.filter(function(v) { return v != '*' });
const new_value = other_value.filter(function(v) { return v != '*' });
if (new_value.length == other_value.length)
continue;
@@ -306,7 +296,7 @@ var cbiTagValue = form.Value.extend({
}
};
var node = widget.render();
const node = widget.render();
node.style.minWidth = '4em';
@@ -316,16 +306,16 @@ var cbiTagValue = form.Value.extend({
return E('div', { 'style': 'display:inline-block' }, node);
},
cfgvalue: function(section_id) {
var ports = L.toArray(uci.get('network', section_id, 'ports'));
cfgvalue(section_id) {
const ports = L.toArray(uci.get('network', section_id, 'ports'));
for (var i = 0; i < ports.length; i++) {
var s = ports[i].split(/:/);
for (let i = 0; i < ports.length; i++) {
const s = ports[i].split(/:/);
if (s[0] != this.port)
continue;
var t = /t/.test(s[1] || '') ? 't' : 'u';
const t = /t/.test(s[1] || '') ? 't' : 'u';
return /\x2a/.test(s[1] || '') ? [t, '*'] : [t];
}
@@ -333,12 +323,10 @@ var cbiTagValue = form.Value.extend({
return ['-'];
},
write: function(section_id, value) {
var ports = [];
for (var i = 0; i < this.section.children.length; i++) {
var opt = this.section.children[i];
write(section_id, value) {
const ports = [];
for (let opt of this.section.children) {
if (opt.port) {
var val = L.toArray(opt.formvalue(section_id)).join('');
@@ -360,7 +348,7 @@ var cbiTagValue = form.Value.extend({
uci.set('network', section_id, 'ports', ports.length ? ports : null);
},
remove: function() {}
remove() {}
});
return baseclass.extend({
@@ -422,8 +410,8 @@ return baseclass.extend({
{ n: 'rohc', i: 142, d: 'ROHC' },
],
replaceOption: function(s, tabName, optionClass, optionName, optionTitle, optionDescription) {
var o = s.getOption(optionName);
replaceOption(s, tabName, optionClass, optionName, optionTitle, optionDescription) {
const o = s.getOption(optionName);
if (o) {
if (o.tab) {
@@ -440,10 +428,10 @@ return baseclass.extend({
return s.taboption(tabName, optionClass, optionName, optionTitle, optionDescription);
},
addDeviceOptions: function(s, dev, isNew, rtTables, hasPSE) {
var parent_dev = dev ? dev.getParent() : null,
devname = dev ? dev.getName() : null,
o, ss;
addDeviceOptions(s, dev, isNew, rtTables, hasPSE) {
const parent_dev = dev ? dev.getParent() : null;
const devname = dev ? dev.getName() : null;
let o, ss;
s.tab('devgeneral', _('General device options'));
s.tab('devadvanced', _('Advanced device options'));
@@ -693,7 +681,7 @@ return baseclass.extend({
o.value('encap2+3', _('Encap 2+3'));
o.value('encap3+4', _('Encap 3+4'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'layer2':
@@ -742,7 +730,7 @@ return baseclass.extend({
o.value('bandwidth', _('Bandwidth'));
o.value('count', _('Count'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'stable':
@@ -769,7 +757,7 @@ return baseclass.extend({
o.value('slow', _('Slow (every 30 seconds)'));
o.value('fast', _('Fast (every second)'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'slow':
@@ -827,7 +815,7 @@ return baseclass.extend({
o.value('better', _('Better'));
o.value('failure', _('Failure'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'always':
@@ -854,7 +842,7 @@ return baseclass.extend({
o.value('active', _('Active'));
o.value('follow', _('Follow'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'none':
@@ -882,7 +870,7 @@ return baseclass.extend({
o.value('arp', _('ARP link monitoring'));
o.value('mii', _('MII link monitoring'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'arp':
@@ -923,7 +911,7 @@ return baseclass.extend({
o.value('filter_active', _('Filter active'));
o.value('filter_backup', _('Filter backup'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'none':
@@ -988,16 +976,16 @@ return baseclass.extend({
o.ucioption = 'ports';
o.default = L.toArray(dev ? dev.getPorts() : null).filter(function(p) { return p.getType() != 'wifi' }).map(function(p) { return p.getName() });
o.filter = function(section_id, device_name) {
var bridge_name = uci.get('network', section_id, 'name'),
const bridge_name = uci.get('network', section_id, 'name'),
choice_dev = network.instantiateDevice(device_name),
parent_dev = choice_dev.getParent();
/* only show wifi networks which are already present in "option ifname" */
if (choice_dev.getType() == 'wifi') {
var ifnames = L.toArray(uci.get('network', section_id, 'ports'));
const ifnames = L.toArray(uci.get('network', section_id, 'ports'));
for (var i = 0; i < ifnames.length; i++)
if (ifnames[i] == device_name)
for (let ifn of ifnames)
if (ifn == device_name)
return true;
return false;
@@ -1084,8 +1072,8 @@ return baseclass.extend({
o.placeholder = '1000';
o.datatype = 'uinteger';
o.validate = function(section_id, value) {
var qiopt = L.toArray(this.map.lookupOption('query_interval', section_id))[0],
qival = qiopt ? (qiopt.formvalue(section_id) || qiopt.placeholder) : '';
const qiopt = L.toArray(this.map.lookupOption('query_interval', section_id))[0];
const qival = qiopt ? (qiopt.formvalue(section_id) || qiopt.placeholder) : '';
if (value != '' && qival != '' && +value >= +qival)
return _('The query response interval must be lower than the query interval value');
@@ -1102,7 +1090,7 @@ return baseclass.extend({
o = this.replaceOption(s, 'devgeneral', form.Value, 'mtu', _('MTU'));
o.datatype = 'range(576, 9200)';
o.validate = function(section_id, value) {
var parent_mtu = (dev && dev.getType() == 'vlan') ? (parent_dev ? parent_dev.getMTU() : null) : null;
const parent_mtu = (dev && dev.getType() == 'vlan') ? (parent_dev ? parent_dev.getMTU() : null) : null;
if (parent_mtu !== null && +value > parent_mtu)
return _('The MTU must not exceed the parent device MTU of %d bytes').format(parent_mtu);
@@ -1118,13 +1106,13 @@ return baseclass.extend({
o.datatype = 'maxlength(15)';
o.depends('type', 'veth');
o.load = function(section_id) {
var sections = uci.sections('network', 'device'),
idx = 0;
const sections = uci.sections('network', 'device');
let idx = 0;
for (var i = 0; i < sections.length; i++)
if (sections[i]['.name'] == section_id)
for (let s of sections)
if (s['.name'] == section_id)
break;
else if (sections[i].type == 'veth')
else if (s.type == 'veth')
idx++;
this.placeholder = 'veth%d'.format(idx);
@@ -1178,7 +1166,7 @@ return baseclass.extend({
o.value('loose', _('Loose filtering'));
o.value('strict', _('Strict filtering'));
o.cfgvalue = function(/* ... */) {
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
const val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
switch (val || '') {
case 'loose':
@@ -1291,9 +1279,9 @@ return baseclass.extend({
o = this.replaceOption(s, 'bridgevlan', form.Flag, 'vlan_filtering', _('Enable VLAN filtering'));
o.depends('type', 'bridge');
o.updateDefaultValue = function(section_id) {
var device = uci.get('network', s.section, 'name'),
uielem = this.getUIElement(section_id),
has_vlans = false;
const device = uci.get('network', s.section, 'name');
const uielem = this.getUIElement(section_id);
let has_vlans = false;
uci.sections('network', 'bridge-vlan', function(bvs) {
has_vlans = has_vlans || (bvs.device == device);
@@ -1313,7 +1301,7 @@ return baseclass.extend({
ss.anonymous = true;
ss.renderHeaderRows = function(/* ... */) {
var node = form.TableSection.prototype.renderHeaderRows.apply(this, arguments);
const node = form.TableSection.prototype.renderHeaderRows.apply(this, arguments);
node.querySelectorAll('.th').forEach(function(th) {
th.classList.add('left');
@@ -1324,7 +1312,7 @@ return baseclass.extend({
};
ss.filter = function(section_id) {
var devname = uci.get('network', s.section, 'name');
const devname = uci.get('network', s.section, 'name');
return (uci.get('network', section_id, 'device') == devname);
};
@@ -1347,7 +1335,7 @@ return baseclass.extend({
};
ss.updatePorts = function(ports) {
var devices = ports.map(function(port) {
const devices = ports.map(function(port) {
return network.instantiateDevice(port)
}).filter(function(dev) {
return dev.getType() != 'wifi' || dev.isUp();
@@ -1357,35 +1345,35 @@ return baseclass.extend({
this.children = this.children.filter(function(opt) { return !opt.option.match(/^port_/) });
for (var i = 0; i < devices.length; i++) {
o = ss.option(cbiTagValue, 'port_%s'.format(sfh(devices[i].getName())), renderDevBadge(devices[i]), renderPortStatus(devices[i]));
o.port = devices[i].getName();
for (let d of devices) {
o = ss.option(cbiTagValue, 'port_%s'.format(sfh(d.getName())), renderDevBadge(d), renderPortStatus(d));
o.port = d.getName();
}
var section_ids = this.cfgsections(),
device_names = devices.reduce(function(names, dev) { names[dev.getName()] = true; return names }, {});
const section_ids = this.cfgsections();
const device_names = devices.reduce(function(names, dev) { names[dev.getName()] = true; return names }, {});
for (var i = 0; i < section_ids.length; i++) {
var old_spec = L.toArray(uci.get('network', section_ids[i], 'ports')),
new_spec = old_spec.filter(function(spec) { return device_names[spec.replace(/:[ut*]+$/, '')] });
for (let s of section_ids) {
const old_spec = L.toArray(uci.get('network', s, 'ports'));
const new_spec = old_spec.filter(function(spec) { return device_names[spec.replace(/:[ut*]+$/, '')] });
if (old_spec.length != new_spec.length)
uci.set('network', section_ids[i], 'ports', new_spec.length ? new_spec : null);
uci.set('network', s, 'ports', new_spec.length ? new_spec : null);
}
};
ss.handleAdd = function(ev) {
return s.parse().then(L.bind(function() {
var device = uci.get('network', s.section, 'name'),
section_ids = this.cfgsections(),
section_id = null,
max_vlan_id = 0;
const device = uci.get('network', s.section, 'name');
const section_ids = this.cfgsections();
let section_id = null;
let max_vlan_id = 0;
if (!device)
return;
for (var i = 0; i < section_ids.length; i++) {
var vid = +uci.get('network', section_ids[i], 'vlan');
for (let s of section_ids) {
var vid = +uci.get('network', s, 'vlan');
if (vid > max_vlan_id)
max_vlan_id = vid;
@@ -1428,7 +1416,7 @@ return baseclass.extend({
o.datatype = 'range(1, 4094)';
o.renderWidget = function(/* ... */) {
var node = form.Value.prototype.renderWidget.apply(this, arguments);
const node = form.Value.prototype.renderWidget.apply(this, arguments);
node.style.width = '5em';
@@ -1436,13 +1424,13 @@ return baseclass.extend({
};
o.validate = function(section_id, value) {
var section_ids = this.section.cfgsections();
const section_ids = this.section.cfgsections();
for (var i = 0; i < section_ids.length; i++) {
if (section_ids[i] == section_id)
for (let s of section_ids) {
if (s == section_id)
continue;
if (uci.get('network', section_ids[i], 'vlan') == value)
if (uci.get('network', s, 'vlan') == value)
return _('The VLAN ID must be unique');
}

View File

@@ -534,7 +534,6 @@ return view.extend({
else
return _('Address families of "Relay from" and "Relay to address" must match.')
}
return true;
};
so = ss.option(widgets.NetworkSelect, 'interface', _('Only accept replies via'));

View File

@@ -90,14 +90,14 @@ function validateServerSpec(sid, s) {
}
return view.extend({
load: function() {
load() {
return Promise.all([
callHostHints(),
uci.load('firewall')
]);
},
render: function([hosts]) {
render([hosts]) {
let m, s, o, ss, so, dnss;
let noi18nstrings = {
@@ -524,6 +524,7 @@ return view.extend({
let target = this.section.formvalue(section_id, '_svc_target') || '.';
let params = value.trim().split('\n').map(l => l.trim()).filter(Boolean);
// eslint-disable-next-line no-undef
const hex = drh.buildSvcbHex(priority, target, params);
uci.set('dhcp', section_id, 'hexdata', hex);
};
@@ -533,6 +534,7 @@ return view.extend({
if (rrnum !== '65') return null;
let hexdata = uci.get('dhcp', section_id, 'hexdata');
// eslint-disable-next-line no-undef
return drh.parseSvcbHex(hexdata);
};

View File

@@ -28,12 +28,12 @@ function count_changes(section_id) {
return n;
if (Array.isArray(changes.network))
for (var i = 0; i < changes.network.length; i++)
n += (changes.network[i][1] == section_id);
for (let c of changes.network)
n += (c[1] == section_id);
if (Array.isArray(changes.dhcp))
for (var i = 0; i < changes.dhcp.length; i++)
n += (changes.dhcp[i][1] == section_id);
for (let c of changes.dhcp)
n += (c[1] == section_id);
return n;
}
@@ -62,7 +62,7 @@ function render_iface(dev, alias) {
}
function render_status(node, ifc, with_device) {
var desc = null, c = [];
let desc = null;
if (ifc.isDynamic())
desc = _('Virtual dynamic interface');
@@ -125,9 +125,9 @@ function render_modal_status(node, ifc) {
}
function render_ifacebox_status(node, ifc) {
var dev = ifc.getL3Device() || ifc.getDevice(),
subdevs = dev ? dev.getPorts() : null,
c = [ render_iface(dev, ifc.isAlias()) ];
const dev = ifc.getL3Device() || ifc.getDevice();
const subdevs = dev ? dev.getPorts() : null;
const c = [ render_iface(dev, ifc.isAlias()) ];
if (subdevs && subdevs.length) {
var sifs = [ ' (' ];
@@ -142,7 +142,7 @@ function render_ifacebox_status(node, ifc) {
c.push(E('br'));
c.push(E('small', {}, ifc.isAlias() ? _('Alias of "%s"').format(ifc.isAlias())
: (dev ? dev.getName() : E('em', _('Not present')))));
: (dev ? dev.getName() : E('em', _('Not present')))));
dom.content(node, c);
@@ -153,9 +153,9 @@ function render_ifacebox_status(node, ifc) {
}
function iface_updown(up, id, ev, force) {
var row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(id)),
dsc = row.querySelector('[data-name="_ifacestat"] > div'),
btns = row.querySelectorAll('.cbi-section-actions .reconnect, .cbi-section-actions .down');
const row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(id));
const dsc = row.querySelector('[data-name="_ifacestat"] > div');
const btns = row.querySelectorAll('.cbi-section-actions .reconnect, .cbi-section-actions .down');
btns[+!up].blur();
btns[+!up].classList.add('spinning');
@@ -176,7 +176,7 @@ function iface_updown(up, id, ev, force) {
E('div', { 'class': 'button-row' }, [
E('button', {
'class': 'btn cbi-button cbi-button-neutral',
'click': function(ev) {
'click': function (ev) {
btns[1].classList.remove('spinning');
btns[1].disabled = false;
btns[0].disabled = false;
@@ -187,7 +187,7 @@ function iface_updown(up, id, ev, force) {
' ',
E('button', {
'class': 'btn cbi-button cbi-button-negative important',
'click': function(ev) {
'click': function (ev) {
dsc.setAttribute('disconnect', '');
dom.content(dsc, E('em', _('Interface is shutting down...')));
@@ -210,15 +210,15 @@ function iface_updown(up, id, ev, force) {
}
function get_netmask(s, use_cfgvalue) {
var readfn = use_cfgvalue ? 'cfgvalue' : 'formvalue',
addrs = L.toArray(s[readfn](s.section, 'ipaddr')),
mask = s[readfn](s.section, 'netmask'),
firstsubnet = mask ? addrs[0] + '/' + mask : addrs.filter(function(a) { return a.indexOf('/') > 0 })[0];
const readfn = use_cfgvalue ? 'cfgvalue' : 'formvalue';
const addrs = L.toArray(s[readfn](s.section, 'ipaddr'));
const mask = s[readfn](s.section, 'netmask');
const firstsubnet = mask ? addrs[0] + '/' + mask : addrs.filter(function(a) { return a.indexOf('/') > 0 })[0];
if (firstsubnet == null)
return null;
var subnetmask = firstsubnet.split('/')[1];
let subnetmask = firstsubnet.split('/')[1];
if (!isNaN(subnetmask))
subnetmask = network.prefixToMask(+subnetmask);
@@ -263,25 +263,24 @@ function has_sourcefilter(proto) {
}
return view.extend({
poll_status: function(map, networks) {
var resolveZone = null;
poll_status(map, networks) {
let resolveZone = null;
for (var i = 0; i < networks.length; i++) {
var ifc = networks[i],
row = map.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(ifc.getName()));
for (let ifc of networks) {
const row = map.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(ifc.getName()));
if (row == null)
continue;
var dsc = row.querySelector('[data-name="_ifacestat"] > div'),
box = row.querySelector('[data-name="_ifacebox"] .ifacebox-body'),
btn1 = row.querySelector('.cbi-section-actions .reconnect'),
btn2 = row.querySelector('.cbi-section-actions .down'),
stat = document.querySelector('[id="%s-ifc-status"]'.format(ifc.getName())),
resolveZone = render_ifacebox_status(box, ifc),
disabled = ifc ? !ifc.isUp() : true,
dynamic = ifc ? ifc.isDynamic() : false,
pending = ifc ? ifc.isPending() : false;
const dsc = row.querySelector('[data-name="_ifacestat"] > div');
const box = row.querySelector('[data-name="_ifacebox"] .ifacebox-body');
const btn1 = row.querySelector('.cbi-section-actions .reconnect');
const btn2 = row.querySelector('.cbi-section-actions .down');
const stat = document.querySelector('[id="%s-ifc-status"]'.format(ifc.getName()));
resolveZone = render_ifacebox_status(box, ifc);
const disabled = ifc ? !ifc.isUp() : true;
const dynamic = ifc ? ifc.isDynamic() : false;
const pending = ifc ? ifc.isPending() : false;
if (dsc.hasAttribute('reconnect')) {
dom.content(dsc, E('em', _('Interface is starting...')));
@@ -293,10 +292,10 @@ return view.extend({
render_status(dsc, ifc, false);
}
else if (!ifc.getProtocol()) {
var e = map.querySelector('[id="cbi-network-%s"] .cbi-button-edit'.format(ifc.getName()));
const e = map.querySelector('[id="cbi-network-%s"] .cbi-button-edit'.format(ifc.getName()));
if (e) e.disabled = true;
var link = L.url('admin/system/package-manager') + '?query=luci-proto';
const link = L.url('admin/system/package-manager') + '?query=luci-proto';
dom.content(dsc, [
E('em', _('Unsupported protocol type.')), E('br'),
E('a', { href: link }, _('Install protocol extensions...'))
@@ -354,7 +353,7 @@ return view.extend({
return Promise.all([ resolveZone, network.flushCache() ]);
},
load: function() {
load() {
return Promise.all([
network.getDSLModemType(),
network.getDevices(),
@@ -363,29 +362,29 @@ return view.extend({
]);
},
interfaceBridgeWithIfnameSections: function() {
interfaceBridgeWithIfnameSections() {
return uci.sections('network', 'interface').filter(function(ns) {
return ns.type == 'bridge' && !ns.ports && ns.ifname;
});
},
deviceWithIfnameSections: function() {
deviceWithIfnameSections() {
return uci.sections('network', 'device').filter(function(ns) {
return ns.type == 'bridge' && !ns.ports && ns.ifname;
});
},
interfaceWithIfnameSections: function() {
interfaceWithIfnameSections() {
return uci.sections('network', 'interface').filter(function(ns) {
return !ns.device && ns.ifname;
});
},
handleBridgeMigration: function(ev) {
var tasks = [];
handleBridgeMigration(ev) {
const tasks = [];
this.interfaceBridgeWithIfnameSections().forEach(function(ns) {
var device_name = 'br-' + ns['.name'];
const device_name = 'br-' + ns['.name'];
tasks.push(uci.callAdd('network', 'device', null, {
'name': device_name,
@@ -411,7 +410,7 @@ return view.extend({
.then(L.bind(ui.changes.apply, ui.changes));
},
renderBridgeMigration: function() {
renderBridgeMigration() {
ui.showModal(_('Network bridge configuration migration'), [
E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')),
E('p', _('Upon pressing "Continue", bridges configuration will be updated and the network will be restarted to apply the updated configuration.')),
@@ -423,8 +422,8 @@ return view.extend({
]);
},
handleIfnameMigration: function(ev) {
var tasks = [];
handleIfnameMigration(ev) {
const tasks = [];
this.deviceWithIfnameSections().forEach(function(ds) {
tasks.push(uci.callSet('network', ds['.name'], {
@@ -445,7 +444,7 @@ return view.extend({
.then(L.bind(ui.changes.apply, ui.changes));
},
renderIfnameMigration: function() {
renderIfnameMigration() {
ui.showModal(_('Network ifname configuration migration'), [
E('p', _('The existing network configuration needs to be changed for LuCI to function properly.')),
E('p', _('Upon pressing "Continue", ifname options will get renamed and the network will be restarted to apply the updated configuration.')),
@@ -457,19 +456,17 @@ return view.extend({
]);
},
render: function(data) {
render([dslModemType, netDevs, rtTables]) {
if (this.interfaceBridgeWithIfnameSections().length)
return this.renderBridgeMigration();
else if (this.deviceWithIfnameSections().length || this.interfaceWithIfnameSections().length)
return this.renderIfnameMigration();
var dslModemType = data[0],
netDevs = data[1],
m, s, o;
let m, s, o;
var rtTables = data[2].map(function(l) {
var m = l.trim().match(/^(\d+)\s+(\S+)$/);
rtTables = rtTables.map(function(l) {
const m = l.trim().match(/^(\d+)\s+(\S+)$/);
return m ? [ +m[1], m[2] ] : null;
}).filter(function(e) {
return e && e[0] > 0;
@@ -570,11 +567,11 @@ return view.extend({
};
s.addModalOptions = function(s) {
var protoval = uci.get('network', s.section, 'proto') || 'none',
o, proto_select, proto_switch, type, stp, igmp, ss, so;
const protoval = uci.get('network', s.section, 'proto') || 'none';
let o, proto_select, proto_switch, ss, so;
return network.getNetwork(s.section).then(L.bind(function(ifc) {
var protocols = network.getProtocols();
const protocols = network.getProtocols();
protocols.sort(function(a, b) {
return L.naturalCompare(a.getProtocol(), b.getProtocol());
@@ -583,7 +580,7 @@ return view.extend({
o = s.taboption('general', form.DummyValue, '_ifacestat_modal', _('Status'));
o.modalonly = true;
o.cfgvalue = L.bind(function(section_id) {
var net = this.networks.filter(function(n) { return n.getName() == section_id })[0];
const net = this.networks.filter(function(n) { return n.getName() == section_id })[0];
return render_modal_status(E('div', {
'id': '%s-ifc-status'.format(section_id),
@@ -638,10 +635,7 @@ return view.extend({
return Promise.all([
firewall.getZoneByNetwork(ifc.getName()),
(value != null) ? firewall.getZone(value) : null
]).then(function(data) {
var old_zone = data[0],
new_zone = data[1];
]).then(function([old_zone, new_zone]) {
if (old_zone == null && new_zone == null && (value == null || value == ''))
return;
@@ -661,11 +655,11 @@ return view.extend({
};
}
for (var i = 0; i < protocols.length; i++) {
proto_select.value(protocols[i].getProtocol(), protocols[i].getI18n());
for (let p of protocols) {
proto_select.value(p.getProtocol(), p.getI18n());
if (protocols[i].getProtocol() != protoval)
proto_switch.depends('proto', protocols[i].getProtocol());
if (p.getProtocol() != protoval)
proto_switch.depends('proto', p.getProtocol());
}
if (L.hasSystemFeature('dnsmasq') || L.hasSystemFeature('odhcpd')) {
@@ -787,7 +781,7 @@ return view.extend({
return form.Value.prototype.render.apply(this, [ option_index, section_id, in_table ]);
};
so.validate = function(section_id, value) {
var uielem = this.getUIElement(section_id);
const uielem = this.getUIElement(section_id);
if (uielem)
uielem.setPlaceholder(get_netmask(s, false));
return form.Value.prototype.validate.apply(this, [ section_id, value ]);
@@ -796,7 +790,7 @@ return view.extend({
}
var has_other_master = uci.sections('dhcp', 'dhcp').filter(function(s) {
const has_other_master = uci.sections('dhcp', 'dhcp').filter(function(s) {
return (s.interface != ifc.getName() && s.master == '1');
})[0];
@@ -808,14 +802,14 @@ return view.extend({
;
so.validate = function(section_id, value) {
var hybrid_downstream_desc = _('Operate in <em>relay mode</em> if a designated master interface is configured and active, otherwise fall back to <em>server mode</em>.'),
ndp_downstream_desc = _('Operate in <em>relay mode</em> if a designated master interface is configured and active, otherwise disable <abbr title="Neighbour Discovery Protocol">NDP</abbr> proxying.'),
hybrid_master_desc = _('Operate in <em>relay mode</em> if an upstream IPv6 prefix is present, otherwise disable service.'),
ra_server_allowed = true,
checked = this.formvalue(section_id),
dhcpv6 = this.section.getOption('dhcpv6').getUIElement(section_id),
ndp = this.section.getOption('ndp').getUIElement(section_id),
ra = this.section.getOption('ra').getUIElement(section_id);
const hybrid_downstream_desc = _('Operate in <em>relay mode</em> if a designated master interface is configured and active, otherwise fall back to <em>server mode</em>.');
const ndp_downstream_desc = _('Operate in <em>relay mode</em> if a designated master interface is configured and active, otherwise disable <abbr title="Neighbour Discovery Protocol">NDP</abbr> proxying.');
const hybrid_master_desc = _('Operate in <em>relay mode</em> if an upstream IPv6 prefix is present, otherwise disable service.');
let ra_server_allowed = true;
const checked = this.formvalue(section_id);
const dhcpv6 = this.section.getOption('dhcpv6').getUIElement(section_id);
const ndp = this.section.getOption('ndp').getUIElement(section_id);
const ra = this.section.getOption('ra').getUIElement(section_id);
/* Assume that serving RAs by default is fine, but disallow it for certain
interface protocols such as DHCP, DHCPv6 or the various PPP flavors.
@@ -923,11 +917,11 @@ return view.extend({
so.depends('ra', 'server');
so.depends({ ra: 'hybrid', master: '0' });
so.cfgvalue = function(section_id) {
var flags = L.toArray(uci.get('dhcp', section_id, 'ra_flags'));
const flags = L.toArray(uci.get('dhcp', section_id, 'ra_flags'));
return flags.length ? flags : [ 'other-config' ];
};
so.remove = function(section_id) {
var existing = L.toArray(uci.get('dhcp', section_id, 'ra_flags'));
const existing = L.toArray(uci.get('dhcp', section_id, 'ra_flags'));
if (this.isActive(section_id)) {
if (existing.length != 1 || existing[0] != 'none')
uci.set('dhcp', section_id, 'ra_flags', [ 'none' ]);
@@ -1034,8 +1028,8 @@ return view.extend({
so.depends('ra', 'server');
so.depends({ ra: 'hybrid', master: '0' });
so.load = function(section_id) {
var dev = ifc.getL3Device(),
path = dev ? "/proc/sys/net/ipv6/conf/%s/mtu".format(dev.getName()) : null;
const dev = ifc.getL3Device();
const path = dev ? "/proc/sys/net/ipv6/conf/%s/mtu".format(dev.getName()) : null;
return Promise.all([
dev ? L.resolveDefault(fs.read(path), dev.getMTU()) : null,
@@ -1053,8 +1047,8 @@ return view.extend({
so.depends('ra', 'server');
so.depends({ ra: 'hybrid', master: '0' });
so.load = function(section_id) {
var dev = ifc.getL3Device(),
path = dev ? "/proc/sys/net/ipv6/conf/%s/hop_limit".format(dev.getName()) : null;
const dev = ifc.getL3Device();
const path = dev ? "/proc/sys/net/ipv6/conf/%s/hop_limit".format(dev.getName()) : null;
return Promise.all([
dev ? L.resolveDefault(fs.read(path), 64) : null,
@@ -1155,14 +1149,14 @@ return view.extend({
so = ss.taboption('dhcpv6', form.DynamicList, 'ntp', _('NTP Servers'),
_('DHCPv6 option 56. %s.', 'DHCPv6 option 56. RFC5908 link').format('<a href="%s" target="_blank">RFC5908</a>').format('https://www.rfc-editor.org/rfc/rfc5908#section-4'));
so.datatype = 'host(0)';
for(var x of uci.get('system', 'ntp', 'server') || '') {
for(let x of uci.get('system', 'ntp', 'server') || '') {
so.value(x);
}
var local_nets = this.networks.filter(function(n) { return n.getName() != 'loopback' });
const local_nets = this.networks.filter(function(n) { return n.getName() != 'loopback' });
if(local_nets) {
// If ntpd is set up, suggest our IP(v6) also
if(uci.get('system', 'ntp', 'enable_server')) {
local_nets.forEach(function(n){
local_nets.forEach(function(n) {
n.getIPAddrs().forEach(function(i4) {
so.value(i4.split('/')[0]);
});
@@ -1224,13 +1218,13 @@ return view.extend({
o = nettools.replaceOption(s, 'advanced', form.Value, 'ip4table', _('Override IPv4 routing table'));
o.datatype = 'or(uinteger, string)';
for (var i = 0; i < rtTables.length; i++)
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
for (let rt of rtTables)
o.value(rt[1], '%s (%d)'.format(rt[1], rt[0]));
o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6table', _('Override IPv6 routing table'));
o.datatype = 'or(uinteger, string)';
for (var i = 0; i < rtTables.length; i++)
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
for (let rt of rtTables)
o.value(rt[1], '%s (%d)'.format(rt[1], rt[0]));
if (has_sourcefilter(protoval)) {
o = nettools.replaceOption(s, 'advanced', form.Flag, 'sourcefilter', _('IPv6 source routing'), _('Automatically handle multiple uplink interfaces using source-based policy routing.'));
@@ -1251,24 +1245,24 @@ return view.extend({
if (value == null || value == '')
return true;
var n = parseInt(value, 16);
const n = parseInt(value, 16);
if (!/^(0x)?[0-9a-fA-F]+$/.test(value) || isNaN(n) || n >= 0xffffffff)
return _('Expecting a hexadecimal assignment hint');
return true;
};
for (var i = 33; i <= 64; i++)
for (let i = 33; i <= 64; i++)
o.depends('ip6assign', String(i));
o = nettools.replaceOption(s, 'advanced', form.DynamicList, 'ip6class', _('IPv6 prefix filter'), _('If set, downstream subnets are only allocated from the given IPv6 prefix classes.'));
o.value('local', 'local (%s)'.format(_('Local ULA')));
var prefixClasses = {};
const prefixClasses = {};
this.networks.forEach(function(net) {
var prefixes = net._ubus('ipv6-prefix');
const prefixes = net._ubus('ipv6-prefix');
if (Array.isArray(prefixes)) {
prefixes.forEach(function(pfx) {
if (L.isObject(pfx) && typeof(pfx['class']) == 'string') {
@@ -1280,7 +1274,7 @@ return view.extend({
});
Object.keys(prefixClasses).sort().forEach(function(c) {
var networks = Object.keys(prefixClasses[c]).sort().join(', ');
const networks = Object.keys(prefixClasses[c]).sort().join(', ');
o.value(c, (c != networks) ? '%s (%s)'.format(c, networks) : c);
});
@@ -1293,9 +1287,8 @@ return view.extend({
o.datatype = 'uinteger';
o.placeholder = '0';
for (var i = 0; i < s.children.length; i++) {
o = s.children[i];
for (let o of s.children) {
const deps = [];
switch (o.option) {
case 'proto':
case 'auto':
@@ -1309,14 +1302,13 @@ return view.extend({
case 'stp':
case 'type':
case '_net_device':
var deps = [];
for (var j = 0; j < protocols.length; j++) {
if (!protocols[j].isVirtual()) {
for (let p of protocols) {
if (!p.isVirtual()) {
if (o.deps.length)
for (var k = 0; k < o.deps.length; k++)
deps.push(Object.assign({ proto: protocols[j].getProtocol() }, o.deps[k]));
for (let od of o.deps)
deps.push(Object.assign({ proto: p.getProtocol() }, od));
else
deps.push({ proto: protocols[j].getProtocol() });
deps.push({ proto: p.getProtocol() });
}
}
o.deps = deps;
@@ -1324,8 +1316,8 @@ return view.extend({
default:
if (o.deps.length)
for (var j = 0; j < o.deps.length; j++)
o.deps[j].proto = protoval;
for (let od of o.deps)
od.proto = protoval;
else
o.depends('proto', protoval);
}
@@ -1336,8 +1328,8 @@ return view.extend({
};
s.handleModalCancel = function(/* ... */) {
var type = uci.get('network', this.activeSection || this.addedSection, 'type'),
device = (type == 'bridge') ? 'br-%s'.format(this.activeSection || this.addedSection) : null;
const type = uci.get('network', this.activeSection || this.addedSection, 'type');
const device = (type == 'bridge') ? 'br-%s'.format(this.activeSection || this.addedSection) : null;
uci.sections('network', 'bridge-vlan', function(bvs) {
if (device != null && bvs.device == device)
@@ -1348,10 +1340,10 @@ return view.extend({
};
s.handleAdd = function(ev) {
var m2 = new form.Map('network'),
s2 = m2.section(form.NamedSection, '_new_'),
protocols = network.getProtocols(),
proto, name, device;
const m2 = new form.Map('network');
const s2 = m2.section(form.NamedSection, '_new_');
const protocols = network.getProtocols();
let proto, name, device;
protocols.sort(function(a, b) {
return L.naturalCompare(a.getProtocol(), b.getProtocol());
@@ -1372,10 +1364,10 @@ return view.extend({
if (uci.get('network', value) != null)
return _('The interface name is already used');
var pr = network.getProtocol(proto.formvalue(section_id), value),
ifname = pr.isVirtual() ? '%s-%s'.format(pr.getProtocol(), value) : 'br-%s'.format(value);
const pr = network.getProtocol(proto.formvalue(section_id), value);
const ifname = pr.isVirtual() ? '%s-%s'.format(pr.getProtocol(), value) : 'br-%s'.format(value);
if (value.length > 15)
if (ifname.length > 15)
return _('The interface name is too long');
return true;
@@ -1383,7 +1375,7 @@ return view.extend({
proto = s2.option(form.ListValue, 'proto', _('Protocol'));
proto.onchange = function(ev, section_id, value) {
var elem = name.getUIElement(section_id);
const elem = name.getUIElement(section_id);
elem.triggerValidation();
};
@@ -1391,11 +1383,11 @@ return view.extend({
device.noaliases = false;
device.optional = false;
for (var i = 0; i < protocols.length; i++) {
proto.value(protocols[i].getProtocol(), protocols[i].getI18n());
for (let p of protocols) {
proto.value(p.getProtocol(), p.getI18n());
if (!protocols[i].isVirtual())
device.depends('proto', protocols[i].getProtocol());
if (!p.isVirtual())
device.depends('proto', p.getProtocol());
}
m2.render().then(L.bind(function(nodes) {
@@ -1409,9 +1401,9 @@ return view.extend({
E('button', {
'class': 'cbi-button cbi-button-positive important',
'click': ui.createHandlerFn(this, function(ev) {
var nameval = name.isValid('_new_') ? name.formvalue('_new_') : null,
protoval = proto.isValid('_new_') ? proto.formvalue('_new_') : null,
protoclass = protoval ? network.getProtocol(protoval, nameval) : null;
const nameval = name.isValid('_new_') ? name.formvalue('_new_') : null;
const protoval = proto.isValid('_new_') ? proto.formvalue('_new_') : null;
const protoclass = protoval ? network.getProtocol(protoval, nameval) : null;
if (nameval == null || protoval == null || nameval == '' || protoval == '')
return;
@@ -1425,7 +1417,7 @@ return view.extend({
}
return m.save(function() {
var section_id = uci.add('network', 'interface', nameval);
const section_id = uci.add('network', 'interface', nameval);
protoclass.set('proto', protoval);
protoclass.addDevice(device.formvalue('_new_'));
@@ -1454,13 +1446,13 @@ return view.extend({
o = s.option(form.DummyValue, '_ifacebox');
o.modalonly = false;
o.textvalue = function(section_id) {
var net = this.section.networks.filter(function(n) { return n.getName() == section_id })[0],
zone = net ? this.section.zones.filter(function(z) { return !!z.getNetworks().filter(function(n) { return n == section_id })[0] })[0] : null;
const net = this.section.networks.filter(function(n) { return n.getName() == section_id })[0];
const zone = net ? this.section.zones.filter(function(z) { return !!z.getNetworks().filter(function(n) { return n == section_id })[0] })[0] : null;
if (!net)
return;
var node = E('div', { 'class': 'ifacebox' }, [
const node = E('div', { 'class': 'ifacebox' }, [
E('div', {
'class': 'ifacebox-head',
'style': firewall.getZoneColorStyle(zone),
@@ -1487,12 +1479,12 @@ return view.extend({
o = s.option(form.DummyValue, '_ifacestat');
o.modalonly = false;
o.textvalue = function(section_id) {
var net = this.section.networks.filter(function(n) { return n.getName() == section_id })[0];
const net = this.section.networks.filter(function(n) { return n.getName() == section_id })[0];
if (!net)
return;
var node = E('div', { 'id': '%s-ifc-description'.format(section_id) });
const node = E('div', { 'id': '%s-ifc-description'.format(section_id) });
render_status(node, net, false);
@@ -1518,36 +1510,36 @@ return view.extend({
s.addbtntitle = _('Add device configuration…');
s.cfgsections = function() {
var sections = uci.sections('network', 'device'),
section_ids = sections.sort(function(a, b) { return L.naturalCompare(a.name, b.name) }).map(function(s) { return s['.name'] });
const sections = uci.sections('network', 'device');
const section_ids = sections.sort(function(a, b) { return L.naturalCompare(a.name, b.name) }).map(function(s) { return s['.name'] });
for (var i = 0; i < netDevs.length; i++) {
if (sections.filter(function(s) { return s.name == netDevs[i].getName() }).length)
for (let nd of netDevs) {
if (sections.filter(function(s) { return s.name == nd.getName() }).length)
continue;
if (netDevs[i].getType() == 'wifi' && !netDevs[i].isUp())
if (nd.getType() == 'wifi' && !nd.isUp())
continue;
/* Unless http://lists.openwrt.org/pipermail/openwrt-devel/2020-July/030397.html is implemented,
we cannot properly redefine bridges as devices, so filter them away for now... */
var m = netDevs[i].isBridge() ? netDevs[i].getName().match(/^br-([A-Za-z0-9_]+)$/) : null,
s = m ? uci.get('network', m[1]) : null;
const m = nd.isBridge() ? nd.getName().match(/^br-([A-Za-z0-9_]+)$/) : null;
const s = m ? uci.get('network', m[1]) : null;
if (s && s['.type'] == 'interface' && s.type == 'bridge')
continue;
section_ids.push('dev:%s'.format(netDevs[i].getName()));
section_ids.push('dev:%s'.format(nd.getName()));
}
return section_ids;
};
s.renderMoreOptionsModal = function(section_id, ev) {
var m = section_id.match(/^dev:(.+)$/);
const m = section_id.match(/^dev:(.+)$/);
if (m) {
var devtype = getDevType(section_id);
const devtype = getDevType(section_id);
section_id = uci.add('network', 'device');
@@ -1561,8 +1553,8 @@ return view.extend({
};
s.renderRowActions = function(section_id) {
var trEl = this.super('renderRowActions', [ section_id, _('Configure…') ]),
deleteBtn = trEl.querySelector('button:last-child');
const trEl = this.super('renderRowActions', [ section_id, _('Configure…') ]);
const deleteBtn = trEl.querySelector('button:last-child');
deleteBtn.firstChild.data = _('Unconfigure');
deleteBtn.setAttribute('title', _('Remove related device settings from the configuration'));
@@ -1572,16 +1564,16 @@ return view.extend({
};
s.modaltitle = function(section_id) {
var m = section_id.match(/^dev:(.+)$/),
name = m ? m[1] : uci.get('network', section_id, 'name');
const m = section_id.match(/^dev:(.+)$/);
const name = m ? m[1] : uci.get('network', section_id, 'name');
return name ? '%s: %q'.format(getDevTypeDesc(section_id), name) : _('Add device configuration');
};
s.addModalOptions = function(s) {
const isNew = (uci.get('network', s.section, 'name') == null),
dev = getDevice(s.section),
devName = dev ? dev.getName() : null;
const isNew = (uci.get('network', s.section, 'name') == null);
const dev = getDevice(s.section);
const devName = dev ? dev.getName() : null;
/* Query PSE status from netifd to determine if device has PSE capability */
if (devName) {
@@ -1596,7 +1588,7 @@ return view.extend({
};
s.handleModalCancel = function(map /*, ... */) {
var name = uci.get('network', this.addedSection, 'name')
const name = uci.get('network', this.addedSection, 'name');
uci.sections('network', 'bridge-vlan', function(bvs) {
if (name != null && bvs.device == name)
@@ -1604,8 +1596,8 @@ return view.extend({
});
if (map.addedVLANs)
for (var i = 0; i < map.addedVLANs.length; i++)
uci.remove('network', map.addedVLANs[i]);
for (let mav of map.addedVLANs)
uci.remove('network', mav);
if (this.addedSection)
uci.remove('network', this.addedSection);
@@ -1614,8 +1606,8 @@ return view.extend({
};
s.handleRemove = function(section_id /*, ... */) {
var name = uci.get('network', section_id, 'name'),
type = uci.get('network', section_id, 'type');
const name = uci.get('network', section_id, 'name');
const type = uci.get('network', section_id, 'type');
if (name != null && type == 'bridge') {
uci.sections('network', 'bridge-vlan', function(bvs) {
@@ -1628,16 +1620,16 @@ return view.extend({
};
function getDevice(section_id) {
var m = section_id.match(/^dev:(.+)$/),
name = m ? m[1] : uci.get('network', section_id, 'name');
const m = section_id.match(/^dev:(.+)$/);
const name = m ? m[1] : uci.get('network', section_id, 'name');
return netDevs.filter(function(d) { return d.getName() == name })[0];
}
function getDevType(section_id) {
var dev = getDevice(section_id),
cfg = uci.get('network', section_id),
type = cfg ? (uci.get('network', section_id, 'type') || 'ethernet') : (dev ? dev.getType() : '');
const dev = getDevice(section_id);
const cfg = uci.get('network', section_id);
const type = cfg ? (uci.get('network', section_id, 'type') || 'ethernet') : (dev ? dev.getType() : '');
switch (type) {
case '':
@@ -1714,9 +1706,9 @@ return view.extend({
o = s.option(form.DummyValue, 'name', _('Device'));
o.modalonly = false;
o.textvalue = function(section_id) {
var dev = getDevice(section_id),
ext = section_id.match(/^dev:/),
icon = render_iface(dev);
const dev = getDevice(section_id);
const ext = section_id.match(/^dev:/);
const icon = render_iface(dev);
if (ext)
icon.querySelector('img').style.opacity = '.5';
@@ -1736,9 +1728,9 @@ return view.extend({
o = s.option(form.DummyValue, 'macaddr', _('MAC Address'));
o.modalonly = false;
o.textvalue = function(section_id) {
var dev = getDevice(section_id),
val = uci.get('network', section_id, 'macaddr'),
mac = dev ? dev.getMAC() : null;
const dev = getDevice(section_id);
const val = uci.get('network', section_id, 'macaddr');
const mac = dev ? dev.getMAC() : null;
return val ? E('strong', {
'data-tooltip': _('The value is overridden by configuration.')
@@ -1748,9 +1740,9 @@ return view.extend({
o = s.option(form.DummyValue, 'mtu', _('MTU'));
o.modalonly = false;
o.textvalue = function(section_id) {
var dev = getDevice(section_id),
val = uci.get('network', section_id, 'mtu'),
mtu = dev ? dev.getMTU() : null;
const dev = getDevice(section_id);
const val = uci.get('network', section_id, 'mtu');
const mtu = dev ? dev.getMTU() : null;
return val ? E('strong', {
'data-tooltip': _('The value is overridden by configuration.')
@@ -1790,7 +1782,7 @@ return view.extend({
o.default = '1';
o.optional = true;
var steer_flow = uci.get('network', 'globals', 'steering_flows');
const steer_flow = uci.get('network', 'globals', 'steering_flows');
o = s.option(form.Value, 'steering_flows', _('Steering flows (<abbr title="Receive Packet Steering">RPS</abbr>)'),
_('Directs packet flows to specific CPUs where the local socket owner listens (the local service).') + ' ' +
@@ -1851,7 +1843,7 @@ return view.extend({
o = s.option(form.ListValue, 'ds_snr_offset', _('Downstream SNR offset'));
o.default = '0';
for (var i = -100; i <= 100; i += 5)
for (let i = -100; i <= 100; i += 5)
o.value(i, _('%.1f dB').format(i / 10));
}
@@ -1868,18 +1860,18 @@ return view.extend({
s.addbtntitle = _('Add ATM Bridge');
s.handleAdd = function(ev) {
var sections = uci.sections('network', 'atm-bridge'),
max_unit = -1;
const sections = uci.sections('network', 'atm-bridge');
let max_unit = -1;
for (var i = 0; i < sections.length; i++) {
var unit = +sections[i].unit;
for (let s of sections) {
const unit = +s.unit;
if (!isNaN(unit) && unit > max_unit)
max_unit = unit;
}
return this.map.save(function() {
var sid = uci.add('network', 'atm-bridge');
const sid = uci.add('network', 'atm-bridge');
uci.set('network', sid, 'unit', max_unit + 1);
uci.set('network', sid, 'atmdev', 0);
@@ -1911,24 +1903,24 @@ return view.extend({
return m.render().then(L.bind(function(m, nodes) {
poll.add(L.bind(function() {
var section_ids = m.children[0].cfgsections(),
tasks = [];
const section_ids = m.children[0].cfgsections();
const tasks = [];
for (var i = 0; i < section_ids.length; i++) {
var row = nodes.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(section_ids[i])),
dsc = row.querySelector('[data-name="_ifacestat"] > div'),
btn1 = row.querySelector('.cbi-section-actions .reconnect'),
btn2 = row.querySelector('.cbi-section-actions .down');
for (let sid of section_ids) {
const row = nodes.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid));
const dsc = row.querySelector('[data-name="_ifacestat"] > div');
const btn1 = row.querySelector('.cbi-section-actions .reconnect');
const btn2 = row.querySelector('.cbi-section-actions .down');
if (dsc.getAttribute('reconnect') == '') {
dsc.setAttribute('reconnect', '1');
tasks.push(fs.exec('/sbin/ifup', [section_ids[i]]).catch(function(e) {
tasks.push(fs.exec('/sbin/ifup', [sid]).catch(function(e) {
ui.addNotification(null, E('p', e.message));
}));
}
else if (dsc.getAttribute('disconnect') == '') {
dsc.setAttribute('disconnect', '1');
tasks.push(fs.exec('/sbin/ifdown', [section_ids[i]]).catch(function(e) {
tasks.push(fs.exec('/sbin/ifdown', [sid]).catch(function(e) {
ui.addNotification(null, E('p', e.message));
}));
}

View File

@@ -5,22 +5,21 @@
'require form';
'require network';
'require tools.widgets as widgets';
'require tools.network as tn';
'require tools.network as nettools';
return view.extend({
load: function() {
load() {
return Promise.all([
network.getDevices(),
fs.lines('/etc/iproute2/rt_tables')
]);
},
render: function(data) {
var netDevs = data[0],
m, s, o;
render([netDevs, rtTables]) {
let m, s, o;
var rtTables = data[1].map(function(l) {
var m = l.trim().match(/^(\d+)\s+(\S+)$/);
rtTables = rtTables.map(function(l) {
const m = l.trim().match(/^(\d+)\s+(\S+)$/);
return m ? [ +m[1], m[2] ] : null;
}).filter(function(e) {
return e && e[0] > 0;
@@ -31,7 +30,7 @@ return view.extend({
'<br/>' + _('Rules determine which routing table to use, based on conditions like source address or interface.'));
m.tabbed = true;
for (var family = 4; family <= 6; family += 2) {
for (let family = 4; family <= 6; family += 2) {
s = m.section(form.GridSection, (family == 6) ? 'route6' : 'route', (family == 6) ? _('Static IPv6 Routes') : _('Static IPv4 Routes'));
s.anonymous = true;
s.addremove = true;
@@ -64,11 +63,11 @@ return view.extend({
o.datatype = (family == 6) ? 'cidr6' : 'cidr4';
o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0';
o.cfgvalue = function(section_id) {
var section_type = uci.get('network', section_id, '.type'),
target = uci.get('network', section_id, 'target'),
mask = uci.get('network', section_id, 'netmask'),
v6 = (section_type == 'route6') ? true : false,
bits = mask ? network.maskToPrefix(mask, v6) : (v6 ? 128 : 32);
const section_type = uci.get('network', section_id, '.type');
const target = uci.get('network', section_id, 'target');
const mask = uci.get('network', section_id, 'netmask');
const v6 = (section_type == 'route6') ? true : false;
const bits = mask ? network.maskToPrefix(mask, v6) : (v6 ? 128 : 32);
if (target) {
return target.split('/')[1] ? target : target + '/' + bits;
}
@@ -98,8 +97,8 @@ return view.extend({
_('A numeric table index, or symbol alias declared in %s. Special aliases local (255), main (254) and default (253) are also valid').format('<code>/etc/iproute2/rt_tables</code>')
+ '<br/>' + _('Only interfaces using this table (via override) will use this route.'));
o.datatype = 'or(uinteger, string)';
for (var i = 0; i < rtTables.length; i++)
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
for (let rt of rtTables)
o.value(rt[1], '%s (%d)'.format(rt[1], rt[0]));
o.textvalue = function(section_id) {
return this.cfgvalue(section_id) || E('em', _('auto'));
};
@@ -108,10 +107,10 @@ return view.extend({
+ '<br/>' + _('This is only used if no default route matches the destination gateway'));
o.modalonly = true;
o.datatype = (family == 6) ? 'ip6addr' : 'ip4addr';
for (var i = 0; i < netDevs.length; i++) {
var addrs = (family == 6) ? netDevs[i].getIP6Addrs() : netDevs[i].getIPAddrs();
for (var j = 0; j < addrs.length; j++)
o.value(addrs[j].split('/')[0]);
for (let nd of netDevs) {
const addrs = (family == 6) ? nd.getIP6Addrs() : nd.getIPAddrs();
for (let a of addrs)
o.value(a.split('/')[0]);
}
o = s.taboption('advanced', form.Flag, 'onlink', _('On-link'), _('When enabled, gateway is on-link even if the gateway does not match any interface prefix'));
@@ -124,7 +123,7 @@ return view.extend({
o.default = o.disabled;
}
for (var family = 4; family <= 6; family += 2) {
for (let family = 4; family <= 6; family += 2) {
s = m.section(form.GridSection, (family == 6) ? 'rule6' : 'rule', (family == 6) ? _('IPv6 Rules') : _('IPv4 Rules'));
s.anonymous = true;
s.addremove = true;
@@ -163,7 +162,7 @@ return view.extend({
o = s.taboption('general', form.Value, 'ipproto', _('IP Protocol'), _('Match traffic IP protocol type'));
o.datatype = 'range(0,255)';
tn.protocols.forEach(function(p) {
nettools.protocols.forEach(function(p) {
o.value(p.i, p.d);
});
@@ -182,8 +181,8 @@ return view.extend({
_('A numeric table index, or symbol alias declared in %s. Special aliases local (255), main (254) and default (253) are also valid').format('<code>/etc/iproute2/rt_tables</code>')
+ '<br/>' + _('Matched traffic re-targets to an interface using this table.'));
o.datatype = 'or(uinteger, string)';
for (var i = 0; i < rtTables.length; i++)
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
for (let rt of rtTables)
o.value(rt[1], '%s (%d)'.format(rt[1], rt[0]));
o = s.taboption('advanced', form.Value, 'goto', _('Jump to rule'), _('Jumps to another rule specified by its priority value'));
o.modalonly = true;

View File

@@ -9,10 +9,10 @@
'require network';
function parse_portvalue(section_id) {
var ports = L.toArray(uci.get('network', section_id, 'ports'));
const ports = L.toArray(uci.get('network', section_id, 'ports'));
for (var i = 0; i < ports.length; i++) {
var m = ports[i].match(/^(\d+)([tu]?)/);
for (let p of ports) {
const m = p.match(/^(\d+)([tu]?)/);
if (m && m[1] == this.option)
return m[2] || 'u';
@@ -25,13 +25,13 @@ function validate_portvalue(section_id, value) {
if (value != 'u')
return true;
var sections = this.section.cfgsections();
const sections = this.section.cfgsections();
for (var i = 0; i < sections.length; i++) {
if (sections[i] == section_id)
for (let s of sections) {
if (s == section_id)
continue;
if (this.formvalue(sections[i]) == 'u')
if (this.formvalue(s) == 'u')
return _('%s is untagged in multiple VLANs!').format(this.title);
}
@@ -39,28 +39,28 @@ function validate_portvalue(section_id, value) {
}
function update_interfaces(old_ifname, new_ifname) {
var interfaces = uci.sections('network', 'interface');
const interfaces = uci.sections('network', 'interface');
for (var i = 0; i < interfaces.length; i++) {
var old_ifnames = L.toArray(interfaces[i].ifname),
new_ifnames = [],
changed = false;
for (let intf of interfaces) {
const old_ifnames = L.toArray(intf.ifname);
const new_ifnames = [];
let changed = false;
for (var j = 0; j < old_ifnames.length; j++) {
if (old_ifnames[j] == old_ifname) {
for (let oif of old_ifnames) {
if (oif == old_ifname) {
new_ifnames.push(new_ifname);
changed = true;
}
else {
new_ifnames.push(old_ifnames[j]);
new_ifnames.push(oif);
}
}
if (changed) {
uci.set('network', interfaces[i]['.name'], 'ifname', new_ifnames.join(' '));
uci.set('network', intf['.name'], 'ifname', new_ifnames.join(' '));
ui.addNotification(null, E('p', _('Interface %q device auto-migrated from %q to %q.')
.replace(/%q/g, '"%s"').format(interfaces[i]['.name'], old_ifname, new_ifname)));
.replace(/%q/g, '"%s"').format(intf['.name'], old_ifname, new_ifname)));
}
}
}
@@ -88,27 +88,27 @@ function render_port_status(node, portstate) {
}
function update_port_status(topologies) {
var tasks = [];
const tasks = [];
for (var switch_name in topologies)
for (let switch_name in topologies)
tasks.push(callSwconfigPortState(switch_name).then(L.bind(function(switch_name, ports) {
for (var i = 0; i < ports.length; i++) {
var node = document.querySelector('[data-switch="%s"][data-port="%d"]'.format(switch_name, ports[i].port));
render_port_status(node, ports[i]);
for (let p of ports) {
const node = document.querySelector('[data-switch="%s"][data-port="%d"]'.format(switch_name, p.port));
render_port_status(node, p);
}
}, topologies[switch_name], switch_name)));
return Promise.all(tasks);
}
var callSwconfigFeatures = rpc.declare({
const callSwconfigFeatures = rpc.declare({
object: 'luci',
method: 'getSwconfigFeatures',
params: [ 'switch' ],
expect: { '': {} }
});
var callSwconfigPortState = rpc.declare({
const callSwconfigPortState = rpc.declare({
object: 'luci',
method: 'getSwconfigPortState',
params: [ 'switch' ],
@@ -116,11 +116,11 @@ var callSwconfigPortState = rpc.declare({
});
return view.extend({
load: function() {
load() {
return network.getSwitchTopologies().then(function(topologies) {
var tasks = [];
const tasks = [];
for (var switch_name in topologies) {
for (let switch_name in topologies) {
tasks.push(callSwconfigFeatures(switch_name).then(L.bind(function(features) {
this.features = features;
}, topologies[switch_name])));
@@ -133,18 +133,17 @@ return view.extend({
});
},
render: function(topologies) {
var m, s, o;
render(topologies) {
let m, s, o;
m = new form.Map('network', _('Switch'), _('The network ports on this device can be combined to several <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s in which computers can communicate directly with each other. <abbr title=\"Virtual Local Area Network\">VLAN</abbr>s are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network.'));
m = new form.Map('network', _('Switch'), _("The network ports on this device can be combined to several <abbr title='Virtual Local Area Network'>VLAN</abbr>s in which computers can communicate directly with each other. <abbr title='Virtual Local Area Network'>VLAN</abbr>s are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network."));
var switchSections = uci.sections('network', 'switch');
const switchSections = uci.sections('network', 'switch');
for (var i = 0; i < switchSections.length; i++) {
var switchSection = switchSections[i],
sid = switchSection['.name'],
switch_name = switchSection.name || sid,
topology = topologies[switch_name];
for (let switchSection of switchSections) {
const sid = switchSection['.name'];
const switch_name = switchSection.name || sid;
let topology = topologies[switch_name];
if (!topology) {
ui.addNotification(null, _('Switch %q has an unknown topology - the VLAN settings might not be accurate.').replace(/%q/, switch_name));
@@ -165,12 +164,11 @@ return view.extend({
};
}
var feat = topology.features,
min_vid = feat.min_vid || 0,
max_vid = feat.max_vid || 16,
num_vlans = feat.num_vlans || 16,
switch_title = _('Switch %q').replace(/%q/, '"%s"'.format(switch_name)),
vlan_title = _('VLANs on %q').replace(/%q/, '"%s"'.format(switch_name));
const feat = topology.features;
const min_vid = feat.min_vid || 0;
const num_vlans = feat.num_vlans || 16;
let switch_title = _('Switch %q').replace(/%q/, '"%s"'.format(switch_name));
let vlan_title = _('VLANs on %q').replace(/%q/, '"%s"'.format(switch_name));
if (feat.switch_title) {
switch_title += ' (%s)'.format(feat.switch_title);
@@ -200,8 +198,8 @@ return view.extend({
s.option(form.Flag, 'enable_mirror_rx', _('Enable mirroring of incoming packets'));
s.option(form.Flag, 'enable_mirror_tx', _('Enable mirroring of outgoing packets'));
var sp = s.option(form.ListValue, 'mirror_source_port', _('Mirror source port')),
mp = s.option(form.ListValue, 'mirror_monitor_port', _('Mirror monitor port'));
const sp = s.option(form.ListValue, 'mirror_source_port', _('Mirror source port'));
const mp = s.option(form.ListValue, 'mirror_monitor_port', _('Mirror monitor port'));
sp.depends('enable_mirror_rx', '1');
sp.depends('enable_mirror_tx', '1');
@@ -209,9 +207,9 @@ return view.extend({
mp.depends('enable_mirror_rx', '1');
mp.depends('enable_mirror_tx', '1');
for (var j = 0; j < topology.ports.length; j++) {
sp.value(topology.ports[j].num, topology.ports[j].label);
mp.value(topology.ports[j].num, topology.ports[j].label);
for (let tp of topology.ports) {
sp.value(tp.num, tp.label);
mp.value(tp.num, tp.label);
}
}
@@ -223,16 +221,16 @@ return view.extend({
s.device = switch_name;
s.filter = function(section_id) {
var device = uci.get('network', section_id, 'device');
const device = uci.get('network', section_id, 'device');
return (device == this.device);
};
s.cfgsections = function() {
var sections = form.TableSection.prototype.cfgsections.apply(this);
const sections = form.TableSection.prototype.cfgsections.apply(this);
return sections.sort(function(a, b) {
var vidA = feat.vid_option ? uci.get('network', a, feat.vid_option) : null,
vidB = feat.vid_option ? uci.get('network', b, feat.vid_option) : null;
let vidA = feat.vid_option ? uci.get('network', a, feat.vid_option) : null;
let vidB = feat.vid_option ? uci.get('network', b, feat.vid_option) : null;
vidA = +(vidA != null ? vidA : uci.get('network', a, 'vlan') || 9999);
vidB = +(vidB != null ? vidB : uci.get('network', b, 'vlan') || 9999);
@@ -242,17 +240,17 @@ return view.extend({
};
s.handleAdd = function(ev) {
var sections = uci.sections('network', 'switch_vlan'),
section_id = uci.add('network', 'switch_vlan'),
max_vlan = 0,
max_vid = 0;
const sections = uci.sections('network', 'switch_vlan');
const section_id = uci.add('network', 'switch_vlan');
let max_vlan = 0;
let max_vid = 0;
for (var j = 0; j < sections.length; j++) {
if (sections[j].device != this.device)
for (let s of sections) {
if (s.device != this.device)
continue;
var vlan = +sections[j].vlan,
vid = feat.vid_option ? +sections[j][feat.vid_option] : null;
const vlan = +s.vlan;
const vid = feat.vid_option ? +s[feat.vid_option] : null;
if (vlan > max_vlan)
max_vlan = vlan;
@@ -278,34 +276,34 @@ return view.extend({
o.description = _('Port status:');
o.validate = function(section_id, value) {
var v = +value,
m = feat.vid_option ? 4094 : num_vlans - 1;
const v = +value;
const m = feat.vid_option ? 4094 : num_vlans - 1;
if (isNaN(v) || v < min_vid || v > m)
return _('Invalid VLAN ID given! Only IDs between %d and %d are allowed.').format(min_vid, m);
var sections = this.section.cfgsections();
const sections = this.section.cfgsections();
for (var i = 0; i < sections.length; i++) {
if (sections[i] == section_id)
for (let s of sections) {
if (s == section_id)
continue;
if (this.formvalue(sections[i]) == v)
if (this.formvalue(s) == v)
return _('Invalid VLAN ID given! Only unique IDs are allowed');
}
return true;
};
var port_opts = o.port_opts = [];
const port_opts = o.port_opts = [];
o.write = function(section_id, value) {
var topology = this.section.topology,
values = [];
const topology = this.section.topology;
const values = [];
for (var i = 0; i < this.port_opts.length; i++) {
var tagging = this.port_opts[i].formvalue(section_id),
portspec = Array.isArray(topology.ports) ? topology.ports[i] : null;
for (let i = 0; i < this.port_opts.length; i++) {
const tagging = this.port_opts[i].formvalue(section_id);
const portspec = Array.isArray(topology.ports) ? topology.ports[i] : null;
if (tagging == 't')
values.push(this.port_opts[i].option + tagging);
@@ -313,12 +311,12 @@ return view.extend({
values.push(this.port_opts[i].option);
if (portspec && portspec.device) {
var old_tag = this.port_opts[i].cfgvalue(section_id),
old_vid = this.cfgvalue(section_id);
const old_tag = this.port_opts[i].cfgvalue(section_id);
const old_vid = this.cfgvalue(section_id);
if (old_tag != tagging || old_vid != value) {
var old_ifname = portspec.device + (old_tag != 'u' ? '.' + old_vid : ''),
new_ifname = portspec.device + (tagging != 'u' ? '.' + value : '');
const old_ifname = portspec.device + (old_tag != 'u' ? '.' + old_vid : '');
const new_ifname = portspec.device + (tagging != 'u' ? '.' + value : '');
if (old_ifname != new_ifname)
update_interfaces(old_ifname, new_ifname);
@@ -335,15 +333,15 @@ return view.extend({
};
o.cfgvalue = function(section_id) {
var value = feat.vid_option ? uci.get('network', section_id, feat.vid_option) : null;
const value = feat.vid_option ? uci.get('network', section_id, feat.vid_option) : null;
return (value || uci.get('network', section_id, 'vlan'));
};
s.option(form.Value, 'description', _('Description'));
for (var j = 0; Array.isArray(topology.ports) && j < topology.ports.length; j++) {
var portspec = topology.ports[j],
portstate = Array.isArray(topology.portstate) ? topology.portstate[portspec.num] : null;
for (let j = 0; Array.isArray(topology.ports) && j < topology.ports.length; j++) {
const portspec = topology.ports[j];
const portstate = Array.isArray(topology.portstate) ? topology.portstate[portspec.num] : null;
o = s.option(form.ListValue, String(portspec.num), portspec.label);
o.value('', _('off'));

View File

@@ -1867,7 +1867,7 @@ return view.extend({
const has_80211r = L.hasSystemFeature('hostapd', '11r') || L.hasSystemFeature('hostapd', 'eap');
o = ss.taboption('roaming', form.Flag, 'ieee80211r', _('802.11r Fast Transition'), _('Enables fast roaming among access points that belong to the same Mobility Domain'));
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa2', 'wpa3', 'wpa3-mixed', , 'wpa3-192'] });
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa2', 'wpa3', 'wpa3-mixed', 'wpa3-192'] });
if (has_80211r)
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk2', 'psk-mixed', 'sae', 'sae-mixed'] });
o.rmempty = true;

View File

@@ -44,7 +44,6 @@ return view.extend({
const data_wanted = Math.floor(width / step);
const data_values = [];
const line_elements = [];
for (const line of lines)
if (line)
@@ -244,10 +243,10 @@ return view.extend({
render([svg, devs]) {
var v = E('div', { 'class': 'cbi-map', 'id': 'map' }, E('div'));
const v = E('div', { 'class': 'cbi-map', 'id': 'map' }, E('div'));
for (const dev of devs) {
var ifname = dev.getName();
const ifname = dev.getName();
const ssid = dev.wif?.getSSID?.() || null;
if (!ifname || !dev.isUp() || dev.wif?.isDisabled())

View File

@@ -8,22 +8,22 @@
'require tools.prng as random';
return view.extend({
callFrequencyList : rpc.declare({
callFrequencyList: rpc.declare({
object: 'iwinfo',
method: 'freqlist',
params: [ 'device' ],
expect: { results: [] }
}),
callInfo : rpc.declare({
callInfo: rpc.declare({
object: 'iwinfo',
method: 'info',
params: [ 'device' ],
expect: { }
}),
render_signal_badge: function(signalPercent, signalValue) {
var icon, title, value;
render_signal_badge(signalPercent, signalValue) {
let icon, title, value;
if (signalPercent < 0)
icon = L.resource('icons/signal-none.svg');
@@ -51,7 +51,7 @@ return view.extend({
]);
},
add_wifi_to_graph: function(chan_analysis, res, scanCache, channels, channel_width) {
add_wifi_to_graph(chan_analysis, res, scanCache, channels, channel_width) {
const offset_tbl = chan_analysis.offset_tbl;
const height = chan_analysis.graph.offsetHeight - 2;
const step = chan_analysis.col_width;
@@ -112,15 +112,15 @@ return view.extend({
})
},
create_channel_graph: function(chan_analysis, freq_tbl, band) {
var columns = (band != 2) ? freq_tbl.length * 4 : freq_tbl.length + 3,
chan_graph = chan_analysis.graph,
G = chan_graph.firstElementChild,
step = (chan_graph.offsetWidth - 2) / columns,
curr_offset = step;
create_channel_graph(chan_analysis, freq_tbl, band) {
const columns = (band != 2) ? freq_tbl.length * 4 : freq_tbl.length + 3;
const chan_graph = chan_analysis.graph;
const G = chan_graph.firstElementChild;
const step = (chan_graph.offsetWidth - 2) / columns;
let curr_offset = step;
function createGraphHLine(graph, pos, width, dash) {
var elem = document.createElementNS('http://www.w3.org/2000/svg', 'line');
const elem = document.createElementNS('http://www.w3.org/2000/svg', 'line');
elem.setAttribute('x1', pos);
elem.setAttribute('y1', 0);
elem.setAttribute('x2', pos);
@@ -130,7 +130,7 @@ return view.extend({
}
function createGraphText(graph, pos, text) {
var elem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
const elem = document.createElementNS('http://www.w3.org/2000/svg', 'text');
elem.setAttribute('y', 15);
elem.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
elem.setAttribute('x', pos + 5);
@@ -141,8 +141,8 @@ return view.extend({
chan_analysis.col_width = step;
createGraphHLine(G,curr_offset, 0.1, 1);
for (var i=0; i< freq_tbl.length;i++) {
var channel = freq_tbl[i]
for (let i=0; i< freq_tbl.length;i++) {
const channel = freq_tbl[i]
chan_analysis.offset_tbl[channel] = curr_offset+step;
if (band != 2) {
@@ -158,10 +158,10 @@ return view.extend({
curr_offset += step;
if ((band != 2) && freq_tbl[i+1]) {
var next_channel = freq_tbl[i+1];
const next_channel = freq_tbl[i+1];
/* Check if we are transitioning to another 5/6Ghz band range */
if ((next_channel - channel) == 4) {
for (var j=1; j < 4; j++) {
for (let j=1; j < 4; j++) {
chan_analysis.offset_tbl[channel+j] = curr_offset+step;
if (j == 2)
createGraphHLine(G,curr_offset+step, 0.1, 0);
@@ -193,31 +193,30 @@ return view.extend({
}, this));
},
handleScanRefresh: function() {
handleScanRefresh() {
if (!this.active_tab)
return;
var radio = this.radios[this.active_tab];
const radio = this.radios[this.active_tab];
let q;
return Promise.all([
radio.dev.getScanList(),
this.callInfo(radio.dev.getName())
]).then(L.bind(function(data) {
var results = data[0],
local_wifi = data[1],
table = radio.table,
chan_analysis = radio.graph,
scanCache = radio.scanCache,
band = radio.band;
]).then(L.bind(function([results, local_wifi]) {
const table = radio.table;
const chan_analysis = radio.graph;
const scanCache = radio.scanCache;
const band = radio.band;
var rows = [];
const rows = [];
for (var i = 0; i < results.length; i++) {
if (scanCache[results[i].bssid] == null)
scanCache[results[i].bssid] = {};
for (let res of results) {
if (scanCache[res.bssid] == null)
scanCache[res.bssid] = {};
scanCache[results[i].bssid].data = results[i];
scanCache[results[i].bssid].data.stale = false;
scanCache[res.bssid].data = res;
scanCache[res.bssid].data.stale = false;
}
if (band + 'g' == radio.dev.get('band')) {
@@ -227,9 +226,9 @@ return view.extend({
scanCache[local_wifi.bssid].data = local_wifi;
if (chan_analysis.offset_tbl[local_wifi.channel] != null && local_wifi.center_chan1) {
var center_channels = [local_wifi.center_chan1],
chan_width_text = local_wifi.htmode.replace(/[EV]*H[TE]/,''), /* Handle HT VHT HE EHT */
chan_width = parseInt(chan_width_text)/10;
const center_channels = [local_wifi.center_chan1];
const chan_width_text = local_wifi.htmode.replace(/[EV]*H[TE]/,''); /* Handle HT VHT HE EHT */
let chan_width = parseInt(chan_width_text)/10;
if (local_wifi.center_chan2) {
center_channels.push(local_wifi.center_chan2);
@@ -254,7 +253,7 @@ return view.extend({
}
}
for (var k in scanCache)
for (let k in scanCache)
if (scanCache[k].data.stale)
results.push(scanCache[k].data);
@@ -273,14 +272,13 @@ return view.extend({
return 1;
});
for (var i = 0; i < results.length; i++) {
var res = results[i],
qv = res.quality || 0,
qm = res.quality_max || 0,
q = (qv > 0 && qm > 0) ? Math.floor((100 / qm) * qv) : 0,
s = res.stale ? 'opacity:0.5' : '',
center_channels = [res.channel],
chan_width = 2;
for (let res of results) {
const qv = res.quality || 0;
const qm = res.quality_max || 0;
q = (qv > 0 && qm > 0) ? Math.floor((100 / qm) * qv) : 0;
const s = res.stale ? 'opacity:0.5' : '';
const center_channels = [res.channel];
let chan_width = 2;
/* Skip WiFi not supported by the current band */
if (band != res.band)
@@ -319,7 +317,7 @@ return view.extend({
/* If needed, adjust based on the 802.11ac Wave 2 interop workaround. */
if (res.vht_operation.center_freq_2) {
var diff = Math.abs(res.vht_operation.center_freq_2 -
const diff = Math.abs(res.vht_operation.center_freq_2 -
res.vht_operation.center_freq_1);
if (diff == 8) {
@@ -370,7 +368,7 @@ return view.extend({
rows.push([
E('span', { 'style': s }, this.render_signal_badge(q, res.signal)),
E('span', { 'style': s }, [
E('span', { 'style': 'color:'+scanCache[results[i].bssid].color }, '⬤ '),
E('span', { 'style': 'color:'+scanCache[res.bssid].color }, '⬤ '),
(res.ssid != null) ? '%h'.format(res.ssid) : E('em', _('hidden'))
]),
E('span', { 'style': s }, '%d'.format(res.channel)),
@@ -379,7 +377,7 @@ return view.extend({
E('span', { 'style': s }, '%h'.format(res.bssid))
]);
scanCache[results[i].bssid].data.stale = true;
scanCache[res.bssid].data.stale = true;
}
cbi_update_table(table, rows);
@@ -391,9 +389,9 @@ return view.extend({
}, this))
},
radios : {},
radios: {},
loadSVG : function(src) {
loadSVG(src) {
return request.get(src).then(function(response) {
if (!response.ok)
throw new Error(response.statusText);
@@ -405,19 +403,19 @@ return view.extend({
});
},
load: function() {
load() {
return Promise.all([
this.loadSVG(L.resource('svg/channel_analysis.svg')),
network.getWifiDevices().then(L.bind(function(data) {
var tasks = [], ret = [];
const tasks = [], ret = [];
for (var i = 0; i < data.length; i++) {
ret[data[i].getName()] = { dev : data[i] };
for (let d of data) {
ret[d.getName()] = { dev : d };
tasks.push(this.callFrequencyList(data[i].getName())
tasks.push(this.callFrequencyList(d.getName())
.then(L.bind(function(radio, data) {
ret[radio.getName()].freq = data;
}, this, data[i])));
}, this, d)));
}
return Promise.all(tasks).then(function() { return ret; })
@@ -425,11 +423,8 @@ return view.extend({
]);
},
render: function(data) {
var svg = data[0],
wifiDevs = data[1];
var h2 = E('div', {'class' : 'cbi-title-section'}, [
render([svg, wifiDevs]) {
const h2 = E('div', {'class' : 'cbi-title-section'}, [
E('h2', {'class': 'cbi-title-field'}, [ _('Channel Analysis') ]),
E('div', {'class': 'cbi-title-buttons' }, [
E('button', {
@@ -438,10 +433,10 @@ return view.extend({
}, [ _('Refresh Channels') ])])
]);
var tabs = E('div', {}, E('div'));
const tabs = E('div', {}, E('div'));
for (var ifname in wifiDevs) {
var bands = {
for (let ifname in wifiDevs) {
const bands = {
[2] : { title: '2.4GHz', channels: [] },
[5] : { title: '5GHz', channels: [] },
[6] : { title: '6GHz', channels: [] },
@@ -453,12 +448,12 @@ return view.extend({
bands[freq.band].channels.push(freq.channel);
});
for (var band in bands) {
for (let band in bands) {
if (bands[band].channels.length == 0)
continue;
var csvg = svg.cloneNode(true),
table = E('table', { 'class': 'table' }, [
const csvg = svg.cloneNode(true);
const table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th col-2 middle center' }, _('Signal')),
E('th', { 'class': 'th col-4 middle left' }, _('SSID')),

View File

@@ -5,107 +5,106 @@
'require rpc';
'require fs';
var callLuciRealtimeStats = rpc.declare({
const callLuciRealtimeStats = rpc.declare({
object: 'luci',
method: 'getRealtimeStats',
params: [ 'mode', 'device' ],
expect: { result: [] }
});
var callLuciConntrackList = rpc.declare({
const callLuciConntrackList = rpc.declare({
object: 'luci',
method: 'getConntrackList',
expect: { result: [] }
});
var callNetworkRrdnsLookup = rpc.declare({
const callNetworkRrdnsLookup = rpc.declare({
object: 'network.rrdns',
method: 'lookup',
params: [ 'addrs', 'timeout', 'limit' ],
expect: { '': {} }
});
var callLuciRpcGetHostHints = rpc.declare({
const callLuciRpcGetHostHints = rpc.declare({
object: 'luci-rpc',
method: 'getHostHints',
expect: { '': {} }
});
var callLuciRpcGetNetworkDevices = rpc.declare({
const callLuciRpcGetNetworkDevices = rpc.declare({
object: 'luci-rpc',
method: 'getNetworkDevices',
expect: { '': {} }
});
var callLuciRpcGetDHCPLeases = rpc.declare({
const callLuciRpcGetDHCPLeases = rpc.declare({
object: 'luci-rpc',
method: 'getDHCPLeases',
expect: { '': {} }
});
var graphPolls = [],
pollInterval = 3,
dns_cache = Object.create(null),
service_cache = Object.create(null),
ethers_cache = Object.create(null),
ethers_cache_is_loaded = false,
enableLookups = false,
filterText = '';
const graphPolls = [];
const pollInterval = 3;
const dns_cache = Object.create(null);
const service_cache = Object.create(null);
const ethers_cache = Object.create(null);
let ethers_cache_is_loaded = false;
let enableLookups = false;
let filterText = '';
var recheck_lookup_queue = {};
const recheck_lookup_queue = {};
Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; };
return view.extend({
load: function() {
load() {
return Promise.all([
this.loadSVG(L.resource('svg/connections.svg'))
]);
},
updateGraph: function(svg, lines, cb) {
var G = svg.firstElementChild;
updateGraph(svg, lines, cb) {
const G = svg.firstElementChild;
var view = document.querySelector('#view');
const view = document.querySelector('#view');
var width = view.offsetWidth - 2;
var height = 300 - 2;
var step = 5;
const width = view.offsetWidth - 2;
const height = 300 - 2;
const step = 5;
var data_wanted = Math.floor(width / step);
const data_wanted = Math.floor(width / step);
var data_values = [],
line_elements = [];
const data_values = [];
for (var i = 0; i < lines.length; i++)
if (lines[i] != null)
for (let line of lines)
if (line != null)
data_values.push([]);
var info = {
const info = {
line_current: [],
line_average: [],
line_peak: []
};
/* prefill datasets */
for (var i = 0; i < data_values.length; i++)
for (var j = 0; j < data_wanted; j++)
data_values[i][j] = 0;
for (let dv of data_values)
for (let j = 0; j < data_wanted; j++)
dv[j] = 0;
/* plot horizontal time interval lines */
for (var i = width % (step * 60); i < width; i += step * 60) {
var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
for (let i = width % (step * 60); i < width; i += step * 60) {
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(document.createTextNode(Math.round((width - i) / step / 60) + 'm'));
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(document.createTextNode(Math.round((width - i) / step / 60) + 'm'));
G.appendChild(line);
G.appendChild(text);
@@ -128,7 +127,7 @@ return view.extend({
});
},
updateConntrack: async function(conn) {
async updateConntrack(conn) {
async function fetchServices() {
if (!enableLookups) return;
if (Object.keys(service_cache).length > 0) return;
@@ -283,38 +282,37 @@ return view.extend({
}
},
pollData: async function() {
async pollData() {
poll.add(L.bind(async function() {
var tasks = [
const tasks = [
L.resolveDefault(callLuciConntrackList(), [])
];
for (var i = 0; i < graphPolls.length; i++) {
var ctx = graphPolls[i];
graphPolls.forEach(() => {
tasks.push(L.resolveDefault(callLuciRealtimeStats('conntrack'), []));
}
});
const datasets = await Promise.all(tasks);
await this.updateConntrack(datasets[0]);
for (var gi = 0; gi < graphPolls.length; gi++) {
var ctx = graphPolls[gi],
data = datasets[gi + 1],
values = ctx.values,
lines = ctx.lines,
info = ctx.info;
for (let gi = 0; gi < graphPolls.length; gi++) {
const ctx = graphPolls[gi];
const data = datasets[gi + 1];
const values = ctx.values;
const lines = ctx.lines;
const info = ctx.info;
var data_scale = 0;
var data_wanted = Math.floor(ctx.width / ctx.step);
var last_timestamp = NaN;
let data_scale = 0;
let data_wanted = Math.floor(ctx.width / ctx.step);
let last_timestamp = NaN;
for (var i = 0, di = 0; di < lines.length; di++) {
for (let i = 0, di = 0; di < lines.length; di++) {
if (lines[di] == null)
continue;
var multiply = (lines[di].multiply != null) ? lines[di].multiply : 1,
offset = (lines[di].offset != null) ? lines[di].offset : 0;
const multiply = (lines[di].multiply != null) ? lines[di].multiply : 1;
const offset = (lines[di].offset != null) ? lines[di].offset : 0;
for (var j = ctx.timestamp ? 0 : 1; j < data.length; j++) {
for (let j = ctx.timestamp ? 0 : 1; j < data.length; j++) {
/* skip overlapping entries */
if (data[j][0] <= ctx.timestamp)
continue;
@@ -335,15 +333,15 @@ return view.extend({
/* cut off outdated entries */
ctx.fill = Math.min(ctx.fill, data_wanted);
for (var i = 0; i < values.length; i++) {
var len = values[i].length;
for (let i = 0; i < values.length; i++) {
const len = values[i].length;
values[i] = values[i].slice(len - data_wanted, len);
/* find peaks, averages */
info.line_peak[i] = NaN;
info.line_average[i] = 0;
for (var j = 0; j < values[i].length; j++) {
for (let j = 0; j < values[i].length; j++) {
info.line_peak[i] = isNaN(info.line_peak[i]) ? values[i][j] : Math.max(info.line_peak[i], values[i][j]);
info.line_average[i] += values[i][j];
}
@@ -357,29 +355,29 @@ return view.extend({
if (!isNaN(last_timestamp))
ctx.timestamp = last_timestamp;
var size = Math.floor(Math.log2(info.peak)),
div = Math.pow(2, size - (size % 10)),
mult = info.peak / div,
mult = (mult < 5) ? 2 : ((mult < 50) ? 10 : ((mult < 500) ? 100 : 1000));
const size = Math.floor(Math.log2(info.peak));
const div = Math.pow(2, size - (size % 10));
let mult = info.peak / div;
mult = (mult < 5) ? 2 : ((mult < 50) ? 10 : ((mult < 500) ? 100 : 1000));
info.peak = info.peak + (mult * div) - (info.peak % (mult * div));
data_scale = ctx.height / info.peak;
/* plot data */
for (var i = 0, di = 0; di < lines.length; di++) {
for (let i = 0, di = 0; di < lines.length; di++) {
if (lines[di] == null)
continue;
var el = ctx.svg.firstElementChild.getElementById(lines[di].line),
pt = '0,' + ctx.height,
y = 0;
const el = ctx.svg.firstElementChild.getElementById(lines[di].line);
let pt = '0,' + ctx.height;
let y = 0;
if (!el)
continue;
for (var j = 0; j < values[i].length; j++) {
var x = j * ctx.step;
for (let j = 0; j < values[i].length; j++) {
let x = j * ctx.step;
y = ctx.height - Math.floor(values[i][j] * data_scale);
//y -= Math.floor(y % (1 / data_scale));
@@ -406,7 +404,7 @@ return view.extend({
}, this), pollInterval);
},
loadSVG: function(src) {
loadSVG(src) {
return request.get(src).then(function(response) {
if (!response.ok)
throw new Error(response.statusText);
@@ -417,10 +415,9 @@ return view.extend({
});
},
render: function(data) {
var svg = data[0];
render([svg]) {
var v = E('div', { 'class': 'cbi-map', 'id': 'map' }, [
const v = E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('h2', _('Connections')),
E('div', {'class': 'cbi-map-descr'}, _('This page displays the active connections via this device.')),
E('div', { 'class': 'cbi-section' }, [
@@ -527,7 +524,7 @@ return view.extend({
]);
this.updateGraph(svg, [ { line: 'udp' }, { line: 'tcp' }, { line: 'other' } ], function(svg, info) {
var G = svg.firstElementChild, tab = svg.parentNode;
const G = svg.firstElementChild, tab = svg.parentNode;
G.getElementById('label_25').firstChild.data = '%d'.format(info.label_25);
G.getElementById('label_50').firstChild.data = '%d'.format(info.label_50);

View File

@@ -35,7 +35,7 @@ return view.extend({
*/
],
retrieveLog: async function() {
async retrieveLog() {
return fs.exec_direct('/bin/dmesg', [ '-r' ]).then(logdata => {
let loglines = [];
let lastSeverity = null;
@@ -113,7 +113,7 @@ return view.extend({
});
},
pollLog: async function() {
async pollLog() {
const element = document.getElementById('syslog');
if (element) {
const log = await this.retrieveLog();
@@ -122,12 +122,12 @@ return view.extend({
}
},
load: async function() {
async load() {
poll.add(this.pollLog.bind(this));
return await this.retrieveLog();
},
render: function(loglines) {
render(loglines) {
const scrollDownButton = E('button', {
'id': 'scrollDownButton',
'class': 'cbi-button cbi-button-neutral',
@@ -193,7 +193,7 @@ return view.extend({
'id': 'logSeveritySelect',
'class': 'cbi-input-select',
},
this.severity.map(([val, tag, label]) =>
this.severity.map(([val, , label]) =>
E('option', { value: val }, label)
));

View File

@@ -7,7 +7,7 @@
'require network';
'require firewall';
var callGetBuiltinEthernetPorts = rpc.declare({
const callGetBuiltinEthernetPorts = rpc.declare({
object: 'luci',
method: 'getBuiltinEthernetPorts',
expect: { result: [] }
@@ -28,7 +28,7 @@ function isString(v)
function resolveVLANChain(ifname, bridges, mapping)
{
while (!mapping[ifname]) {
var m = ifname.match(/^(.+)\.([^.]+)$/);
const m = ifname.match(/^(.+)\.([^.]+)$/);
if (!m)
break;
@@ -52,24 +52,24 @@ function resolveVLANChain(ifname, bridges, mapping)
function buildVLANMappings(mapping)
{
var bridge_vlans = uci.sections('network', 'bridge-vlan'),
vlan_devices = uci.sections('network', 'device'),
interfaces = uci.sections('network', 'interface'),
bridges = {};
const bridge_vlans = uci.sections('network', 'bridge-vlan');
const vlan_devices = uci.sections('network', 'device');
const interfaces = uci.sections('network', 'interface');
const bridges = {};
/* find bridge VLANs */
for (var i = 0, s; (s = bridge_vlans[i]) != null; i++) {
for (let i = 0, s; (s = bridge_vlans[i]) != null; i++) {
if (!isString(s.device) || !/^[0-9]{1,4}$/.test(s.vlan) || +s.vlan > 4095)
continue;
var aliases = L.toArray(s.alias),
ports = L.toArray(s.ports),
br = bridges[s.device] = (bridges[s.device] || { ports: [], vlans: {}, vlan_filtering: true });
const aliases = L.toArray(s.alias);
const ports = L.toArray(s.ports);
const br = bridges[s.device] = (bridges[s.device] || { ports: [], vlans: {}, vlan_filtering: true });
br.vlans[s.vlan] = [];
for (var j = 0; j < ports.length; j++) {
var port = ports[j].replace(/:[ut*]+$/, '');
for (let p of ports) {
const port = p.replace(/:[ut*]+$/, '');
if (br.ports.indexOf(port) === -1)
br.ports.push(port);
@@ -77,28 +77,28 @@ function buildVLANMappings(mapping)
br.vlans[s.vlan].push(port);
}
for (var j = 0; j < aliases.length; j++)
if (aliases[j] != s.vlan)
br.vlans[aliases[j]] = br.vlans[s.vlan];
for (let a of aliases)
if (a != s.vlan)
br.vlans[a] = br.vlans[s.vlan];
}
/* find bridges, VLAN devices */
for (var i = 0, s; (s = vlan_devices[i]) != null; i++) {
for (let i = 0, s; (s = vlan_devices[i]) != null; i++) {
if (s.type == 'bridge') {
if (!isString(s.name))
continue;
var ports = L.toArray(s.ports),
br = bridges[s.name] || (bridges[s.name] = { ports: [], vlans: {}, vlan_filtering: false });
const ports = L.toArray(s.ports);
const br = bridges[s.name] || (bridges[s.name] = { ports: [], vlans: {}, vlan_filtering: false });
if (s.vlan_filtering == '0')
br.vlan_filtering = false;
else if (s.vlan_filtering == '1')
br.vlan_filtering = true;
for (var j = 0; j < ports.length; j++)
if (br.ports.indexOf(ports[j]) === -1)
br.ports.push(ports[j]);
for (let p of ports)
if (br.ports.indexOf(p) === -1)
br.ports.push(p);
mapping[s.name] = br.ports;
}
@@ -127,17 +127,17 @@ function buildVLANMappings(mapping)
}
/* resolve VLAN tagged interfaces in bridge ports */
for (var brname in bridges) {
for (var i = 0; i < bridges[brname].ports.length; i++)
resolveVLANChain(bridges[brname].ports[i], bridges, mapping);
for (let brname in bridges) {
for (let bp of bridges[brname].ports)
resolveVLANChain(bp, bridges, mapping);
for (var vid in bridges[brname].vlans)
for (var i = 0; i < bridges[brname].vlans[vid].length; i++)
resolveVLANChain(bridges[brname].vlans[vid][i], bridges, mapping);
for (let vid in bridges[brname].vlans)
for (let v of bridges[brname].vlans[vid])
resolveVLANChain(v, bridges, mapping);
}
/* find implicit VLAN devices */
for (var i = 0, s; (s = interfaces[i]) != null; i++) {
for (let i = 0, s; (s = interfaces[i]) != null; i++) {
if (!isString(s.device))
continue;
@@ -147,16 +147,16 @@ function buildVLANMappings(mapping)
function resolveVLANPorts(ifname, mapping, seen)
{
var ports = [];
const ports = [];
if (!seen)
seen = {};
if (mapping[ifname]) {
for (var i = 0; i < mapping[ifname].length; i++) {
if (!seen[mapping[ifname][i]]) {
seen[mapping[ifname][i]] = true;
ports.push.apply(ports, resolveVLANPorts(mapping[ifname][i], mapping, seen));
for (let m of mapping[ifname]) {
if (!seen[m]) {
seen[m] = true;
ports.push.apply(ports, resolveVLANPorts(m, mapping, seen));
}
}
}
@@ -168,47 +168,47 @@ function resolveVLANPorts(ifname, mapping, seen)
}
function buildInterfaceMapping(zones, networks) {
var vlanmap = {},
portmap = {},
netmap = {};
const vlanmap = {};
const portmap = {};
const netmap = {};
buildVLANMappings(vlanmap);
for (var i = 0; i < networks.length; i++) {
var l3dev = networks[i].getDevice();
for (let net of networks) {
const l3dev = net.getDevice();
if (!l3dev)
continue;
var ports = resolveVLANPorts(l3dev.getName(), vlanmap);
const ports = resolveVLANPorts(l3dev.getName(), vlanmap);
for (var j = 0; j < ports.length; j++) {
portmap[ports[j]] = portmap[ports[j]] || { networks: [], zones: [] };
portmap[ports[j]].networks.push(networks[i]);
for (let p of ports) {
portmap[p] = portmap[p] || { networks: [], zones: [] };
portmap[p].networks.push(net);
}
netmap[networks[i].getName()] = networks[i];
netmap[net.getName()] = net;
}
for (var i = 0; i < zones.length; i++) {
var networknames = zones[i].getNetworks();
for (let z of zones) {
const networknames = z.getNetworks();
for (var j = 0; j < networknames.length; j++) {
if (!netmap[networknames[j]])
for (let nn of networknames) {
if (!netmap[nn])
continue;
var l3dev = netmap[networknames[j]].getDevice();
const l3dev = netmap[nn].getDevice();
if (!l3dev)
continue;
var ports = resolveVLANPorts(l3dev.getName(), vlanmap);
const ports = resolveVLANPorts(l3dev.getName(), vlanmap);
for (var k = 0; k < ports.length; k++) {
portmap[ports[k]] = portmap[ports[k]] || { networks: [], zones: [] };
for (let p of ports) {
portmap[p] = portmap[p] || { networks: [], zones: [] };
if (portmap[ports[k]].zones.indexOf(zones[i]) === -1)
portmap[ports[k]].zones.push(zones[i]);
if (portmap[p].zones.indexOf(z) === -1)
portmap[p].zones.push(z);
}
}
}
@@ -218,8 +218,8 @@ function buildInterfaceMapping(zones, networks) {
function formatSpeed(carrier, speed, duplex) {
if ((speed > 0) && duplex) {
var d = (duplex == 'half') ? '\u202f(H)' : '',
e = E('span', { 'title': _('Speed: %d Mbit/s, Duplex: %s').format(speed, duplex) });
const d = (duplex == 'half') ? '\u202f(H)' : '';
const e = E('span', { 'title': _('Speed: %d Mbit/s, Duplex: %s').format(speed, duplex) });
switch (true) {
case (speed < 1000):
@@ -325,8 +325,8 @@ function formatStats(portdev, pse) {
}
function renderNetworkBadge(network, zonename) {
var l3dev = network.getDevice();
var span = E('span', { 'class': 'ifacebadge', 'style': 'margin:.125em 0' }, [
const l3dev = network.getDevice();
const span = E('span', { 'class': 'ifacebadge', 'style': 'margin:.125em 0' }, [
E('span', {
'class': 'zonebadge',
'title': zonename ? _('Part of zone %q').format(zonename) : _('No zone assigned'),
@@ -347,18 +347,18 @@ function renderNetworkBadge(network, zonename) {
}
function renderNetworksTooltip(pmap) {
var res = [ null ],
zmap = {};
const res = [ null ];
const zmap = {};
for (var i = 0; pmap && i < pmap.zones.length; i++) {
var networknames = pmap.zones[i].getNetworks();
for (let pmz of pmap.zones) {
const networknames = pmz.getNetworks();
for (var k = 0; k < networknames.length; k++)
zmap[networknames[k]] = pmap.zones[i].getName();
for (let nn of networknames)
zmap[nn] = pmz.getName();
}
for (var i = 0; pmap && i < pmap.networks.length; i++)
res.push(E('br'), renderNetworkBadge(pmap.networks[i], zmap[pmap.networks[i].getName()]));
for (let pmn of pmap.networks)
res.push(E('br'), renderNetworkBadge(pmn, zmap[pmn.getName()]));
if (res.length > 1)
res[0] = N_((res.length - 1) / 2, 'Part of network:', 'Part of networks:');
@@ -371,7 +371,7 @@ function renderNetworksTooltip(pmap) {
return baseclass.extend({
title: _('Port status'),
load: function() {
load() {
return Promise.all([
L.resolveDefault(callGetBuiltinEthernetPorts(), []),
L.resolveDefault(fs.read('/etc/board.json'), '{}'),
@@ -421,7 +421,7 @@ return baseclass.extend({
});
},
render: function(data) {
render(data) {
if (L.hasSystemFeature('swconfig'))
return null;
@@ -438,7 +438,7 @@ return baseclass.extend({
}
else {
if (L.isObject(board) && L.isObject(board.network)) {
for (var k = 'lan'; k != null; k = (k == 'lan') ? 'wan' : null) {
for (let k = 'lan'; k != null; k = (k == 'lan') ? 'wan' : null) {
if (!L.isObject(board.network[k]))
continue;

View File

@@ -224,7 +224,6 @@ return baseclass.extend({
},
render(data) {
const seen = {};
const radios = data[0];
const networks = data[1];
const hosthints = data[2];

View File

@@ -4,18 +4,18 @@
'require fs';
'require ui';
var table_names = [ 'Filter', 'NAT', 'Mangle', 'Raw' ],
raw_style = 'font-family:monospace;font-size:smaller;text-align:right';
const table_names = [ 'Filter', 'NAT', 'Mangle', 'Raw' ];
const raw_style = 'font-family:monospace;font-size:smaller;text-align:right';
return view.extend({
load: function() {
load() {
return L.resolveDefault(fs.stat('/usr/sbin/ip6tables'));
},
createTableSection: function(is_ipv6, table) {
var idiv = document.querySelector('div[data-tab="%s"]'.format(is_ipv6 ? 'ip6tables' : 'iptables')),
tdiv = idiv.querySelector('[data-table="%s-%s"]'.format(is_ipv6 ? 'ipv6' : 'ipv4', table)),
title = '%s: %s'.format(_('Table'), table);
createTableSection(is_ipv6, table) {
const idiv = document.querySelector('div[data-tab="%s"]'.format(is_ipv6 ? 'ip6tables' : 'iptables'));
let tdiv = idiv.querySelector('[data-table="%s-%s"]'.format(is_ipv6 ? 'ipv6' : 'ipv4', table));
const title = '%s: %s'.format(_('Table'), table);
if (!tdiv) {
tdiv = E('div', { 'data-table': '%s-%s'.format(is_ipv6 ? 'ipv6' : 'ipv4', table) }, [
@@ -26,10 +26,10 @@ return view.extend({
if (idiv.firstElementChild.nodeName.toLowerCase() === 'p')
idiv.removeChild(idiv.firstElementChild);
var added = false, thisIdx = table_names.indexOf(table);
let added = false, thisIdx = table_names.indexOf(table);
idiv.querySelectorAll('[data-table]').forEach(function(child) {
var childIdx = table_names.indexOf(child.getAttribute('data-table').split(/-/)[1]);
const childIdx = table_names.indexOf(child.getAttribute('data-table').split(/-/)[1]);
if (added === false && childIdx > thisIdx) {
idiv.insertBefore(tdiv, child);
@@ -44,10 +44,10 @@ return view.extend({
return tdiv.lastElementChild;
},
createChainSection: function(is_ipv6, table, chain, policy, packets, bytes, references) {
var tdiv = this.createTableSection(is_ipv6, table),
cdiv = tdiv.querySelector('[data-chain="%s"]'.format(chain)),
title;
createChainSection(is_ipv6, table, chain, policy, packets, bytes, references) {
const tdiv = this.createTableSection(is_ipv6, table);
let cdiv = tdiv.querySelector('[data-chain="%s"]'.format(chain));
let title;
if (policy)
title = '%s <em>%s</em> <span>(%s: <em>%s</em>, %d %s, %.2mB %s)</span>'
@@ -84,14 +84,13 @@ return view.extend({
return cdiv.lastElementChild;
},
updateChainSection: function(chaintable, rows) {
updateChainSection(chaintable, rows) {
if (!chaintable)
return;
cbi_update_table(chaintable, rows, _('No rules in this chain.'));
if (rows.length === 0 &&
document.querySelector('[data-hide-empty="true"]'))
if (rows.length === 0 && document.querySelector('[data-hide-empty="true"]'))
chaintable.parentNode.style.display = 'none';
else
chaintable.parentNode.style.display = '';
@@ -99,21 +98,21 @@ return view.extend({
chaintable.parentNode.setAttribute('data-empty', rows.length === 0);
},
parseIptablesDump: function(is_ipv6, table, s) {
var current_chain = null;
var current_rules = [];
var seen_chains = {};
var chain_refs = {};
var re = /([^\n]*)\n/g;
var m, m2;
var raw = document.querySelector('[data-raw-counters="true"]');
parseIptablesDump(is_ipv6, table, s) {
let current_chain = null;
let current_rules = [];
const seen_chains = {};
const chain_refs = {};
const re = /([^\n]*)\n/g;
let m, m2;
const raw = document.querySelector('[data-raw-counters="true"]');
while ((m = re.exec(s)) != null) {
if (m[1].match(/^Chain (.+) \(policy (\w+) (\d+) packets, (\d+) bytes\)$/)) {
var chain = RegExp.$1,
policy = RegExp.$2,
packets = +RegExp.$3,
bytes = +RegExp.$4;
const chain = RegExp.$1;
const policy = RegExp.$2;
const packets = +RegExp.$3;
const bytes = +RegExp.$4;
this.updateChainSection(current_chain, current_rules);
@@ -122,8 +121,8 @@ return view.extend({
current_rules = [];
}
else if (m[1].match(/^Chain (.+) \((\d+) references\)$/)) {
var chain = RegExp.$1,
references = +RegExp.$2;
const chain = RegExp.$1;
const references = +RegExp.$2;
this.updateChainSection(current_chain, current_rules);
@@ -135,17 +134,17 @@ return view.extend({
continue;
}
else if ((m2 = m[1].match(/^(\d+) +(\d+) +(\d+) +(.*?) +(\S+) +(\S*) +(\S+) +(\S+) +(!?[a-f0-9:.]+(?:\/[a-f0-9:.]+)?) +(!?[a-f0-9:.]+(?:\/[a-f0-9:.]+)?) +(.+)$/)) !== null) {
var num = +m2[1],
pkts = +m2[2],
bytes = +m2[3],
target = m2[4],
proto = m2[5],
indev = m2[7],
outdev = m2[8],
srcnet = m2[9],
dstnet = m2[10],
options = m2[11] || '-',
comment = '-';
const num = +m2[1];
const pkts = +m2[2];
const bytes = +m2[3];
const target = m2[4];
const proto = m2[5];
const indev = m2[7];
const outdev = m2[8];
const srcnet = m2[9];
const dstnet = m2[10];
let options = m2[11] || '-';
let comment = '-';
options = options.trim().replace(/(?:^| )\/\* (.+) \*\//,
function(m1, m2) {
@@ -199,14 +198,14 @@ return view.extend({
}, this));
cdiv.querySelectorAll('.references').forEach(L.bind(function(rspan) {
var refs = chain_refs[cdiv.getAttribute('data-chain')];
const refs = chain_refs[cdiv.getAttribute('data-chain')];
if (refs && refs.length) {
rspan.classList.add('cbi-tooltip-container');
rspan.appendChild(E('small', { 'class': 'cbi-tooltip ifacebadge', 'style': 'top:1em; left:auto' }, [ E('ul') ]));
refs.forEach(L.bind(function(ref) {
var chain = ref[0].parentNode.getAttribute('data-chain'),
num = ref[1];
const chain = ref[0].parentNode.getAttribute('data-chain');
const num = ref[1];
rspan.lastElementChild.lastElementChild.appendChild(E('li', {}, [
_('Chain'), ' ',
@@ -223,20 +222,20 @@ return view.extend({
}, this));
},
pollFirewallLists: function(has_ip6tables) {
var cmds = [ '/usr/sbin/iptables' ];
pollFirewallLists(has_ip6tables) {
const cmds = [ '/usr/sbin/iptables' ];
if (has_ip6tables)
cmds.push('/usr/sbin/ip6tables');
poll.add(L.bind(function() {
var tasks = [];
const tasks = [];
for (var i = 0; i < cmds.length; i++) {
for (var j = 0; j < table_names.length; j++) {
for (let i = 0; i < cmds.length; i++) {
for (let tn of table_names) {
tasks.push(L.resolveDefault(
fs.exec_direct(cmds[i], [ '--line-numbers', '-w', '-nvxL', '-t', table_names[j].toLowerCase() ])
.then(this.parseIptablesDump.bind(this, i > 0, table_names[j]))));
fs.exec_direct(cmds[i], [ '--line-numbers', '-w', '-nvxL', '-t', tn.toLowerCase() ])
.then(this.parseIptablesDump.bind(this, i > 0, tn))));
}
}
@@ -244,12 +243,12 @@ return view.extend({
}, this));
},
handleJumpTarget: function(ev) {
var link = ev.target,
table = findParent(link, '[data-table]').getAttribute('data-table'),
chain = link.textContent,
num = +link.getAttribute('data-num'),
elem = document.getElementById('rule_%s_%s'.format(table.toLowerCase(), chain));
handleJumpTarget(ev) {
const link = ev.target;
const table = findParent(link, '[data-table]').getAttribute('data-table');
const chain = link.textContent;
const num = +link.getAttribute('data-num');
const elem = document.getElementById('rule_%s_%s'.format(table.toLowerCase(), chain));
if (elem) {
if (elem.scrollIntoView) {
@@ -262,7 +261,7 @@ return view.extend({
elem.classList.add('flash');
if (num) {
var rule = elem.nextElementSibling.childNodes[num];
const rule = elem.nextElementSibling.childNodes[num];
if (rule) {
rule.classList.remove('flash');
void rule.offsetWidth;
@@ -272,9 +271,9 @@ return view.extend({
}
},
handleRawCounters: function(ev) {
var btn = ev.currentTarget,
raw = (btn.getAttribute('data-raw-counters') === 'false');
handleRawCounters(ev) {
const btn = ev.currentTarget;
const raw = (btn.getAttribute('data-raw-counters') === 'false');
btn.setAttribute('data-raw-counters', raw);
btn.firstChild.data = raw ? _('Human-readable counters') : _('Show raw counters');
@@ -282,16 +281,16 @@ return view.extend({
document.querySelectorAll('[data-value]')
.forEach(function(div) {
var fmt = raw ? '%d' : div.getAttribute('data-format');
const fmt = raw ? '%d' : div.getAttribute('data-format');
div.style = raw ? raw_style : '';
div.innerText = fmt.format(div.getAttribute('data-value'));
});
},
handleHideEmpty: function(ev) {
var btn = ev.currentTarget,
hide = (btn.getAttribute('data-hide-empty') === 'false');
handleHideEmpty(ev) {
const btn = ev.currentTarget;
const hide = (btn.getAttribute('data-hide-empty') === 'false');
btn.setAttribute('data-hide-empty', hide);
btn.firstChild.data = hide ? _('Show empty chains') : _('Hide empty chains');
@@ -303,7 +302,7 @@ return view.extend({
});
},
handleCounterReset: function(has_ip6tables, ev) {
handleCounterReset(has_ip6tables, ev) {
return Promise.all([
fs.exec('/usr/sbin/iptables', [ '-Z' ])
.catch(function(err) { ui.addNotification(null, E('p', {}, _('Unable to reset iptables counters: %s').format(err.message))) }),
@@ -312,13 +311,13 @@ return view.extend({
]);
},
handleRestart: function(ev) {
handleRestart(ev) {
return fs.exec_direct('/etc/init.d/firewall', [ 'restart' ])
.catch(function(err) { ui.addNotification(null, E('p', {}, _('Unable to restart firewall: %s').format(err.message))) });
},
render: function(has_ip6tables) {
var view = E([], [
render(has_ip6tables) {
const view = E([], [
E('style', { 'type': 'text/css' }, [
'.cbi-tooltip-container, span.jump { border-bottom:1px dotted #00f;cursor:pointer }',
'ul { list-style:none }',

View File

@@ -4,68 +4,67 @@
'require request';
'require rpc';
var callLuciRealtimeStats = rpc.declare({
const callLuciRealtimeStats = rpc.declare({
object: 'luci',
method: 'getRealtimeStats',
params: [ 'mode', 'device' ],
expect: { result: [] }
});
var graphPolls = [],
pollInterval = 3;
const graphPolls = [];
const pollInterval = 3;
Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; };
return view.extend({
load: function() {
load() {
return Promise.all([
this.loadSVG(L.resource('svg/load.svg'))
]);
},
updateGraph: function(svg, lines, cb) {
var G = svg.firstElementChild;
updateGraph(svg, lines, cb) {
const G = svg.firstElementChild;
var view = document.querySelector('#view');
const view = document.querySelector('#view');
var width = view.offsetWidth - 2;
var height = 300 - 2;
var step = 5;
const width = view.offsetWidth - 2;
const height = 300 - 2;
const step = 5;
var data_wanted = Math.floor(width / step);
const data_wanted = Math.floor(width / step);
var data_values = [],
line_elements = [];
const data_values = [];
for (var i = 0; i < lines.length; i++)
if (lines[i] != null)
for (let line of lines)
if (line != null)
data_values.push([]);
var info = {
const info = {
line_current: [],
line_average: [],
line_peak: []
};
/* prefill datasets */
for (var i = 0; i < data_values.length; i++)
for (var j = 0; j < data_wanted; j++)
data_values[i][j] = 0;
for (let dv of data_values)
for (let j = 0; j < data_wanted; j++)
dv[j] = 0;
/* plot horizontal time interval lines */
for (var i = width % (step * 60); i < width; i += step * 60) {
var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
for (let i = width % (step * 60); i < width; i += step * 60) {
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', i);
line.setAttribute('y1', 0);
line.setAttribute('x2', i);
line.setAttribute('y2', '100%');
line.setAttribute('style', 'stroke:black;stroke-width:0.1');
var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(document.createTextNode(Math.round((width - i) / step / 60) + 'm'));
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttribute('x', i + 5);
text.setAttribute('y', 15);
text.setAttribute('style', 'fill:#eee; font-size:9pt; font-family:sans-serif; text-shadow:1px 1px 1px #000');
text.appendChild(document.createTextNode(Math.round((width - i) / step / 60) + 'm'));
G.appendChild(line);
G.appendChild(text);
@@ -88,35 +87,34 @@ return view.extend({
});
},
pollData: function() {
pollData() {
poll.add(L.bind(function() {
var tasks = [];
const tasks = [];
for (var i = 0; i < graphPolls.length; i++) {
var ctx = graphPolls[i];
graphPolls.forEach(() => {
tasks.push(L.resolveDefault(callLuciRealtimeStats('load'), []));
}
});
return Promise.all(tasks).then(L.bind(function(datasets) {
for (var gi = 0; gi < graphPolls.length; gi++) {
var ctx = graphPolls[gi],
data = datasets[gi],
values = ctx.values,
lines = ctx.lines,
info = ctx.info;
for (let gi = 0; gi < graphPolls.length; gi++) {
const ctx = graphPolls[gi];
const data = datasets[gi];
const values = ctx.values;
const lines = ctx.lines;
const info = ctx.info;
var data_scale = 0;
var data_wanted = Math.floor(ctx.width / ctx.step);
var last_timestamp = NaN;
let data_scale = 0;
let data_wanted = Math.floor(ctx.width / ctx.step);
let last_timestamp = NaN;
for (var i = 0, di = 0; di < lines.length; di++) {
for (let i = 0, di = 0; di < lines.length; di++) {
if (lines[di] == null)
continue;
var multiply = (lines[di].multiply != null) ? lines[di].multiply : 1,
offset = (lines[di].offset != null) ? lines[di].offset : 0;
const multiply = (lines[di].multiply != null) ? lines[di].multiply : 1;
const offset = (lines[di].offset != null) ? lines[di].offset : 0;
for (var j = ctx.timestamp ? 0 : 1; j < data.length; j++) {
for (let j = ctx.timestamp ? 0 : 1; j < data.length; j++) {
/* skip overlapping entries */
if (data[j][0] <= ctx.timestamp)
continue;
@@ -137,15 +135,15 @@ return view.extend({
/* cut off outdated entries */
ctx.fill = Math.min(ctx.fill, data_wanted);
for (var i = 0; i < values.length; i++) {
var len = values[i].length;
for (let i = 0; i < values.length; i++) {
const len = values[i].length;
values[i] = values[i].slice(len - data_wanted, len);
/* find peaks, averages */
info.line_peak[i] = NaN;
info.line_average[i] = 0;
for (var j = 0; j < values[i].length; j++) {
for (let j = 0; j < values[i].length; j++) {
info.line_peak[i] = isNaN(info.line_peak[i]) ? values[i][j] : Math.max(info.line_peak[i], values[i][j]);
info.line_average[i] += values[i][j];
}
@@ -159,29 +157,29 @@ return view.extend({
if (!isNaN(last_timestamp))
ctx.timestamp = last_timestamp;
var size = Math.floor(Math.log2(info.peak)),
div = Math.pow(2, size - (size % 10)),
mult = info.peak / div,
mult = (mult < 5) ? 2 : ((mult < 50) ? 10 : ((mult < 500) ? 100 : 1000));
const size = Math.floor(Math.log2(info.peak));
const div = Math.pow(2, size - (size % 10));
let mult = info.peak / div;
mult = (mult < 5) ? 2 : ((mult < 50) ? 10 : ((mult < 500) ? 100 : 1000));
info.peak = info.peak + (mult * div) - (info.peak % (mult * div));
data_scale = ctx.height / info.peak;
/* plot data */
for (var i = 0, di = 0; di < lines.length; di++) {
for (let i = 0, di = 0; di < lines.length; di++) {
if (lines[di] == null)
continue;
var el = ctx.svg.firstElementChild.getElementById(lines[di].line),
pt = '0,' + ctx.height,
y = 0;
const el = ctx.svg.firstElementChild.getElementById(lines[di].line);
let pt = '0,' + ctx.height;
let y = 0;
if (!el)
continue;
for (var j = 0; j < values[i].length; j++) {
var x = j * ctx.step;
for (let j = 0; j < values[i].length; j++) {
let x = j * ctx.step;
y = ctx.height - Math.floor(values[i][j] * data_scale);
//y -= Math.floor(y % (1 / data_scale));
@@ -209,7 +207,7 @@ return view.extend({
}, this), pollInterval);
},
loadSVG: function(src) {
loadSVG(src) {
return request.get(src).then(function(response) {
if (!response.ok)
throw new Error(response.statusText);
@@ -220,10 +218,8 @@ return view.extend({
});
},
render: function(data) {
var svg = data[0];
var v = E('div', { 'class': 'cbi-map', 'id': 'map' }, [
render([svg]) {
const v = E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('h2', _('System load')),
E('div', {'class': 'cbi-map-descr'}, _('Load Average is a metric that is used by Linux to keep track of system resources.')),
E('div', { 'class': 'cbi-section' }, [
@@ -267,7 +263,7 @@ return view.extend({
]);
this.updateGraph(svg, [ { line: 'load01' }, { line: 'load05' }, { line: 'load15' } ], function(svg, info) {
var G = svg.firstElementChild, tab = svg.parentNode;
const G = svg.firstElementChild, tab = svg.parentNode;
G.getElementById('label_25').firstChild.data = '%.2f'.format(info.label_25 / 100);
G.getElementById('label_50').firstChild.data = '%.2f'.format(info.label_50 / 100);

View File

@@ -5,7 +5,7 @@
'require ui';
'require dom';
var expr_translations = {
const expr_translations = {
'meta.iifname': _('Ingress device name', 'nft meta iifname'),
'meta.oifname': _('Egress device name', 'nft meta oifname'),
'meta.iif': _('Ingress device id', 'nft meta iif'),
@@ -85,7 +85,7 @@ var expr_translations = {
'payload.th': _('Transport header bits %d-%d', 'nft @th,off,len')
};
var op_translations = {
const op_translations = {
'==': _('<var>%s</var> is <strong>%s</strong>', 'nft relational "==" operator expression'),
'!=': _('<var>%s</var> not <strong>%s</strong>', 'nft relational "!=" operator expression'),
'>=': _('<var>%s</var> greater than or equal to <strong>%s</strong>', 'nft relational ">=" operator expression'),
@@ -97,7 +97,7 @@ var op_translations = {
'not_in_set': _('<var>%s</var> not in set <strong>%s</strong>', 'nft not in set match expression'),
};
var action_translations = {
const action_translations = {
'accept': _('Accept packet', 'nft accept action'),
'notrack': _('Do not track', 'nft notrack action'),
'drop': _('Drop packet', 'nft drop action'),
@@ -143,24 +143,24 @@ var action_translations = {
};
return view.extend({
load: function() {
load() {
return Promise.all([
L.resolveDefault(fs.exec_direct('/usr/sbin/nft', [ '--terse', '--json', 'list', 'ruleset' ], 'json'), {}),
fs.stat('/usr/sbin/iptables-legacy-save').then(function(stat) {
fs.stat('/usr/sbin/iptables-legacy-save').then(function() {
return L.resolveDefault(fs.exec_direct('/usr/sbin/iptables-legacy-save'), '');
}).catch(function(err) {
}).catch(function() {
return L.resolveDefault(fs.exec_direct('/usr/sbin/iptables-save'), '');
}),
fs.stat('/usr/sbin/ip6tables-legacy-save').then(function(stat) {
fs.stat('/usr/sbin/ip6tables-legacy-save').then(function() {
return L.resolveDefault(fs.exec_direct('/usr/sbin/ip6tables-legacy-save'), '');
}).catch(function(err) {
}).catch(function() {
return L.resolveDefault(fs.exec_direct('/usr/sbin/ip6tables-save'), '');
})
]);
},
isActionExpression: function(expr) {
for (var k in expr) {
isActionExpression(expr) {
for (let k in expr) {
if (expr.hasOwnProperty(k)) {
switch (k) {
case 'accept':
@@ -187,11 +187,11 @@ return view.extend({
return false;
},
exprToKey: function(expr) {
var kind, spec;
exprToKey(expr) {
let kind, spec;
if (!Array.isArray(expr) && typeof(expr) == 'object') {
for (var k in expr) {
for (let k in expr) {
if (expr.hasOwnProperty(k)) {
kind = k;
spec = expr[k];
@@ -216,11 +216,11 @@ return view.extend({
return null;
},
exprToString: function(expr, hint) {
var kind, spec;
exprToString(expr, hint) {
let kind, spec;
if (typeof(expr) != 'object') {
var s;
let s;
if (hint)
s = expr_translations['%s.%h'.format(hint, expr)];
@@ -233,7 +233,7 @@ return view.extend({
spec = expr;
}
else {
for (var k in expr) {
for (let k in expr) {
if (expr.hasOwnProperty(k)) {
kind = k;
spec = expr[k];
@@ -244,21 +244,21 @@ return view.extend({
if (!kind)
return '';
const items = [];
const lis = [];
let tpl, k;
switch (kind) {
case 'prefix':
return '%h/%d'.format(spec.addr, spec.len);
case 'set':
case 'list':
var items = [],
lis = [];
for (var i = 0; i < spec.length; i++) {
items.push('<span class="nft-set-item">%s</span>'.format(this.exprToString(spec[i])));
lis.push('<span class="ifacebadge">%s</span>'.format(this.exprToString(spec[i])));
}
var tpl;
if (kind == 'set')
tpl = '<div class="nft-set cbi-tooltip-container">{ <span class="nft-set-items">%s</span> }<div class="cbi-tooltip">%s</div></div>';
@@ -268,10 +268,9 @@ return view.extend({
return tpl.format(items.join(', '), lis.join('<br />'));
case 'concat':
var items = [];
for (var i = 0; i < spec.length; i++)
items.push(this.exprToString(spec[i]));
for (let s of spec)
items.push(this.exprToString(s));
return items.join('+');
@@ -280,11 +279,11 @@ return view.extend({
case 'payload':
if (spec.protocol && spec.field) {
var k = '%h.%h'.format(spec.protocol, spec.field);
k = '%h.%h'.format(spec.protocol, spec.field);
return expr_translations[k] || '<em>%s</em>'.format(k);
}
else if (spec.base && spec.offset != null && spec.len != null) {
var k = 'payload.%h'.format(spec.base);
k = 'payload.%h'.format(spec.base);
return (expr_translations[k] || '<em>@%s,%%d,%%d</em>'.format(spec.base)).format(spec.offset + 1, spec.offset + spec.len + 1);
}
@@ -299,7 +298,7 @@ return view.extend({
Array.isArray(spec[1]) ? '(%h)'.format(spec[1].join('|')) : this.exprToString(spec[1], hint));
default:
var k = this.exprToKey(expr);
k = this.exprToKey(expr);
if (k)
return expr_translations[k] || '<em>%s</em>'.format(k);
@@ -308,7 +307,7 @@ return view.extend({
}
},
renderVMap: function(spec, table) {
renderVMap(spec, table) {
// spec: { key: {...}, data: { set: [ [mapkey, actionSpec], ... ] } }
const matchElem = E('span', { 'class': 'ifacebadge' },
_('Verdict map: <var>%h</var> is').format(this.exprToString(spec.key)));
@@ -349,7 +348,7 @@ return view.extend({
return { match: matchElem, actions: actions };
},
renderMatchExpr: function(spec) {
renderMatchExpr(spec) {
switch (spec.op) {
case '==':
case '!=':
@@ -374,12 +373,12 @@ return view.extend({
);
},
renderNatFlags: function(spec) {
var f = [];
renderNatFlags(spec) {
const f = [];
if (spec && Array.isArray(spec.flags)) {
for (var i = 0; i < spec.flags.length; i++)
f.push(expr_translations['natflag.%h'.format(spec.flags[i])] || spec.flags[i]);
for (let sf of spec.flags)
f.push(expr_translations['natflag.%h'.format(sf)] || sf);
}
return f.length ? E('small', { 'class': 'cbi-tooltip-container' }, [
@@ -390,7 +389,7 @@ return view.extend({
]) : E([]);
},
renderRateUnit: function(value, unit) {
renderRateUnit(value, unit) {
if (!unit)
unit = 'packets';
@@ -400,10 +399,10 @@ return view.extend({
);
},
renderExpr: function(expr, table) {
var kind, spec;
renderExpr(expr, table) {
let kind, spec;
for (var k in expr) {
for (let k in expr) {
if (expr.hasOwnProperty(k)) {
kind = k;
spec = expr[k];
@@ -413,6 +412,9 @@ return view.extend({
if (!kind)
return E([]);
let k;
let a = [];
switch (kind) {
case 'match':
return this.renderMatchExpr(spec);
@@ -423,7 +425,7 @@ return view.extend({
}, action_translations[kind].format(spec));
case 'reject':
var k = 'reject.%s'.format(spec.type);
k = 'reject.%s'.format(spec.type);
return E('span', {
'class': 'ifacebadge'
@@ -458,8 +460,7 @@ return view.extend({
case 'snat':
case 'dnat':
var k = '%h.%h'.format(kind, spec.family),
a = [];
k = '%h.%h'.format(kind, spec.family);
if (spec.addr) {
k += '.addr';
@@ -477,8 +478,7 @@ return view.extend({
]);
case 'redirect':
var k = 'redirect',
a = [];
k = 'redirect';
if (spec && spec.port) {
k += '.port';
@@ -504,8 +504,8 @@ return view.extend({
));
case 'limit':
var k = 'limit';
var a = [
k = 'limit';
a = [
this.renderRateUnit(spec.rate, spec.rate_unit),
expr_translations['unit.%h'.format(spec.per)] || spec.per
];
@@ -541,7 +541,7 @@ return view.extend({
}
},
renderCounter: function(data) {
renderCounter(data) {
return E('span', { 'class': 'ifacebadge cbi-tooltip-container nft-counter' }, [
E('var', [ '%.1024mB'.format(data.bytes) ]),
E('div', { 'class': 'cbi-tooltip' }, [
@@ -550,7 +550,7 @@ return view.extend({
]);
},
renderComment: function(comment) {
renderComment(comment) {
return E('span', { 'class': 'ifacebadge cbi-tooltip-container nft-comment' }, [
E('var', [ '#' ]),
E('div', { 'class': 'cbi-tooltip' }, [
@@ -559,47 +559,47 @@ return view.extend({
]);
},
renderRule: function(data, spec) {
var empty = true;
renderRule(data, spec) {
let empty = true;
var row = E('tr', { 'class': 'tr' }, [
const row = E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td', 'style': 'width:60%' }),
E('td', { 'class': 'td', 'style': 'width:40%' })
]);
if (Array.isArray(spec.expr)) {
for (var i = 0; i < spec.expr.length; i++) {
for (let se of spec.expr) {
// nftables JSON format bug, `flow` targets are currently not properly serialized
if (typeof(spec.expr[i]) == 'string' && spec.expr[i].match(/^flow add (@\S+)$/))
spec.expr[i] = { flow: { op: "add", flowtable: RegExp.$1 } };
if (typeof(se) == 'string' && se.match(/^flow add (@\S+)$/))
se = { flow: { op: "add", flowtable: RegExp.$1 } };
// vmap special handling
if (spec.expr[i] && spec.expr[i].vmap) {
var vm = this.renderVMap(spec.expr[i].vmap, spec.table);
if (se && se.vmap) {
const vm = this.renderVMap(se.vmap, spec.table);
// add match summary to left column
dom.append(row.childNodes[0], [ vm.match ]);
empty = false;
if (typeof(spec.expr[i]) == 'object' && spec.expr[i].counter) {
if (typeof(se) == 'object' && se.counter) {
row.childNodes[0].appendChild(
this.renderCounter(spec.expr[i].counter));
this.renderCounter(se.counter));
}
// append each mapped action to the actions column
for (var ai = 0; ai < vm.actions.length; ai++)
dom.append(row.childNodes[1], [ vm.actions[ai] ]);
for (let vma of vm.actions)
dom.append(row.childNodes[1], [ vma ]);
continue;
}
var res = this.renderExpr(spec.expr[i], spec.table);
const res = this.renderExpr(se, spec.table);
if (typeof(spec.expr[i]) == 'object' && spec.expr[i].counter) {
if (typeof(se) == 'object' && se.counter) {
row.childNodes[0].insertBefore(
this.renderCounter(spec.expr[i].counter),
this.renderCounter(se.counter),
row.childNodes[0].firstChild);
}
else if (this.isActionExpression(spec.expr[i])) {
else if (this.isActionExpression(se)) {
dom.append(row.childNodes[1], [ res ]);
}
else {
@@ -621,8 +621,8 @@ return view.extend({
return row;
},
renderChain: function(data, spec) {
var title, policy, hook;
renderChain(data, spec) {
let title, policy, hook;
switch (spec.type) {
case 'filter':
@@ -682,7 +682,7 @@ return view.extend({
break;
}
var node = E('div', { 'class': 'nft-chain' }, [
const node = E('div', { 'class': 'nft-chain' }, [
E('h4', {
'id': '%h.%h'.format(spec.table, spec.name)
}, [ title ])
@@ -704,9 +704,9 @@ return view.extend({
])
]));
for (var i = 0; i < data.length; i++)
if (typeof(data[i].rule) == 'object' && data[i].rule.table == spec.table && data[i].rule.chain == spec.name && data[i].rule.family == spec.family)
node.lastElementChild.appendChild(this.renderRule(data, data[i].rule));
for (let d of data)
if (typeof(d.rule) == 'object' && d.rule.table == spec.table && d.rule.chain == spec.name && d.rule.family == spec.family)
node.lastElementChild.appendChild(this.renderRule(data, d.rule));
if (node.lastElementChild.childNodes.length == 1)
node.lastElementChild.appendChild(E('tr', { 'class': 'tr' }, [
@@ -718,8 +718,8 @@ return view.extend({
return node;
},
renderTable: function(data, spec) {
var title;
renderTable(data, spec) {
let title;
switch (spec.family) {
case 'ip':
@@ -751,7 +751,7 @@ return view.extend({
break;
}
var node = E([], [
const node = E([], [
E('style', { 'type': 'text/css' }, [
'.nft-rules .ifacebadge { margin: .125em }',
'.nft-rules tr > td { padding: .25em !important }',
@@ -766,14 +766,14 @@ return view.extend({
])
]);
for (var i = 0; i < data.length; i++)
if (typeof(data[i].chain) == 'object' && data[i].chain.table == spec.name && data[i].chain.family == spec.family)
node.lastElementChild.lastElementChild.appendChild(this.renderChain(data, data[i].chain));
for (let d of data)
if (typeof(d.chain) == 'object' && d.chain.table == spec.name && d.chain.family == spec.family)
node.lastElementChild.lastElementChild.appendChild(this.renderChain(data, d.chain));
return node;
},
checkLegacyRules: function(ipt4save, ipt6save) {
checkLegacyRules(ipt4save, ipt6save) {
if (ipt4save.match(/\n-A /) || ipt6save.match(/\n-A /)) {
ui.addNotification(_('Legacy rules detected'), [
E('p', _('There are legacy iptables rules present on the system. Mixing iptables and nftables rules is discouraged and may lead to incomplete traffic filtering.')),
@@ -785,20 +785,17 @@ return view.extend({
}
},
render: function(data) {
var view = E('div'),
nft = data[0],
ipt = data[1],
ipt6 = data[2];
render([nft, ipt, ipt6]) {
const view = E('div');
this.checkLegacyRules(ipt, ipt6);
if (!Array.isArray(nft.nftables))
return E('em', _('No nftables ruleset loaded.'));
for (var i = 0; i < nft.nftables.length; i++)
if (nft.nftables[i].hasOwnProperty('table'))
view.appendChild(this.renderTable(nft.nftables, nft.nftables[i].table));
for (let t of nft.nftables)
if (t.hasOwnProperty('table'))
view.appendChild(this.renderTable(nft.nftables, t.table));
return view;
},

View File

@@ -120,7 +120,7 @@ return view.extend({
const res = [];
for (const line of routes.trim().split(/\n/)) {
const [, type = 'unicast', d, f = [] ] = line.match(/^(?:([a-z_]+|\d+) )?(default|[0-9a-f:.\/]+) (.+)$/);
const [, type = 'unicast', d, f = [] ] = line.match(/^(?:([a-z_]+|\d+) )?(default|[0-9a-f:./]+) (.+)$/);
const dest = d == 'default' ? (v6 ? '::/0' : '0.0.0.0/0') : d;
const flags = f?.trim?.().split?.(/\s+/);

View File

@@ -53,8 +53,7 @@ return view.extend({
const data_wanted = Math.floor(width / step);
const data_values = [],
line_elements = [];
const data_values = [];
for (const line of lines)
if (line)

View File

@@ -6,9 +6,9 @@
'require fs';
'require ui';
var isReadonlyView = !L.hasViewPermission();
const isReadonlyView = !L.hasViewPermission();
var callSystemValidateFirmwareImage = rpc.declare({
const callSystemValidateFirmwareImage = rpc.declare({
object: 'system',
method: 'validate_firmware_image',
params: [ 'path' ],
@@ -16,11 +16,11 @@ var callSystemValidateFirmwareImage = rpc.declare({
});
function findStorageSize(procmtd, procpart) {
var kernsize = 0, rootsize = 0, wholesize = 0;
let kernsize = 0, rootsize = 0, wholesize = 0;
procmtd.split(/\n/).forEach(function(ln) {
var match = ln.match(/^mtd\d+: ([0-9a-f]+) [0-9a-f]+ "(.+)"$/),
size = match ? parseInt(match[1], 16) : 0;
const match = ln.match(/^mtd\d+: ([0-9a-f]+) [0-9a-f]+ "(.+)"$/);
const size = match ? parseInt(match[1], 16) : 0;
switch (match ? match[2] : '') {
case 'linux':
@@ -49,9 +49,9 @@ function findStorageSize(procmtd, procpart) {
return kernsize + rootsize;
procpart.split(/\n/).forEach(function(ln) {
var match = ln.match(/^\s*\d+\s+\d+\s+(\d+)\s+(\S+)$/);
const match = ln.match(/^\s*\d+\s+\d+\s+(\d+)\s+(\S+)$/);
if (match) {
var size = parseInt(match[1], 10);
const size = parseInt(match[1], 10);
if (!match[2].match(/\d/) && size > 2048 && wholesize == 0)
wholesize = size * 1024;
@@ -62,11 +62,11 @@ function findStorageSize(procmtd, procpart) {
}
var mapdata = { actions: {}, config: {} };
const mapdata = { actions: {}, config: {} };
return view.extend({
load: function() {
var tasks = [
load() {
const tasks = [
L.resolveDefault(fs.stat('/lib/upgrade/platform.sh'), {}),
fs.trimmed('/proc/sys/kernel/hostname'),
fs.trimmed('/proc/mtd'),
@@ -77,8 +77,8 @@ return view.extend({
return Promise.all(tasks);
},
handleBackup: function(ev) {
var form = E('form', {
handleBackup(ev) {
const form = E('form', {
method: 'post',
action: L.env.cgi_base + '/cgi-backup',
enctype: 'application/x-www-form-urlencoded'
@@ -90,7 +90,7 @@ return view.extend({
form.parentNode.removeChild(form);
},
handleFirstboot: function(ev) {
handleFirstboot(ev) {
if (!confirm(_('Do you really want to erase all settings?')))
return;
@@ -104,7 +104,7 @@ return view.extend({
ui.awaitReconnect('192.168.1.1', 'openwrt.lan');
},
handleRestore: function(ev) {
handleRestore(ev) {
return ui.uploadFile('/tmp/backup.tar.gz', ev.target)
.then(L.bind(function(btn, res) {
btn.firstChild.data = _('Checking archive…');
@@ -139,7 +139,7 @@ return view.extend({
}, this, ev.target));
},
handleRestoreConfirm: function(btn, ev) {
handleRestoreConfirm(btn, ev) {
return fs.exec('/sbin/sysupgrade', [ '--restore-backup', '/tmp/backup.tar.gz' ])
.then(L.bind(function(btn, res) {
if (res.code != 0) {
@@ -169,11 +169,11 @@ return view.extend({
.finally(function() { btn.firstChild.data = _('Upload archive...') });
},
handleBlock: function(hostname, ev) {
var mtdblock = dom.parent(ev.target, '.cbi-section').querySelector('[data-name="mtdselect"] select');
var mtdnumber = mtdblock.value;
var mtdname = mtdblock.selectedOptions[0].text.replace(/([^a-zA-Z0-9]+)/g, '-');
var form = E('form', {
handleBlock(hostname, ev) {
const mtdblock = dom.parent(ev.target, '.cbi-section').querySelector('[data-name="mtdselect"] select');
const mtdnumber = mtdblock.value;
const mtdname = mtdblock.selectedOptions[0].text.replace(/([^a-zA-Z0-9]+)/g, '-');
const form = E('form', {
'method': 'post',
'action': L.env.cgi_base + '/cgi-download',
'enctype': 'application/x-www-form-urlencoded'
@@ -189,7 +189,7 @@ return view.extend({
form.parentNode.removeChild(form);
},
handleSysupgrade: function(storage_size, has_rootfs_data, ev) {
handleSysupgrade(storage_size, has_rootfs_data, ev) {
return ui.uploadFile('/tmp/firmware.bin', ev.target.firstChild)
.then(L.bind(function(btn, reply) {
btn.firstChild.data = _('Checking image…');
@@ -207,7 +207,7 @@ return view.extend({
}, this, ev.target))
.then(L.bind(function(btn, res) {
/* sysupgrade opts table [0]:checkbox element [1]:check condition [2]:args to pass */
var opts = {
const opts = {
keep : [ E('input', { type: 'checkbox' }), false, '-n' ],
force : [ E('input', { type: 'checkbox' }), true, '--force' ],
skip_orig : [ E('input', { type: 'checkbox' }), true, '-u' ],
@@ -265,7 +265,7 @@ return view.extend({
])));
};
var cntbtn = E('button', {
const cntbtn = E('button', {
'class': 'btn cbi-button-action important',
'click': ui.createHandlerFn(this, 'handleSysupgradeConfirm', btn, opts),
}, [ _('Continue') ]);
@@ -315,16 +315,16 @@ return view.extend({
}, this, ev.target));
},
handleSysupgradeConfirm: function(btn, opts, ev) {
handleSysupgradeConfirm(btn, opts, ev) {
btn.firstChild.data = _('Flashing…');
ui.showModal(_('Flashing…'), [
E('p', { 'class': 'spinning' }, _('The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings.'))
]);
var args = [];
const args = [];
for (var key in opts)
for (let key in opts)
/* if checkbox == condition add args to sysupgrade */
if (opts[key][0].checked == opts[key][1])
args.push(opts[key][2]);
@@ -340,7 +340,7 @@ return view.extend({
ui.awaitReconnect('192.168.1.1', 'openwrt.lan');
},
handleBackupList: function(ev) {
handleBackupList(ev) {
return fs.exec('/sbin/sysupgrade', [ '--list-backup' ]).then(function(res) {
if (res.code != 0) {
ui.addNotification(null, [
@@ -363,7 +363,7 @@ return view.extend({
});
},
handleBackupSave: function(m, ev) {
handleBackupSave(m, ev) {
return m.save(function() {
return fs.write('/etc/sysupgrade.conf', mapdata.config.editlist.trim().replace(/\r\n/g, '\n') + '\n');
}).then(function() {
@@ -373,15 +373,11 @@ return view.extend({
});
},
render: function(rpc_replies) {
var has_sysupgrade = (rpc_replies[0].type == 'file'),
hostname = rpc_replies[1],
procmtd = rpc_replies[2],
procpart = rpc_replies[3],
procmounts = rpc_replies[4],
has_rootfs_data = (procmtd.match(/"rootfs_data"/) != null) || (procmounts.match("overlayfs:\/overlay \/ ") != null),
storage_size = findStorageSize(procmtd, procpart),
m, s, o, ss;
render([p_fstat, hostname, procmtd, procpart, procmounts]) {
const has_sysupgrade = (p_fstat.type == 'file');
const has_rootfs_data = (procmtd.match(/"rootfs_data"/) != null) || (procmounts.match("overlayfs:/overlay / ") != null);
const storage_size = findStorageSize(procmtd, procpart);
let m, s, o, ss;
m = new form.JSONMap(mapdata, _('Flash operations'));
m.tabbed = true;
@@ -415,9 +411,9 @@ return view.extend({
o.onclick = L.bind(this.handleRestore, this);
var mtdblocks = [];
const mtdblocks = [];
procmtd.split(/\n/).forEach(function(ln) {
var match = ln.match(/^mtd(\d+): .+ "(.+?)"$/);
const match = ln.match(/^mtd(\d+): .+ "(.+?)"$/);
if (match)
mtdblocks.push(match[1], match[2]);
});

View File

@@ -5,25 +5,24 @@
'require form';
'require fs';
var callLeds = rpc.declare({
const callLeds = rpc.declare({
object: 'luci',
method: 'getLEDs',
expect: { '': {} }
});
return view.extend({
load: function() {
load() {
return Promise.all([
callLeds(),
L.resolveDefault(fs.list('/www' + L.resource('view/system/led-trigger')), [])
]).then(function(data) {
var plugins = data[1];
var tasks = [];
]).then(function([leds, plugins]) {
const tasks = [];
for (var i = 0; i < plugins.length; i++) {
var m = plugins[i].name.match(/^(.+)\.js$/);
for (let p of plugins) {
const m = p.name.match(/^(.+)\.js$/);
if (plugins[i].type != 'file' || m == null)
if (p.type != 'file' || m == null)
continue;
tasks.push(L.require('view.system.led-trigger.' + m[1]).then(L.bind(function(name){
@@ -37,22 +36,18 @@ return view.extend({
}
return Promise.all(tasks).then(function(plugins) {
var value = {};
value[0] = data[0];
value[1] = plugins;
return value;
return [leds, plugins];
});
});
},
render: function(data) {
var m, s, o, triggers = [];
var leds = data[0];
var plugins = data[1];
render([leds, plugins]) {
let m, s, o;
const triggers = [];
for (var k in leds)
for (var i = 0; i < leds[k].triggers.length; i++)
triggers[i] = leds[k].triggers[i];
for (let k in leds)
for (let t of leds[k].triggers)
triggers.push(t);
m = new form.Map('system',
_('<abbr title="Light Emitting Diode">LED</abbr> Configuration'),
@@ -73,9 +68,7 @@ return view.extend({
});
o = s.option(form.ListValue, 'trigger', _('Trigger'));
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i];
for (let plugin of plugins) {
if ( plugin.form.kernel == false ) {
o.value(plugin.name, plugin.form.trigger);
}
@@ -85,17 +78,15 @@ return view.extend({
}
}
o.onchange = function(ev, section, value) {
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i];
if ( plugin.name === value )
this.map.findElement('id', 'cbid.system.%s.trigger'.format(section))
.nextElementSibling.innerHTML = plugin.form.description || '';
const nes = this.map.findElement('id', 'cbid.system.%s.trigger'.format(section)).nextElementSibling;
for (let plugin of plugins) {
if ( plugin.name === value && nes )
nes.innerText = plugin.form.description || '';
}
}
o.load = function(section_id) {
var trigger = uci.get('system', section_id, 'trigger');
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i];
const trigger = uci.get('system', section_id, 'trigger');
for (let plugin of plugins) {
if ( plugin.name === trigger)
this.description = plugin.form.description || ' ';
}
@@ -103,17 +94,16 @@ return view.extend({
};
s.addModalOptions = function(s) {
for (var i = 0; i < plugins.length; i++) {
var plugin = plugins[i];
for (let plugin of plugins) {
plugin.form.addFormOptions(s);
}
var opts = s.getOption();
const opts = s.getOption();
var removeIfNoneActive = function(original_remove_fn, section_id) {
var isAnyActive = false;
const removeIfNoneActive = function(original_remove_fn, section_id) {
let isAnyActive = false;
for (var optname in opts) {
for (let optname in opts) {
if (opts[optname].ucioption != this.ucioption)
continue;
@@ -128,7 +118,7 @@ return view.extend({
original_remove_fn.call(this, section_id);
};
for (var optname in opts) {
for (let optname in opts) {
if (!opts[optname].ucioption || optname == opts[optname].ucioption)
continue;
opts[optname].remove = removeIfNoneActive.bind(opts[optname], opts[optname].remove);

View File

@@ -6,29 +6,27 @@
'require rpc';
'require form';
var callBlockDevices, callMountPoints, callBlockDetect;
callBlockDevices = rpc.declare({
const callBlockDevices = rpc.declare({
object: 'luci',
method: 'getBlockDevices',
expect: { '': {} }
});
callMountPoints = rpc.declare({
const callMountPoints = rpc.declare({
object: 'luci',
method: 'getMountPoints',
expect: { result: [] }
});
callBlockDetect = rpc.declare({
const callBlockDetect = rpc.declare({
object: 'luci',
method: 'setBlockDetect',
expect: { result: false }
});
function device_textvalue(devices, section_id) {
var v = (uci.get('fstab', section_id, 'uuid') || '').toLowerCase(),
e = Object.keys(devices).filter(function(dev) { return (devices[dev].uuid || '-').toLowerCase() == v })[0];
let v = (uci.get('fstab', section_id, 'uuid') || '').toLowerCase();
let e = Object.keys(devices).filter(function(dev) { return (devices[dev].uuid || '-').toLowerCase() == v })[0];
if (v) {
this.section.devices[section_id] = devices[e];
@@ -71,13 +69,13 @@ function device_textvalue(devices, section_id) {
}
return view.extend({
handleDetect: function(m, ev) {
handleDetect(m, ev) {
return callBlockDetect()
.then(L.bind(uci.unload, uci, 'fstab'))
.then(L.bind(m.render, m));
},
handleMountAll: function(m, ev) {
handleMountAll(m, ev) {
return fs.exec('/sbin/block', ['mount'])
.then(function(res) {
if (res.code != 0)
@@ -87,53 +85,34 @@ return view.extend({
.then(L.bind(m.render, m));
},
handleUmount: function(m, path, ev) {
handleUmount(m, path, ev) {
return fs.exec('/bin/umount', [path])
.then(L.bind(uci.unload, uci, 'fstab'))
.then(L.bind(m.render, m))
.catch(function(e) { ui.addNotification(null, E('p', e.message)) });
},
load: function() {
load() {
return Promise.all([
callBlockDevices(),
fs.lines('/proc/filesystems'),
fs.lines('/etc/filesystems'),
L.resolveDefault(fs.stat('/usr/sbin/e2fsck'), null),
L.resolveDefault(fs.stat('/usr/sbin/fsck.f2fs'), null),
L.resolveDefault(fs.stat('/usr/sbin/fsck.fat'), null),
L.resolveDefault(fs.stat('/usr/bin/btrfsck'), null),
L.resolveDefault(fs.stat('/usr/bin/ntfsfix'), null),
uci.load('fstab')
uci.load('fstab'),
]);
},
render: function(results) {
var devices = results[0],
procfs = results[1],
etcfs = results[2],
triggers = {},
trigger, m, s, o;
render([devices, procfs, etcfs]) {
let m, s, o;
var fsck = {
ext2: results[3],
ext3: results[3],
ext4: results[3],
f2fs: results[4],
vfat: results[5],
btrfs: results[6],
ntfs: results[7]
};
let filesystems = {};
var filesystems = {};
for (let p of procfs)
if (p.match(/\S/) && !p.match(/^nodev\t/))
filesystems[p.trim()] = true;
for (var i = 0; i < procfs.length; i++)
if (procfs[i].match(/\S/) && !procfs[i].match(/^nodev\t/))
filesystems[procfs[i].trim()] = true;
for (var i = 0; i < etcfs.length; i++)
if (etcfs[i].match(/\S/))
filesystems[etcfs[i].trim()] = true;
for (let e of etcfs)
if (e.match(/\S/))
filesystems[e.trim()] = true;
filesystems = Object.keys(filesystems).sort();
@@ -186,7 +165,7 @@ return view.extend({
};
o.render = L.bind(function(view, section_id) {
var table = E('table', { 'class': 'table' }, [
const table = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, _('Filesystem')),
E('th', { 'class': 'th' }, _('Mount Point')),
@@ -196,23 +175,23 @@ return view.extend({
])
]);
var rows = [];
const rows = [];
for (var i = 0; i < this.mounts.length; i++) {
var used = this.mounts[i].size - this.mounts[i].free,
for (let tm of this.mounts) {
var used = tm.size - tm.free,
umount = true;
if (/^\/(overlay|rom|tmp(?:\/.+)?|dev(?:\/.+)?|)$/.test(this.mounts[i].mount))
if (/^\/(overlay|rom|tmp(?:\/.+)?|dev(?:\/.+)?|)$/.test(tm.mount))
umount = false;
rows.push([
this.mounts[i].device,
this.mounts[i].mount,
'%1024.2mB / %1024.2mB'.format(this.mounts[i].avail, this.mounts[i].size),
'%.2f%% (%1024.2mB)'.format(100 / this.mounts[i].size * used, used),
tm.device,
tm.mount,
'%1024.2mB / %1024.2mB'.format(tm.avail, tm.size),
'%.2f%% (%1024.2mB)'.format(100 / tm.size * used, used),
umount ? E('button', {
'class': 'btn cbi-button-remove',
'click': ui.createHandlerFn(view, 'handleUmount', m, this.mounts[i].mount),
'click': ui.createHandlerFn(view, 'handleUmount', m, tm.mount),
'disabled': this.map.readonly || null
}, [ _('Unmount') ]) : '-'
]);
@@ -256,9 +235,9 @@ return view.extend({
o.modalonly = true;
o.value('', _('-- match by uuid --'));
var devs = Object.keys(devices).sort();
for (var i = 0; i < devs.length; i++) {
var dev = devices[devs[i]];
const devs = Object.keys(devices).sort();
for (let d of devs) {
const dev = devices[d];
if (dev.uuid && dev.size)
o.value(dev.uuid, '%s (%s, %1024.2mB)'.format(dev.uuid, dev.dev, dev.size));
else if (dev.uuid)
@@ -270,8 +249,8 @@ return view.extend({
o.depends('uuid', '');
o.value('', _('-- match by label --'));
for (var i = 0; i < devs.length; i++) {
var dev = devices[devs[i]];
for (let d of devs) {
const dev = devices[d];
if (dev.label && dev.size)
o.value(dev.label, '%s (%s, %1024.2mB)'.format(dev.label, dev.dev, dev.size));
else if (dev.label)
@@ -282,8 +261,8 @@ return view.extend({
o.modalonly = true;
o.depends({ uuid: '', label: '' });
for (var i = 0; i < devs.length; i++) {
var dev = devices[devs[i]];
for (let d of devs) {
const dev = devices[d];
if (dev.size)
o.value(dev.dev, '%s (%1024.2mB)'.format(dev.dev, dev.size));
else
@@ -315,8 +294,8 @@ return view.extend({
o = s.taboption('advanced', form.ListValue, 'fstype', _('Filesystem'));
o.textvalue = function(section_id) {
var dev = this.section.devices[section_id],
text = this.cfgvalue(section_id) || 'auto';
const dev = this.section.devices[section_id];
let text = this.cfgvalue(section_id) || 'auto';
if (dev && dev.type && dev.type != text)
text += ' (%s)'.format(dev.type);
@@ -326,8 +305,8 @@ return view.extend({
o.value('', 'auto');
for (var i = 0; i < filesystems.length; i++)
o.value(filesystems[i]);
for (let fs of filesystems)
o.value(fs);
o = s.taboption('advanced', form.Value, 'options', _('Mount options'), _('See "mount" manpage for details'));
o.textvalue = function(section_id) { return this.cfgvalue(section_id) || 'defaults' };
@@ -360,9 +339,8 @@ return view.extend({
o.modalonly = true;
o.value('', _('-- match by uuid --'));
var devs = Object.keys(devices).sort();
for (var i = 0; i < devs.length; i++) {
var dev = devices[devs[i]];
for (let d of devs) {
const dev = devices[d];
if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/))
continue;
@@ -377,8 +355,8 @@ return view.extend({
o.depends('uuid', '');
o.value('', _('-- match by label --'));
for (var i = 0; i < devs.length; i++) {
var dev = devices[devs[i]];
for (let d of devs) {
const dev = devices[d];
if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/))
continue;
@@ -392,8 +370,8 @@ return view.extend({
o.modalonly = true;
o.depends({ uuid: '', label: '' });
for (var i = 0; i < devs.length; i++) {
var dev = devices[devs[i]];
for (let d of devs) {
const dev = devices[d];
if (dev.dev.match(/^\/dev\/(mtdblock|ubi|ubiblock)\d/))
continue;

View File

@@ -7,52 +7,49 @@
'require form';
'require tools.widgets as widgets';
var callRcList, callRcInit, callTimezone,
callGetUnixtime, callSetLocaltime, CBILocalTime;
callRcList = rpc.declare({
const callRcList = rpc.declare({
object: 'rc',
method: 'list',
params: [ 'name' ],
expect: { '': {} },
filter: function(res) {
filter(res) {
for (var k in res)
return +res[k].enabled;
return null;
}
});
callRcInit = rpc.declare({
const callRcInit = rpc.declare({
object: 'rc',
method: 'init',
params: [ 'name', 'action' ],
expect: { result: false }
});
callGetUnixtime = rpc.declare({
const callGetUnixtime = rpc.declare({
object: 'luci',
method: 'getUnixtime',
expect: { result: 0 }
});
callSetLocaltime = rpc.declare({
const callSetLocaltime = rpc.declare({
object: 'luci',
method: 'setLocaltime',
params: [ 'localtime' ],
expect: { result: 0 }
});
callTimezone = rpc.declare({
const callTimezone = rpc.declare({
object: 'luci',
method: 'getTimezones',
expect: { '': {} }
});
function formatTime(epoch) {
var date = new Date(epoch * 1000),
zn = uci.get('system', '@system[0]', 'zonename')?.replaceAll(' ', '_') || 'UTC',
ts = uci.get('system', '@system[0]', 'clock_timestyle') || 0,
hc = uci.get('system', '@system[0]', 'clock_hourcycle') || 0;
const date = new Date(epoch * 1000);
const zn = uci.get('system', '@system[0]', 'zonename')?.replaceAll(' ', '_') || 'UTC';
const ts = uci.get('system', '@system[0]', 'clock_timestyle') || 0;
const hc = uci.get('system', '@system[0]', 'clock_hourcycle') || 0;
return new Intl.DateTimeFormat(undefined, {
dateStyle: 'medium',
@@ -62,8 +59,8 @@ function formatTime(epoch) {
}).format(date);
}
CBILocalTime = form.DummyValue.extend({
renderWidget: function(section_id, option_id, cfgvalue) {
const CBILocalTime = form.DummyValue.extend({
renderWidget(section_id, option_id, cfgvalue) {
return E([], [
E('input', {
'id': 'localtime',
@@ -94,7 +91,7 @@ CBILocalTime = form.DummyValue.extend({
});
return view.extend({
load: function() {
load() {
return Promise.all([
callRcList('sysntpd'),
callTimezone(),
@@ -104,11 +101,8 @@ return view.extend({
]);
},
render: function(rpc_replies) {
var ntpd_enabled = rpc_replies[0],
timezones = rpc_replies[1],
unixtime = rpc_replies[2],
m, s, o;
render([ntpd_enabled, timezones, unixtime]) {
let m, s, o;
m = new form.Map('system',
_('System'),
@@ -146,12 +140,12 @@ return view.extend({
o = s.taboption('general', form.ListValue, 'zonename', _('Timezone'));
o.value('UTC');
var zones = Object.keys(timezones || {}).sort();
for (var i = 0; i < zones.length; i++)
o.value(zones[i]);
const zones = Object.keys(timezones || {}).sort();
for (let zone of zones)
o.value(zone);
o.write = function(section_id, formvalue) {
var tz = timezones[formvalue] ? timezones[formvalue].tzstring : null;
const tz = timezones[formvalue] ? timezones[formvalue].tzstring : null;
uci.set('system', section_id, 'zonename', formvalue);
uci.set('system', section_id, 'timezone', tz);
};
@@ -236,21 +230,21 @@ return view.extend({
o.ucioption = 'lang';
o.value('auto', _('auto'));
var l = Object.assign({ en: 'English' }, uci.get('luci', 'languages')),
k = Object.keys(l).sort();
for (var i = 0; i < k.length; i++)
if (k[i].charAt(0) != '.')
o.value(k[i], l[k[i]]);
const l = Object.assign({ en: 'English' }, uci.get('luci', 'languages'));
const keys = Object.keys(l).sort();
for (let k of keys)
if (k.charAt(0) != '.')
o.value(k, l[k]);
o = s.taboption('language', form.ListValue, '_mediaurlbase', _('Design'))
o.uciconfig = 'luci';
o.ucisection = 'main';
o.ucioption = 'mediaurlbase';
var k = Object.keys(uci.get('luci', 'themes') || {}).sort();
for (var i = 0; i < k.length; i++)
if (k[i].charAt(0) != '.')
o.value(uci.get('luci', 'themes', k[i]), k[i]);
const th = Object.keys(uci.get('luci', 'themes') || {}).sort();
for (let t of th)
if (t.charAt(0) != '.')
o.value(uci.get('luci', 'themes', t), t);
o = s.taboption('language', form.Flag, '_tablefilters', _('Table Filters'));
o.default = o.disabled;