'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";
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];
// 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 {
]
};
-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);
}
}
-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();
function drawLegend(config, dataSet){
let ctx = config.ctx;
let graphWidth = config.graphWidth;
- let graphHeight = config.graphHeight;
ctx.font = "12px Arial";
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";
function drawAxisY(config, minValue, maxValue, step, title) {
let ctx = config.ctx
- let graphWidth = config.graphWidth;
let graphHeight = config.graphHeight;
ctx.font = "12px Arial";
'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.')),
'require poll';
'require rpc';
-var callDSLMetrics = rpc.declare({
+const callDSLMetrics = rpc.declare({
object: 'dsl',
method: 'metrics',
expect: { '': {} }
}
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));
}, this));
},
- formatHelper: function(format, val) {
+ formatHelper(format, val) {
if (val != null) {
if (format instanceof Function) {
return format(val);
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 ]),
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 ]),
return E('div', { 'class': 'cbi-section' }, table);
},
- renderContent: function(data) {
+ renderContent(data) {
return E([], [
E('h3', {}, [ _('Connection State') ]),
]);
},
- 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);
},
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
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':
},
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));
// 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) {
'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');
}
function deviceSectionExists(section_id, devname) {
- var exists = false;
+ let exists = false;
uci.sections('network', 'device', function(ss) {
exists = exists || (
if (dev.isBridgePort())
return true;
- var isPort = false;
+ let isPort = false;
uci.sections('network', null, function(s) {
if (s['.type'] != 'interface' && s['.type'] != 'device')
}
function updateDevBadge(node, dev) {
- var type = dev.getType(),
- up = dev.getCarrier();
+ const type = dev.getType();
+ const up = dev.getCarrier();
dom.content(node, [
E('img', {
}
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');
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':
}
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) == '!') {
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!')
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';
});
-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') ])
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]);
{
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;
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;
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;
}
};
- var node = widget.render();
+ const node = widget.render();
node.style.minWidth = '4em';
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];
}
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('');
uci.set('network', section_id, 'ports', ports.length ? ports : null);
},
- remove: function() {}
+ remove() {}
});
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) {
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'));
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':
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':
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':
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':
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':
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':
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':
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;
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');
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);
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);
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':
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);
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');
};
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);
};
};
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();
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;
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';
};
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');
}
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'));
}
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 = {
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);
};
if (rrnum !== '65') return null;
let hexdata = uci.get('dhcp', section_id, 'hexdata');
+ // eslint-disable-next-line no-undef
return drh.parseSvcbHex(hexdata);
};
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;
}
}
function render_status(node, ifc, with_device) {
- var desc = null, c = [];
+ let desc = null;
if (ifc.isDynamic())
desc = _('Virtual dynamic interface');
}
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 = [ ' (' ];
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);
}
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');
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;
' ',
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...')));
}
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);
}
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...')));
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...'))
return Promise.all([ resolveZone, network.flushCache() ]);
},
- load: function() {
+ load() {
return Promise.all([
network.getDSLModemType(),
network.getDevices(),
]);
},
- 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,
.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.')),
]);
},
- handleIfnameMigration: function(ev) {
- var tasks = [];
+ handleIfnameMigration(ev) {
+ const tasks = [];
this.deviceWithIfnameSections().forEach(function(ds) {
tasks.push(uci.callSet('network', ds['.name'], {
.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.')),
]);
},
- 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;
};
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());
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),
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;
};
}
- 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')) {
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 ]);
}
- 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];
;
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.
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' ]);
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,
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,
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]);
});
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.'));
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') {
});
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);
});
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':
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;
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);
}
};
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)
};
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());
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;
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();
};
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) {
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;
}
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_'));
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),
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);
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');
};
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'));
};
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) {
};
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)
});
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);
};
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) {
};
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 '':
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';
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.')
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.')
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).') + ' ' +
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));
}
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);
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));
}));
}
'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;
'<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;
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;
}
_('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'));
};
+ '<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'));
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;
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);
});
_('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;
'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';
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);
}
}
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)));
}
}
}
}
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' ],
});
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])));
});
},
- 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));
};
}
- 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);
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');
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);
}
}
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);
};
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;
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);
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);
};
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'));
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;
const data_wanted = Math.floor(width / step);
const data_values = [];
- const line_elements = [];
for (const line of lines)
if (line)
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())
'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');
]);
},
- 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;
})
},
- 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);
}
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);
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) {
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);
}, 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;
-
- var rows = [];
-
- for (var i = 0; i < results.length; i++) {
- if (scanCache[results[i].bssid] == null)
- scanCache[results[i].bssid] = {};
-
- scanCache[results[i].bssid].data = results[i];
- scanCache[results[i].bssid].data.stale = false;
+ ]).then(L.bind(function([results, local_wifi]) {
+ const table = radio.table;
+ const chan_analysis = radio.graph;
+ const scanCache = radio.scanCache;
+ const band = radio.band;
+
+ const rows = [];
+
+ for (let res of results) {
+ if (scanCache[res.bssid] == null)
+ scanCache[res.bssid] = {};
+
+ scanCache[res.bssid].data = res;
+ scanCache[res.bssid].data.stale = false;
}
if (band + 'g' == radio.dev.get('band')) {
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);
}
}
- for (var k in scanCache)
+ for (let k in scanCache)
if (scanCache[k].data.stale)
results.push(scanCache[k].data);
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)
/* 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) {
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)),
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);
}, this))
},
- radios : {},
+ radios: {},
- loadSVG : function(src) {
+ loadSVG(src) {
return request.get(src).then(function(response) {
if (!response.ok)
throw new Error(response.statusText);
});
},
- 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; })
]);
},
- 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', {
}, [ _('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: [] },
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')),
'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');
-
- 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'));
+ 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');
+
+ 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);
});
},
- updateConntrack: async function(conn) {
+ async updateConntrack(conn) {
async function fetchServices() {
if (!enableLookups) return;
if (Object.keys(service_cache).length > 0) return;
}
},
- 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;
-
- var data_scale = 0;
- var data_wanted = Math.floor(ctx.width / ctx.step);
- var last_timestamp = NaN;
-
- for (var i = 0, di = 0; di < lines.length; di++) {
+ 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;
+
+ let data_scale = 0;
+ let data_wanted = Math.floor(ctx.width / ctx.step);
+ let last_timestamp = NaN;
+
+ 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;
/* 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];
}
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));
}, this), pollInterval);
},
- loadSVG: function(src) {
+ loadSVG(src) {
return request.get(src).then(function(response) {
if (!response.ok)
throw new Error(response.statusText);
});
},
- 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' }, [
]);
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);
*/
],
- retrieveLog: async function() {
+ async retrieveLog() {
return fs.exec_direct('/bin/dmesg', [ '-r' ]).then(logdata => {
let loglines = [];
let lastSeverity = null;
});
},
- pollLog: async function() {
+ async pollLog() {
const element = document.getElementById('syslog');
if (element) {
const log = await this.retrieveLog();
}
},
- 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',
'id': 'logSeveritySelect',
'class': 'cbi-input-select',
},
- this.severity.map(([val, tag, label]) =>
+ this.severity.map(([val, , label]) =>
E('option', { value: val }, label)
));
'require network';
'require firewall';
-var callGetBuiltinEthernetPorts = rpc.declare({
+const callGetBuiltinEthernetPorts = rpc.declare({
object: 'luci',
method: 'getBuiltinEthernetPorts',
expect: { result: [] }
function resolveVLANChain(ifname, bridges, mapping)
{
while (!mapping[ifname]) {
- var m = ifname.match(/^(.+)\.([^.]+)$/);
+ const m = ifname.match(/^(.+)\.([^.]+)$/);
if (!m)
break;
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);
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;
}
}
/* 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;
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));
}
}
}
}
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);
}
}
}
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):
}
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'),
}
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:');
return baseclass.extend({
title: _('Port status'),
- load: function() {
+ load() {
return Promise.all([
L.resolveDefault(callGetBuiltinEthernetPorts(), []),
L.resolveDefault(fs.read('/etc/board.json'), '{}'),
});
},
- render: function(data) {
+ render(data) {
if (L.hasSystemFeature('swconfig'))
return null;
}
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;
},
render(data) {
- const seen = {};
const radios = data[0];
const networks = data[1];
const hosthints = data[2];
'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) }, [
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);
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>'
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 = '';
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);
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);
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) {
}, 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'), ' ',
}, 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))));
}
}
}, 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) {
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;
}
},
- 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');
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');
});
},
- 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))) }),
]);
},
- 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 }',
'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');
-
- 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'));
+ 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');
+
+ 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);
});
},
- 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;
-
- var data_scale = 0;
- var data_wanted = Math.floor(ctx.width / ctx.step);
- var last_timestamp = NaN;
-
- for (var i = 0, di = 0; di < lines.length; di++) {
+ 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;
+
+ let data_scale = 0;
+ let data_wanted = Math.floor(ctx.width / ctx.step);
+ let last_timestamp = NaN;
+
+ 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;
/* 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];
}
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));
}, this), pollInterval);
},
- loadSVG: function(src) {
+ loadSVG(src) {
return request.get(src).then(function(response) {
if (!response.ok)
throw new Error(response.statusText);
});
},
- 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' }, [
]);
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);
'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'),
'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'),
'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'),
};
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':
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];
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)];
spec = expr;
}
else {
- for (var k in expr) {
+ for (let k in expr) {
if (expr.hasOwnProperty(k)) {
kind = k;
spec = expr[k];
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>';
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('+');
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);
}
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);
}
},
- 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)));
return { match: matchElem, actions: actions };
},
- renderMatchExpr: function(spec) {
+ renderMatchExpr(spec) {
switch (spec.op) {
case '==':
case '!=':
);
},
- 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' }, [
]) : E([]);
},
- renderRateUnit: function(value, unit) {
+ renderRateUnit(value, unit) {
if (!unit)
unit = 'packets';
);
},
- 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];
if (!kind)
return E([]);
+ let k;
+ let a = [];
+
switch (kind) {
case 'match':
return this.renderMatchExpr(spec);
}, 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'
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';
]);
case 'redirect':
- var k = 'redirect',
- a = [];
+ k = 'redirect';
if (spec && spec.port) {
k += '.port';
));
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
];
}
},
- 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' }, [
]);
},
- renderComment: function(comment) {
+ renderComment(comment) {
return E('span', { 'class': 'ifacebadge cbi-tooltip-container nft-comment' }, [
E('var', [ '#' ]),
E('div', { 'class': 'cbi-tooltip' }, [
]);
},
- 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 {
return row;
},
- renderChain: function(data, spec) {
- var title, policy, hook;
+ renderChain(data, spec) {
+ let title, policy, hook;
switch (spec.type) {
case 'filter':
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 ])
])
]));
- 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' }, [
return node;
},
- renderTable: function(data, spec) {
- var title;
+ renderTable(data, spec) {
+ let title;
switch (spec.family) {
case 'ip':
break;
}
- var node = E([], [
+ const node = E([], [
E('style', { 'type': 'text/css' }, [
'.nft-rules .ifacebadge { margin: .125em }',
'.nft-rules tr > td { padding: .25em !important }',
])
]);
- 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.')),
}
},
- 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;
},
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+/);
const data_wanted = Math.floor(width / step);
- const data_values = [],
- line_elements = [];
+ const data_values = [];
for (const line of lines)
if (line)
'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' ],
});
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':
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;
}
-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'),
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'
form.parentNode.removeChild(form);
},
- handleFirstboot: function(ev) {
+ handleFirstboot(ev) {
if (!confirm(_('Do you really want to erase all settings?')))
return;
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…');
}, 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) {
.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'
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…');
}, 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' ],
])));
};
- var cntbtn = E('button', {
+ const cntbtn = E('button', {
'class': 'btn cbi-button-action important',
'click': ui.createHandlerFn(this, 'handleSysupgradeConfirm', btn, opts),
}, [ _('Continue') ]);
}, 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]);
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, [
});
},
- 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() {
});
},
- 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;
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]);
});
'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){
}
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'),
});
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);
}
}
}
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 || ' ';
}
};
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;
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);
'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];
}
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)
.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;
-
- var fsck = {
- ext2: results[3],
- ext3: results[3],
- ext4: results[3],
- f2fs: results[4],
- vfat: results[5],
- btrfs: results[6],
- ntfs: results[7]
- };
+ render([devices, procfs, etcfs]) {
+ let m, s, o;
- var filesystems = {};
+ let filesystems = {};
- for (var i = 0; i < procfs.length; i++)
- if (procfs[i].match(/\S/) && !procfs[i].match(/^nodev\t/))
- filesystems[procfs[i].trim()] = true;
+ for (let p of procfs)
+ if (p.match(/\S/) && !p.match(/^nodev\t/))
+ filesystems[p.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();
};
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')),
])
]);
- 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') ]) : '-'
]);
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)
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)
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
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);
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' };
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;
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;
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;
'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',
}).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',
});
return view.extend({
- load: function() {
+ load() {
return Promise.all([
callRcList('sysntpd'),
callTimezone(),
]);
},
- 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'),
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);
};
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;