diff options
author | Dirk Brenken <dev@brenken.org> | 2021-08-11 18:28:07 +0200 |
---|---|---|
committer | Dirk Brenken <dev@brenken.org> | 2021-08-11 18:28:07 +0200 |
commit | 863238ee510d616021b0a74fb38dab6dd6ce809c (patch) | |
tree | bf4e544a3f6174a237605a751ace7ba1f9699042 /applications/luci-app-travelmate/htdocs | |
parent | 7f5becc69e004f831c9dc09e0859c179b439c7d2 (diff) |
luci-app-travelmate: sync with travelmate 2.0.5
* support new features of travelmate 2.0.5
* made the station manager more comfortable
* a few minor bugfixes
* sync translations
Signed-off-by: Dirk Brenken <dev@brenken.org>
Diffstat (limited to 'applications/luci-app-travelmate/htdocs')
2 files changed, 424 insertions, 289 deletions
diff --git a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js index b02f60a765..16d933e691 100644 --- a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js +++ b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/overview.js @@ -10,30 +10,32 @@ /* button handling */ -async function handleAction(ev) { +function handleAction(ev) { + var ifaceValue; if (ev === 'restart') { - fs.exec_direct('/etc/init.d/travelmate', [ev]) + ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'); + return fs.exec('/sbin/ifup', [ifaceValue]) + .then(fs.exec('/etc/init.d/travelmate', ['restart'])) } if (ev === 'setup') { - var ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || ''); + ifaceValue = String(uci.get('travelmate', 'global', 'trm_iface') || ''); L.ui.showModal(_('Interface Wizard'), [ E('p', _('To use Travelmate, you have to set up an uplink interface once. This wizard creates an IPv4- and an IPv6 alias network interface with all required network- and firewall settings.')), E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [ E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [ - E('input', { 'class': 'cbi-input-text', 'id': 'iface', 'placeholder': 'trm_wwan', 'value': ifaceValue, 'maxlength': '15', 'spellcheck': 'false' }, [ - ]), - '\xa0\xa0\xa0', - _('The uplink interface name') + E('input', { 'class': 'cbi-input-text', 'id': 'iface', 'placeholder': 'trm_wwan', 'value': ifaceValue, 'maxlength': '15', 'spellcheck': 'false' }), + '\xa0\xa0\xa0', + _('The uplink interface name') ]), E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [ - E('input', { 'class': 'cbi-input-text', 'id': 'zone', 'placeholder': 'wan', 'maxlength': '15', 'spellcheck': 'false' }), - '\xa0\xa0\xa0', - _('The firewall zone name') + E('input', { 'class': 'cbi-input-text', 'id': 'zone', 'placeholder': 'wan', 'maxlength': '15', 'spellcheck': 'false' }), + '\xa0\xa0\xa0', + _('The firewall zone name') ]), E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [ - E('input', { 'class': 'cbi-input-text', 'id': 'metric', 'placeholder': '100', 'maxlength': '3', 'spellcheck': 'false' }), - '\xa0\xa0\xa0', - _('The interface metric') + E('input', { 'class': 'cbi-input-text', 'id': 'metric', 'placeholder': '100', 'maxlength': '3', 'spellcheck': 'false' }), + '\xa0\xa0\xa0', + _('The interface metric') ]) ]), E('div', { 'class': 'right' }, [ @@ -44,18 +46,18 @@ async function handleAction(ev) { ' ', E('button', { 'class': 'cbi-button cbi-button-positive important', - 'click': ui.createHandlerFn(this, function(ev) { + 'click': ui.createHandlerFn(this, function (ev) { var iface = document.getElementById('iface').value || 'trm_wwan', - zone = document.getElementById('zone').value || 'wan', - metric = document.getElementById('metric').value || '100'; - L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['setup', iface, zone, metric])) - .then(function(res) { - if (res) { - ui.addNotification(null, E('p', res.trim() + '.'), 'error'); - } else { - ui.addNotification(null, E('p', _('The uplink interface has been updated.')), 'info'); - } - }); + zone = document.getElementById('zone').value || 'wan', + metric = document.getElementById('metric').value || '100'; + L.resolveDefault(fs.exec('/etc/init.d/travelmate', ['setup', iface, zone, metric])) + .then(function (res) { + if (res) { + ui.addNotification(null, E('p', res.trim() + '.'), 'error'); + } else { + ui.addNotification(null, E('p', _('The uplink interface has been updated.')), 'info'); + } + }); L.hideModal(); }) }, _('Save')) @@ -67,28 +69,28 @@ async function handleAction(ev) { if (ev === 'qrcode') { return Promise.all([ uci.load('wireless') - ]).then(function() { + ]).then(function () { var w_sid, w_device, w_ssid, w_enc, w_key, w_hidden, result, - w_sections = uci.sections('wireless', 'wifi-iface'), - optionsAP = [E('option', { value: '' }, [_('-- AP Selection --')])]; + w_sections = uci.sections('wireless', 'wifi-iface'), + optionsAP = [E('option', { value: '' }, [_('-- AP Selection --')])]; for (var i = 0; i < w_sections.length; i++) { if (w_sections[i].mode === 'ap' && w_sections[i].disabled !== '1') { - w_sid = i; + w_sid = i; w_device = w_sections[i].device; - w_ssid = w_sections[i].ssid; + w_ssid = w_sections[i].ssid; optionsAP.push(E('option', { value: w_sid }, w_device + ', ' + w_ssid)); } } var selectAP = E('select', { id: 'selectID', class: 'cbi-input-select', - change: function(ev) { + change: function (ev) { result = document.getElementById('qrcode'); if (document.getElementById("selectID").value) { - w_sid = document.getElementById("selectID").value; - w_ssid = w_sections[w_sid].ssid; - w_enc = w_sections[w_sid].encryption; - w_key = w_sections[w_sid].key; + w_sid = document.getElementById("selectID").value; + w_ssid = w_sections[w_sid].ssid; + w_enc = w_sections[w_sid].encryption; + w_key = w_sections[w_sid].key; w_hidden = (w_sections[w_sid].hidden == 1 ? 'true' : 'false'); if (w_enc.startsWith('psk')) { w_enc = 'WPA'; @@ -97,17 +99,17 @@ async function handleAction(ev) { w_enc = 'nopass'; w_key = 'nokey'; } - L.resolveDefault(fs.exec_direct('/usr/bin/qrencode', ['--inline', '--8bit', '--type=SVG', '--output=-', 'WIFI:S:' + w_ssid + ';T:' + w_enc + ';P:' + w_key + ';H:' + w_hidden + ';']), null).then(function(res) { + L.resolveDefault(fs.exec_direct('/usr/bin/qrencode', ['--inline', '--8bit', '--type=SVG', '--output=-', 'WIFI:S:' + w_ssid + ';T:' + w_enc + ';P:' + w_key + ';H:' + w_hidden + ';']), null).then(function (res) { if (res) { result.innerHTML = res.trim(); } else { - result.innerHTML = _('The QR-Code could not be generated!'); + result.textContent = _('The QR-Code could not be generated!'); } }); } else { - result.innerHTML = ''; + result.textContent = ''; } } }, optionsAP); @@ -135,13 +137,13 @@ async function handleAction(ev) { } return view.extend({ - load: function() { + load: function () { return Promise.all([ uci.load('travelmate') ]); }, - render: function(result) { + render: function (result) { var m, s, o; m = new form.Map('travelmate', 'Travelmate', _('Configuration of the travelmate package to enable travel router functionality. \ @@ -151,11 +153,11 @@ return view.extend({ /* poll runtime information */ - pollData: poll.add(function() { - return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function(res) { + pollData: poll.add(function () { + return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) { var status = document.getElementById('status'); if (res) { - L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function(res) { + L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) { if (res) { var info = JSON.parse(res); if (status && info) { @@ -206,12 +208,6 @@ return view.extend({ } }); } - else { - if (status && status.classList.contains("spinning")) { - status.textContent = '-'; - status.classList.remove("spinning"); - } - } }); }, 1); @@ -219,53 +215,68 @@ return view.extend({ runtime information and buttons */ s = m.section(form.NamedSection, 'global'); - s.render = L.bind(function(view, section_id) { + s.render = L.bind(function (view, section_id) { return E('div', { 'class': 'cbi-section' }, [ - E('h3', _('Information')), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')), - E('div', { 'class': 'cbi-value-field', 'id': 'status', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')), - E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station MAC')), - E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interface')), - E('div', { 'class': 'cbi-value-field', 'id': 'station_interface', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')), - E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')), - E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Ext. Hooks')), - E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), - E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')), - E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('h3', _('Information')), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')), + E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'color:#37c' }, '\xa0') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station ID')), + E('div', { 'class': 'cbi-value-field', 'id': 'station_id', 'style': 'color:#37c' }, '-') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station MAC')), + E('div', { 'class': 'cbi-value-field', 'id': 'station_mac', 'style': 'color:#37c' }, '-') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Station Interface')), + E('div', { 'class': 'cbi-value-field', 'id': 'station_interface', 'style': 'color:#37c' }, '-') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('WPA Flags')), + E('div', { 'class': 'cbi-value-field', 'id': 'wpa_flags', 'style': 'color:#37c' }, '-') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')), + E('div', { 'class': 'cbi-value-field', 'id': 'run_flags', 'style': 'color:#37c' }, '-') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Ext. Hooks')), + E('div', { 'class': 'cbi-value-field', 'id': 'ext_hooks', 'style': 'color:#37c' }, '-') + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')), + E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'color:#37c' }, '-') + ]), E('div', { class: 'right' }, [ E('button', { 'class': 'cbi-button cbi-button-apply', 'id': 'btn_suspend', - 'click': ui.createHandlerFn(this, function() { - L.resolveDefault(fs.stat('/usr/bin/qrencode'), null).then(function(res) { + 'click': ui.createHandlerFn(this, function () { + L.resolveDefault(fs.stat('/usr/bin/qrencode'), null).then(function (res) { if (res) { return handleAction('qrcode'); } return ui.addNotification(null, E('p', _('Please install the separate \'qrencode\' package.')), 'info'); }) }) - }, [ _('AP QR-Codes...') ]), + }, [_('AP QR-Codes...')]), + '\xa0', + E('button', { + 'class': 'cbi-button cbi-button-negative', + 'click': ui.createHandlerFn(this, function () { + return handleAction('restart'); + }) + }, [_('Restart Interface')]), '\xa0', E('button', { - 'class': 'cbi-button cbi-button-reset', - 'click': ui.createHandlerFn(this, function() { + 'class': 'cbi-button cbi-button-negative', + 'click': ui.createHandlerFn(this, function () { return handleAction('setup'); }) - }, [ _('Interface Wizard...') ]) + }, [_('Interface Wizard...')]) ]) ]); }, o, this); @@ -276,9 +287,8 @@ return view.extend({ */ s = m.section(form.NamedSection, 'global', 'travelmate', _('Settings')); s.addremove = false; - s.tab('general', _('General Settings')); + s.tab('general', _('General Settings')); s.tab('additional', _('Additional Settings')); - s.tab('adv_vpn', _('VPN Settings'), _('Please note: VPN connections require the separate setup of the <em>Wireguard</em> or <em>OpenVPN</em> package.<br /><p> </p>')); s.tab('adv_email', _('E-Mail Settings'), _('Please note: E-Mail notifications require the separate setup of the <em>mstmp</em> package.<br /><p> </p>')); /* @@ -290,8 +300,11 @@ return view.extend({ o = s.taboption('general', form.Flag, 'trm_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.')); o.rmempty = false; - o = s.taboption('general', form.Value, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order (e.g. \'radio1 radio0\').')); - o.placeholder = 'radio0'; + o = s.taboption('general', form.Value, 'trm_radio', _('Radio Selection'), _('Restrict travelmate to a single radio or change the overall scanning order.')); + o.value('radio0', _('use the first radio only (radio0)')); + o.value('radio1', _('use the second radio only (radio1)')); + o.value('radio0 radio1', _('use both radios, normal sort order (radio0 radio1)')); + o.value('radio1 radio0', _('use both radios, reverse sort order (radio1 radio0)')); o.rmempty = true; o = s.taboption('general', form.Flag, 'trm_captive', _('Captive Portal Detection'), _('Check the internet availability, handle captive portal redirections and keep the uplink connection \'alive\'.')); @@ -307,14 +320,20 @@ return view.extend({ o.default = 1; o.rmempty = false; - o = s.taboption('general', form.Flag, 'trm_autoadd', _('AutoAdd Open Uplinks'), _('Automatically add open uplinks like hotel captive portals to your wireless config.')); + o = s.taboption('general', form.Flag, 'trm_randomize', _('Randomize MAC Addresses'), _('Generate a random unicast MAC address for each uplink connection.')); o.default = 0; o.rmempty = false; - o = s.taboption('general', form.Flag, 'trm_randomize', _('Randomize MAC Addresses'), _('Generate a random unicast MAC address for each uplink connection.')); + o = s.taboption('general', form.Flag, 'trm_autoadd', _('AutoAdd Open Uplinks'), _('Automatically add open uplinks like hotel captive portals to your wireless config.')); o.default = 0; o.rmempty = false; + o = s.taboption('general', form.Value, 'trm_maxautoadd', _('Limit AutoAdd'), _('Limit the maximum number of automatically added open uplinks. To disable this limitation set it to \'0\'.')); + o.depends('trm_autoadd', '1'); + o.placeholder = '5'; + o.datatype = 'range(0,30)'; + o.rmempty = true; + /* additional settings tab */ @@ -349,19 +368,20 @@ return view.extend({ o.rmempty = true; o = s.taboption('additional', form.ListValue, 'trm_captiveurl', _('Captive Portal URL'), _('The selected URL will be used for connectivity- and captive portal checks.')); - o.value('http://captive.apple.com', 'Apple (default)'); + o.value('http://detectportal.firefox.com', 'Firefox (default)'); o.value('http://connectivity-check.ubuntu.com', 'Ubuntu'); + o.value('http://captive.apple.com', 'Apple'); o.value('http://connectivitycheck.android.com/generate_204', 'Google'); o.value('http://www.msftncsi.com/ncsi.txt', 'Microsoft'); o.optional = true; o.rmempty = true; o = s.taboption('additional', form.ListValue, 'trm_useragent', _('User Agent'), _('The selected user agent will be used for connectivity- and captive portal checks.')); - o.value('Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0', 'Firefox (default)'); - o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36', 'Chromium'); - o.value('Mozilla/5.0 (iPhone; CPU iPhone OS 13_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/85.0.4183.92 Mobile/15E148 Safari/604.1', 'Safari'); - o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44', 'Edge'); - o.value('Mozilla/5.0 (Linux; Android 10; SM-G970F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.81 Mobile Safari/537.36 OPR/59.1.2926.54067', 'Opera'); + o.value('Mozilla/5.0 (X11; Linux x86_64; rv:90.0) Gecko/20100101 Firefox/90.0', 'Firefox (default)'); + o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36', 'Chromium'); + o.value('Mozilla/5.0 (Macintosh; Intel Mac OS X 11_5_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15', 'Safari'); + o.value('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.55', 'Edge'); + o.value('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 OPR/77.0.4054.277', 'Opera'); o.optional = true; o.rmempty = true; @@ -375,30 +395,6 @@ return view.extend({ o.rmempty = true; /* - advanced vpn settings tab - */ - o = s.taboption('adv_vpn', form.Flag, 'trm_vpn', _('VPN Hook'), _('Automatically handle VPN (re-) connections.')); - o.rmempty = false; - - o = s.taboption('adv_vpn', form.ListValue, 'trm_vpnservice', _('VPN Service')); - o.depends('trm_vpn', '1'); - o.value('wireguard'); - o.value('openvpn'); - o.rmempty = true; - - o = s.taboption('adv_vpn', widgets.NetworkSelect, 'trm_vpniface', _('VPN Interface'), _('The logical vpn network interface, e.g. \'wg0\' or \'tun0\'.')); - o.depends('trm_vpn', '1'); - o.unspecified = false; - o.nocreate = true; - o.rmempty = true; - - o = s.taboption('adv_vpn', widgets.DeviceSelect, 'trm_landevice', _('LAN Device'), _('The lan network device, e.g. \'br-lan\'.')); - o.depends('trm_vpn', '1'); - o.unspecified = false; - o.nocreate = true; - o.rmempty = true; - - /* advanced email settings tab */ o = s.taboption('adv_email', form.Flag, 'trm_mail', _('E-Mail Hook'), _('Sends notification E-Mails after every succesful uplink connect.')); diff --git a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js index 2e149ad9b5..53bc2ec5aa 100644 --- a/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js +++ b/applications/luci-app-travelmate/htdocs/luci-static/resources/view/travelmate/stations.js @@ -9,10 +9,37 @@ 'require tools.widgets as widgets'; /* + change the status of travelmate stations +*/ +function handleToggle(sid) { + var w_device, w_ssid, w_bssid, t_sections, row, element, value, enabled; + + w_device = uci.get('wireless', sid, 'device'); + w_ssid = uci.get('wireless', sid, 'ssid'); + w_bssid = uci.get('wireless', sid, 'bssid'); + t_sections = uci.sections('travelmate', 'uplink'); + + for (var i = 0; i < t_sections.length; i++) { + if (t_sections[i].device === w_device && t_sections[i].ssid === w_ssid && t_sections[i].bssid === w_bssid) { + value = t_sections[i]['enabled']; + value = (value == 0 ? 1 : 0); + enabled = (value == 0 ? 'No' : 'Yes'); + uci.set('travelmate', t_sections[i]['.name'], 'enabled', value); + uci.save().then(function () { + row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid)); + element = row.querySelector('.cbi-value-field'); + element.textContent = enabled; + row.setAttribute('style', 'opacity: 0.5; color: #37c !important;'); + }); + } + } +} + +/* remove wireless and stale travelmate sections */ function handleRemove(sid) { - var w_sections, t_sections, match, changes; + var w_sections, t_sections, match, row; uci.remove('wireless', sid); w_sections = uci.sections('wireless', 'wifi-iface'); @@ -29,14 +56,17 @@ function handleRemove(sid) { uci.remove('travelmate', t_sections[i]['.name']); } } - uci.save(); + return uci.save().then(function () { + row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(sid)); + row.setAttribute('style', 'opacity: 0.5; color: #a22 !important;'); + }); } /* add missing travelmate sections */ function handleSectionsAdd(iface) { - var w_sections, t_sections, match, changes; + var w_sections, t_sections, match; w_sections = uci.sections('wireless', 'wifi-iface'); t_sections = uci.sections('travelmate', 'uplink'); @@ -69,9 +99,9 @@ function handleSectionsAdd(iface) { function handleSectionsVal(action, section_id, option, value) { var date, oldValue, w_device, w_ssid, w_bssid, t_sections; - w_device = uci.get('wireless', section_id, 'device'); - w_ssid = uci.get('wireless', section_id, 'ssid'); - w_bssid = uci.get('wireless', section_id, 'bssid'); + w_device = uci.get('wireless', section_id, 'device'); + w_ssid = uci.get('wireless', section_id, 'ssid'); + w_bssid = uci.get('wireless', section_id, 'bssid'); t_sections = uci.sections('travelmate', 'uplink'); for (var i = 0; i < t_sections.length; i++) { @@ -83,7 +113,7 @@ function handleSectionsVal(action, section_id, option, value) { if (option === 'enabled') { oldValue = t_sections[i][option]; if (oldValue !== value && value === '0') { - date = new Date(new Date().getTime() - new Date().getTimezoneOffset()*60*1000).toISOString().substr(0,19).replace(/-/g, '.').replace('T', '-'); + date = new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60 * 1000).toISOString().substr(0, 19).replace(/-/g, '.').replace('T', '-'); uci.set('travelmate', t_sections[i]['.name'], 'con_end', date); } else if (oldValue !== value && value === '1') { @@ -103,10 +133,10 @@ function handleSectionsVal(action, section_id, option, value) { update travelmate status */ function handleStatus() { - poll.add(function() { - L.resolveDefault(fs.stat('/var/state/travelmate.refresh'), null).then(function(res) { + poll.add(function () { + L.resolveDefault(fs.stat('/var/state/travelmate.refresh'), null).then(function (res) { if (res) { - L.resolveDefault(fs.read_direct('/var/state/travelmate.refresh'), null).then(function(res) { + L.resolveDefault(fs.read_direct('/var/state/travelmate.refresh'), null).then(async function (res) { fs.remove('/var/state/travelmate.refresh'); if (res && res === 'ui_reload') { location.reload(); @@ -116,36 +146,35 @@ function handleStatus() { uci.unload('wireless'); uci.unload('travelmate'); } - return Promise.all([ + await Promise.all([ uci.load('wireless'), uci.load('travelmate') - ]).then(function() { - var item, value, - container = document.querySelectorAll('.cbi-section-table-row[data-sid]'); - for (var i = 0; i < container.length; i++) { - item = container[i].querySelector('.cbi-value-field[data-title="Enabled"]'); - value = handleSectionsVal('get', container[i].getAttribute('data-sid'), 'enabled'); - item.textContent = (value == 0 ? 'No' : 'Yes'); - } - }); + ]); + var rows, item, value; + rows = document.querySelectorAll('.cbi-section-table-row[data-sid]'); + for (var i = 0; i < rows.length; i++) { + item = rows[i].querySelector('.cbi-value-field[data-title="Enabled"]'); + value = handleSectionsVal('get', rows[i].getAttribute('data-sid'), 'enabled'); + item.textContent = (value == 0 ? 'No' : 'Yes'); + } } }); } }); - return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function(res) { + return L.resolveDefault(fs.stat('/tmp/trm_runtime.json'), null).then(function (res) { if (res) { - L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function(res) { + L.resolveDefault(fs.read_direct('/tmp/trm_runtime.json'), null).then(function (res) { if (res) { var info = JSON.parse(res); if (info) { var t_device, t_ssid, t_bssid, oldUplinkView, newUplinkView, - uplinkId = info.data.station_id.trim().split('/'), - oldUplinkView = document.getElementsByName('uplinkStation'), - w_sections = uci.sections('wireless', 'wifi-iface'); + uplinkId = info.data.station_id.trim().split('/'), + oldUplinkView = document.getElementsByName('uplinkStation'), + w_sections = uci.sections('wireless', 'wifi-iface'); t_device = uplinkId[0]; - t_bssid = uplinkId[uplinkId.length-1]; - for (var i = 1; i < uplinkId.length-1; i++) { + t_bssid = uplinkId[uplinkId.length - 1]; + for (var i = 1; i < uplinkId.length - 1; i++) { if (!t_ssid) { t_ssid = uplinkId[i]; } @@ -185,29 +214,31 @@ function handleStatus() { } return view.extend({ - load: function() { + load: function () { return Promise.all([ + L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['assoc']), {}), uci.load('wireless'), uci.load('travelmate') ]); }, - render: function() { + render: function (result) { var m, s, o, - iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'; + iface = uci.get('travelmate', 'global', 'trm_iface') || 'trm_wwan'; m = new form.Map('wireless'); m.chain('travelmate'); s = m.section(form.GridSection, 'wifi-iface', null, _('Overview of all configured uplinks for travelmate.<br /> \ You can edit, remove or prioritize existing uplinks by drag \& drop and scan for new ones. The currently used uplink is emphasized in blue.')); s.anonymous = true; - s.sortable = true; - s.filter = function(section_id) { + s.sortable = true; + s.filter = function (section_id) { return (uci.get('wireless', section_id, 'network') == iface && uci.get('wireless', section_id, 'mode') == 'sta'); }; - s.tab('wireless', _('Wireless Settings')); + s.tab('wireless', _('Wireless Settings')); s.tab('travelmate', _('Travelmate Settings')); - s.renderRowActions = function(section_id) { + s.tab('vpn', _('VPN Settings')); + s.renderRowActions = function (section_id) { var btns; btns = [ E('button', { @@ -222,10 +253,15 @@ return view.extend({ 'click': ui.createHandlerFn(this, 'renderMoreOptionsModal', section_id) }, _('Edit')), E('button', { + 'class': 'cbi-button cbi-button-apply', + 'title': _('Enable/Disable this network'), + 'click': ui.createHandlerFn(this, handleToggle, section_id) + }, _('On/Off')), + E('button', { 'class': 'cbi-button cbi-button-negative remove', - 'title': _('Delete this network'), + 'title': _('Remove this network'), 'click': ui.createHandlerFn(this, handleRemove, section_id) - }, _('Del')) + }, _('Remove')) ]; return E('td', { 'class': 'td middle cbi-section-actions' }, E('div', btns)); }; @@ -235,10 +271,10 @@ return view.extend({ o.ucisection = 'uplink'; o.ucioption = 'enabled'; o.rmempty = false; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'enabled'); } - o.write = function(section_id, value) { + o.write = function (section_id, value) { return handleSectionsVal('set', section_id, 'enabled', value); } @@ -275,7 +311,7 @@ return view.extend({ o.value('owe', _('OWE')); o.value('none', _('none')); o.default = 'none'; - o.textvalue = function(section_id) { + o.textvalue = function (section_id) { var cfgvalue = this.map.data.get('wireless', section_id, 'encryption'); switch (cfgvalue) { case 'sae': @@ -401,6 +437,11 @@ return view.extend({ /* modal travelmate tab */ + var mac, mac_array = []; + if (result[0]) { + mac_array = result[0].trim().split('\n'); + } + o = s.taboption('travelmate', form.Value, '_ssid', _('SSID')); o.modalonly = true; o.uciconfig = 'travelmate'; @@ -408,7 +449,7 @@ return view.extend({ o.ucioption = 'ssid'; o.rmempty = false; o.readonly = true; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'ssid'); } @@ -419,7 +460,7 @@ return view.extend({ o.ucioption = 'bssid'; o.rmempty = true; o.readonly = true; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'bssid'); } @@ -430,7 +471,7 @@ return view.extend({ o.ucioption = 'con_start'; o.rmempty = true; o.readonly = true; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'con_start'); } @@ -441,10 +482,53 @@ return view.extend({ o.ucioption = 'con_end'; o.rmempty = true; o.readonly = true; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'con_end'); } + o = s.taboption('travelmate', form.Flag, '_opensta', _('Auto Added Open Uplink'), + _('This option is selected by default if this uplink was added automatically and counts as \'Open Uplink\'.')); + o.rmempty = true; + o.modalonly = true; + o.uciconfig = 'travelmate'; + o.ucisection = 'uplink'; + o.ucioption = 'opensta'; + o.cfgvalue = function (section_id) { + return handleSectionsVal('get', section_id, 'opensta'); + } + o.write = function (section_id, value) { + return handleSectionsVal('set', section_id, 'opensta', value); + } + o.remove = function (section_id, value) { + return handleSectionsVal('set', section_id, 'opensta', value); + } + + o = s.taboption('travelmate', form.Value, '_macaddr', _('MAC Address'), + _('Use the specified MAC address for this uplink.')); + for (var i = 0; i < mac_array.length; i++) { + if (mac_array[i].match(/^\s+([0-9A-Fa-f]{2}[:]?){5}[0-9A-Fa-f]{2}/)) { + mac = mac_array[i].slice(4).trim(); + o.value(mac); + } + } + o.modalonly = true; + o.uciconfig = 'travelmate'; + o.ucisection = 'uplink'; + o.ucioption = 'macaddr'; + o.nocreate = false; + o.unspecified = true; + o.rmempty = true; + o.datatype = 'macaddr'; + o.cfgvalue = function (section_id) { + return handleSectionsVal('get', section_id, 'macaddr'); + } + o.write = function (section_id, value) { + return handleSectionsVal('set', section_id, 'macaddr', value); + } + o.remove = function (section_id, value) { + return handleSectionsVal('set', section_id, 'macaddr', value); + } + o = s.taboption('travelmate', form.Value, '_con_start_expiry', _('Connection Start Expiry'), _('Automatically disable the uplink after <em>n</em> minutes, e.g. for timed connections.<br /> \ The default of \'0\' disables this feature.')); @@ -456,10 +540,10 @@ return view.extend({ o.placeholder = '0'; o.default = '0'; o.datatype = 'range(0,720)'; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'con_start_expiry'); } - o.write = function(section_id, value) { + o.write = function (section_id, value) { return handleSectionsVal('set', section_id, 'con_start_expiry', value); } @@ -474,10 +558,10 @@ return view.extend({ o.placeholder = '0'; o.default = '0'; o.datatype = 'range(0,720)'; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'con_end_expiry'); } - o.write = function(section_id, value) { + o.write = function (section_id, value) { return handleSectionsVal('set', section_id, 'con_end_expiry', value); } @@ -490,7 +574,7 @@ return view.extend({ o.uciconfig = 'travelmate'; o.ucisection = 'uplink'; o.ucioption = 'script'; - o.renderWidget = function(section_id, option_index, cfgvalue) { + o.renderWidget = function (section_id, option_index, cfgvalue) { var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, { id: this.cbid(section_id), name: this.cbid(section_id), @@ -500,23 +584,23 @@ return view.extend({ root_directory: this.root_directory, disabled: (this.readonly != null) ? this.readonly : this.map.readonly }); - browserEl.renderListing = function(container, path, list) { + browserEl.renderListing = function (container, path, list) { return ui.FileUpload.prototype.renderListing.apply(this, [ container, path, - list.filter(function(entry) { + list.filter(function (entry) { return ((entry.type == 'directory') || (entry.type == 'file' && entry.name.match(/\.login$/))); }) ]); }; return browserEl.render(); }; - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'script'); } - o.write = function(section_id, value) { + o.write = function (section_id, value) { return handleSectionsVal('set', section_id, 'script', value); } - o.remove = function(section_id) { + o.remove = function (section_id) { return handleSectionsVal('del', section_id, 'script'); } @@ -528,34 +612,84 @@ return view.extend({ o.ucioption = 'script_args'; o.rmempty = true; o.depends({ _script: '/etc/travelmate', '!contains': true }); - o.cfgvalue = function(section_id) { + o.cfgvalue = function (section_id) { return handleSectionsVal('get', section_id, 'script_args'); } - o.write = function(section_id, value) { + o.write = function (section_id, value) { return handleSectionsVal('set', section_id, 'script_args', value); } - o.remove = function(section_id) { + o.remove = function (section_id) { return handleSectionsVal('del', section_id, 'script_args'); } /* + modal vpn tab + */ + o = s.taboption('vpn', form.Flag, '_vpn', _('VPN Hook'), _('Automatically handle VPN connections.<br /> \ + Please note: This feature requires the additional configuration of <em>Wireguard</em> or <em>OpenVPN</em>.')); + o.rmempty = true; + o.modalonly = true; + o.uciconfig = 'travelmate'; + o.ucisection = 'uplink'; + o.ucioption = 'vpn'; + o.cfgvalue = function (section_id) { + return handleSectionsVal('get', section_id, 'vpn'); + } + o.write = function (section_id, value) { + return handleSectionsVal('set', section_id, 'vpn', value); + } + o.remove = function (section_id, value) { + return handleSectionsVal('set', section_id, 'vpn', value); + } + + o = s.taboption('vpn', form.ListValue, '_vpnservice', _('VPN Service')); + o.value('wireguard'); + o.value('openvpn'); + o.optional = true; + o.modalonly = true; + o.uciconfig = 'travelmate'; + o.ucisection = 'uplink'; + o.ucioption = 'vpnservice'; + o.cfgvalue = function (section_id) { + return handleSectionsVal('get', section_id, 'vpnservice'); + } + o.write = function (section_id, value) { + return handleSectionsVal('set', section_id, 'vpnservice', value); + } + + o = s.taboption('vpn', widgets.NetworkSelect, '_vpniface', _('VPN Interface'), _('The logical vpn network interface, e.g. \'wg0\' or \'tun0\'.')); + o.unspecified = false; + o.nocreate = true; + o.optional = true; + o.modalonly = true; + o.uciconfig = 'travelmate'; + o.ucisection = 'uplink'; + o.ucioption = 'vpniface'; + o.cfgvalue = function (section_id) { + return handleSectionsVal('get', section_id, 'vpniface'); + } + o.write = function (section_id, value) { + return handleSectionsVal('set', section_id, 'vpniface', value); + } + + /* scan buttons */ s = m.section(form.GridSection, 'wifi-device'); s.anonymous = true; s.addremove = false; - s.render = function() { - return network.getWifiDevices().then(L.bind(function(radios) { + s.render = function () { + return network.getWifiDevices().then(L.bind(function (radios) { var radio, ifname, btns = []; for (var i = 0; i < radios.length; i++) { - radio = radios[i].sid; + radio = radios[i].sid; if (radio) { btns.push(E('button', { - 'class': 'cbi-button cbi-button-apply', + 'class': 'cbi-button cbi-button-positive', 'id': radio, 'click': ui.createHandlerFn(this, 'handleScan', radio) - }, [ _('Scan on ' + radio + '...') ]), - '\xa0') + }, [_('Scan on ' + radio + '...')]), + '\xa0') } } return E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, E('div', { 'class': 'left', 'style': 'padding-top:5px; padding-bottom:5px' }, btns)); @@ -565,7 +699,7 @@ return view.extend({ /* modal 'scan' dialog */ - s.handleScan = function(radio) { + s.handleScan = function (radio) { var table = E('table', { 'class': 'table' }, [ E('tr', { 'class': 'tr table-titles' }, [ E('th', { 'class': 'th col-1 middle left' }, _('Strength')), @@ -596,117 +730,116 @@ return view.extend({ md.style.maxWidth = '90%'; md.style.maxHeight = 'none'; - return L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', [ 'scan', radio ]), null) - .then(L.bind(function(res) { - if (res) { + return L.resolveDefault(fs.exec_direct('/etc/init.d/travelmate', ['scan', radio]), null) + .then(L.bind(function (res) { var lines, strength, channel, encryption, tbl_encryption, bssid, ssid, tbl_ssid, rows = []; - lines = res.trim().split('\n'); - for (var i = 0; i < lines.length; i++) { - if (lines[i].match(/^\s+[0-9]/)) { - encryption = lines[i].slice(80).trim(); - if (!encryption.includes('WEP')) { - strength = lines[i].slice(4,7).trim(); - channel = lines[i].slice(15,18).trim(); - bssid = lines[i].slice(60,77).trim(); - ssid = lines[i].slice(25,59).trim(); - if (ssid.startsWith('"')) { - ssid = ssid.slice(1, ssid.length-1); - tbl_ssid = ssid; - } - else { - ssid = "hidden"; - tbl_ssid = "<em>hidden</em>"; - } - switch (encryption) { - case 'WPA3 PSK (SAE)': - encryption = 'sae'; - tbl_encryption = 'WPA3 Pers. (SAE)'; - break; - case 'mixed WPA2/WPA3 PSK/SAE (CCMP)': - encryption = 'sae-mixed'; - tbl_encryption = 'WPA2/WPA3 Pers. (CCMP)'; - break; - case 'WPA2 PSK (CCMP)': - encryption = 'psk2+ccmp'; - tbl_encryption = 'WPA2 Pers. (CCMP)'; - break; - case 'WPA2 PSK (TKIP)': - encryption = 'psk2+tkip'; - tbl_encryption = 'WPA2 Pers. (TKIP)'; - break; - case 'mixed WPA/WPA2 PSK (TKIP, CCMP)': - encryption = 'psk-mixed+ccmp'; - tbl_encryption = 'WPA/WPA2 Pers. (CCMP)'; - break; - case 'WPA3 802.1X (CCMP)': - encryption = 'wpa3'; - tbl_encryption = 'WPA3 Ent. (CCMP)'; - break; - case 'mixed WPA2/WPA3 802.1X (CCMP)': - encryption = 'wpa3-mixed'; - tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)'; - break; - case 'WPA PSK (CCMP)': - encryption = 'psk2+ccmp'; - tbl_encryption = 'WPA Pers. (CCMP)'; - break; - case 'WPA PSK (TKIP)': - encryption = 'psk2+tkip'; - tbl_encryption = 'WPA Pers. (TKIP)'; - break; - case 'WPA2 802.1X (CCMP)': - encryption = 'wpa2+ccmp'; - tbl_encryption = 'WPA2 Ent. (CCMP)'; - break; - case 'WPA3 OWE (CCMP)': - encryption = 'owe'; - tbl_encryption = 'WPA3 OWE (CCMP)'; - break; - case 'none': - encryption = 'none'; - tbl_encryption = 'none'; - break; + if (res) { + lines = res.trim().split('\n'); + for (var i = 0; i < lines.length; i++) { + if (lines[i].match(/^\s+[0-9]/)) { + encryption = lines[i].slice(80).trim(); + if (!encryption.includes('WEP')) { + strength = lines[i].slice(4, 7).trim(); + channel = lines[i].slice(15, 18).trim(); + bssid = lines[i].slice(60, 77).trim(); + ssid = lines[i].slice(25, 59).trim(); + if (ssid.startsWith('"')) { + ssid = ssid.slice(1, ssid.length - 1); + tbl_ssid = ssid; + } + else { + ssid = "hidden"; + tbl_ssid = "<em>hidden</em>"; + } + switch (encryption) { + case 'WPA3 PSK (SAE)': + encryption = 'sae'; + tbl_encryption = 'WPA3 Pers. (SAE)'; + break; + case 'mixed WPA2/WPA3 PSK/SAE (CCMP)': + encryption = 'sae-mixed'; + tbl_encryption = 'WPA2/WPA3 Pers. (CCMP)'; + break; + case 'WPA2 PSK (CCMP)': + encryption = 'psk2+ccmp'; + tbl_encryption = 'WPA2 Pers. (CCMP)'; + break; + case 'WPA2 PSK (TKIP)': + encryption = 'psk2+tkip'; + tbl_encryption = 'WPA2 Pers. (TKIP)'; + break; + case 'mixed WPA/WPA2 PSK (TKIP, CCMP)': + encryption = 'psk-mixed+ccmp'; + tbl_encryption = 'WPA/WPA2 Pers. (CCMP)'; + break; + case 'WPA3 802.1X (CCMP)': + encryption = 'wpa3'; + tbl_encryption = 'WPA3 Ent. (CCMP)'; + break; + case 'mixed WPA2/WPA3 802.1X (CCMP)': + encryption = 'wpa3-mixed'; + tbl_encryption = 'WPA2/WPA3 Ent. (CCMP)'; + break; + case 'WPA PSK (CCMP)': + encryption = 'psk2+ccmp'; + tbl_encryption = 'WPA Pers. (CCMP)'; + break; + case 'WPA PSK (TKIP)': + encryption = 'psk2+tkip'; + tbl_encryption = 'WPA Pers. (TKIP)'; + break; + case 'WPA2 802.1X (CCMP)': + encryption = 'wpa2+ccmp'; + tbl_encryption = 'WPA2 Ent. (CCMP)'; + break; + case 'WPA3 OWE (CCMP)': + encryption = 'owe'; + tbl_encryption = 'WPA3 OWE (CCMP)'; + break; + case 'none': + encryption = 'none'; + tbl_encryption = 'none'; + break; + } + rows.push([ + strength, + channel, + tbl_ssid, + bssid, + tbl_encryption, + E('div', { 'class': 'right' }, E('button', { + 'class': 'cbi-button cbi-button-action', + 'click': ui.createHandlerFn(this, 'handleAdd', radio, iface, ssid, bssid, encryption) + }, _('Add Uplink...'))) + ]); } + } + else if (lines[i] === '::: Empty resultset') { rows.push([ - strength, - channel, - tbl_ssid, - bssid, - tbl_encryption, - E('div', { 'class': 'right' }, E('button', { - 'class': 'cbi-button cbi-button-action', - 'click': ui.createHandlerFn(this, 'handleAdd', radio, iface, ssid, bssid, encryption) - }, _('Add Uplink...'))) + 'No scan results (empty resultset)' ]); } } - else if (lines[i] === '::: No scan results') { - rows.push([ - 'No scan results' - ]); - } } - } - else { - rows.push([ - 'No scan results' - ]); - } - cbi_update_table(table, rows); - }, this)); + else { + rows.push([ + 'No scan results (timeout)' + ]); + } + cbi_update_table(table, rows); + }, this)); }; /* modal 'add' dialog */ - s.handleAdd = function(radio, iface, ssid, bssid, encryption, ev) { - ui.hideModal; + s.handleAdd = function (radio, iface, ssid, bssid, encryption, ev) { var m2, s2, o2; m2 = new form.Map('wireless'), - s2 = m2.section(form.NamedSection, '_add_trm'); + s2 = m2.section(form.NamedSection, '_add_trm'); - s2.render = function() { + s2.render = function () { return Promise.all([ {}, this.renderUCISection('_add_trm') @@ -819,7 +952,7 @@ return view.extend({ o2.password = true; o2.rmempty = true; - return m2.render().then(L.bind(function(elements) { + return m2.render().then(L.bind(function (elements) { ui.showModal(_('Add Uplink %q').replace(/%q/, '"%h"'.format(ssid)), [ elements, E('div', { 'class': 'right' }, [ @@ -830,7 +963,7 @@ return view.extend({ '\xa0', E('button', { 'class': 'cbi-button cbi-button-positive important', - 'click': ui.createHandlerFn(this, 'handleSave', m2) + 'click': ui.createHandlerFn(this, 'handleCommit', m2) }, _('Save')) ]) ]); @@ -840,16 +973,16 @@ return view.extend({ /* save new uplink */ - s.handleSave = function(map, ev) { + s.handleCommit = function (map, ev) { var w_sections = uci.sections('wireless', 'wifi-iface'), - device = L.toArray(map.lookupOption('device', '_add_trm'))[0].formvalue('_add_trm'), - network = L.toArray(map.lookupOption('network', '_add_trm'))[0].formvalue('_add_trm'), - ssid = L.toArray(map.lookupOption('ssid', '_add_trm'))[0].formvalue('_add_trm'), - ignore_bssid = L.toArray(map.lookupOption('ignore_bssid', '_add_trm'))[0].formvalue('_add_trm'), - bssid = L.toArray(map.lookupOption('bssid', '_add_trm'))[0].formvalue('_add_trm'), - encryption = L.toArray(map.lookupOption('encryption', '_add_trm'))[0].formvalue('_add_trm'), - password = L.toArray(map.lookupOption('key', '_add_trm'))[0].formvalue('_add_trm'); - if (!ssid || ((encryption.includes('psk') || encryption.includes('wpa') || encryption.includes('sae')) && !password )) { + device = L.toArray(map.lookupOption('device', '_add_trm'))[0].formvalue('_add_trm'), + network = L.toArray(map.lookupOption('network', '_add_trm'))[0].formvalue('_add_trm'), + ssid = L.toArray(map.lookupOption('ssid', '_add_trm'))[0].formvalue('_add_trm'), + ignore_bssid = L.toArray(map.lookupOption('ignore_bssid', '_add_trm'))[0].formvalue('_add_trm'), + bssid = L.toArray(map.lookupOption('bssid', '_add_trm'))[0].formvalue('_add_trm'), + encryption = L.toArray(map.lookupOption('encryption', '_add_trm'))[0].formvalue('_add_trm'), + password = L.toArray(map.lookupOption('key', '_add_trm'))[0].formvalue('_add_trm'); + if (!ssid || ((encryption.includes('psk') || encryption.includes('wpa') || encryption.includes('sae')) && !password)) { if (!ssid) { ui.addNotification(null, E('p', 'Empty SSID, the uplink station could not be saved.'), 'error'); } @@ -867,8 +1000,8 @@ return view.extend({ } } - var offset = w_sections.length, - new_sid = 'trm_uplink' + (++offset); + var offset = w_sections.length, + new_sid = 'trm_uplink' + (++offset); while (uci.get('wireless', new_sid)) { new_sid = 'trm_uplink' + (++offset); } @@ -884,8 +1017,14 @@ return view.extend({ uci.set('wireless', new_sid, 'key', password); uci.set('wireless', new_sid, 'disabled', '1'); handleSectionsAdd(network); - uci.save(); - ui.hideModal(); + uci.save() + .then(L.bind(this.map.load, this.map)) + .then(L.bind(this.map.reset, this.map)) + .then(function () { + var row = document.querySelector('.cbi-section-table-row[data-sid="%s"]'.format(new_sid)); + row.setAttribute('style', 'opacity: 0.5; color: #4a4 !important;'); + }) + .then(ui.hideModal) }; return m.render(); }, |