luci-mod-network: switch to client side wifi configuration pages

Rewrite the wireless network management views in client side JS using ubus
rpc calls for the router communication.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2019-09-04 17:26:38 +02:00
parent dab0a11b73
commit 963b7636b4
11 changed files with 1925 additions and 2117 deletions

View file

@ -26,11 +26,10 @@
},
"ubus": {
"file": [ "list", "stat" ],
"iwinfo": [ "assoclist" ],
"iwinfo": [ "assoclist", "freqlist", "txpowerlist", "countrylist" ],
"luci": [ "getBoardJSON", "getDUIDHints", "getHostHints", "getIfaddrs", "getInitList", "getLocaltime", "getTimezones", "getDHCPLeases", "getLEDs", "getNetworkDevices", "getUSBDevices", "getHostname", "getTTYDevices", "getWirelessDevices" ],
"network.device": [ "status" ],
"network.interface": [ "dump" ],
"network.wireless": [ "status" ],
"network": [ "get_proto_handlers" ],
"uci": [ "changes", "get" ]
},
@ -45,7 +44,7 @@
"file": [ "remove" ],
"iwinfo": [ "scan" ],
"luci": [ "setInitAction", "setLocaltime" ],
"uci": [ "add", "apply", "confirm", "delete", "order", "set" ]
"uci": [ "add", "apply", "confirm", "delete", "order", "set", "rename" ]
},
"uci": [ "*" ]
}

View file

@ -1,164 +0,0 @@
var poll = null;
function format_signal(bss) {
var qval = bss.quality || 0,
qmax = bss.quality_max || 100,
scale = 100 / qmax * qval,
range = 'none';
if (!bss.bssid || bss.bssid == '00:00:00:00:00:00')
range = 'none';
else if (scale < 15)
range = '0';
else if (scale < 35)
range = '0-25';
else if (scale < 55)
range = '25-50';
else if (scale < 75)
range = '50-75';
else
range = '75-100';
return E('span', {
class: 'ifacebadge',
title: '%s: %d%s / %s: %d/%d'.format(_('Signal'), bss.signal, _('dB'), _('Quality'), qval, qmax)
}, [
E('img', { src: L.resource('icons/signal-%s.png').format(range) }),
' %d%%'.format(scale)
]);
}
function format_encryption(bss) {
var enc = bss.encryption || { }
if (enc.wep === true)
return 'WEP';
else if (enc.wpa > 0)
return E('abbr', {
title: 'Pairwise: %h / Group: %h'.format(
enc.pair_ciphers.join(', '),
enc.group_ciphers.join(', '))
},
'%h - %h'.format(
(enc.wpa === 3) ? _('mixed WPA/WPA2') : (enc.wpa === 2 ? 'WPA2' : 'WPA'),
enc.auth_suites.join(', ')));
else
return E('em', enc.enabled ? _('unknown') : _('open'));
}
function format_actions(dev, type, bss) {
var enc = bss.encryption || { },
input = [
E('input', { type: 'submit', class: 'cbi-button cbi-button-action important', value: _('Join Network') }),
E('input', { type: 'hidden', name: 'token', value: L.env.token }),
E('input', { type: 'hidden', name: 'device', value: dev }),
E('input', { type: 'hidden', name: 'join', value: bss.ssid }),
E('input', { type: 'hidden', name: 'mode', value: bss.mode }),
E('input', { type: 'hidden', name: 'bssid', value: bss.bssid }),
E('input', { type: 'hidden', name: 'channel', value: bss.channel }),
E('input', { type: 'hidden', name: 'clbridge', value: type === 'wl' ? 1 : 0 }),
E('input', { type: 'hidden', name: 'wep', value: enc.wep ? 1 : 0 })
];
if (enc.wpa) {
input.push(E('input', { type: 'hidden', name: 'wpa_version', value: enc.wpa }));
enc.auth_suites.forEach(function(s) {
input.push(E('input', { type: 'hidden', name: 'wpa_suites', value: s }));
});
enc.group_ciphers.forEach(function(s) {
input.push(E('input', { type: 'hidden', name: 'wpa_group', value: s }));
});
enc.pair_ciphers.forEach(function(s) {
input.push(E('input', { type: 'hidden', name: 'wpa_pairwise', value: s }));
});
}
return E('form', {
class: 'inline',
method: 'post',
action: L.url('admin/network/wireless_join')
}, input);
}
function fade(bss, content) {
if (bss.stale)
return E('span', { style: 'opacity:0.5' }, content);
else
return content;
}
function flush() {
L.stop(poll);
L.halt();
scan();
}
function scan() {
var tbl = document.querySelector('[data-wifi-scan]'),
dev = tbl.getAttribute('data-wifi-scan'),
type = tbl.getAttribute('data-wifi-type');
cbi_update_table(tbl, [], E('em', { class: 'spinning' }, _('Starting wireless scan...')));
L.post(L.url('admin/network/wireless_scan_trigger', dev), null, function(s) {
if (s.status !== 204) {
cbi_update_table(tbl, [], E('em', _('Scan request failed')));
return;
}
var count = 0;
poll = L.poll(3, L.url('admin/network/wireless_scan_results', dev), null, function(s, results) {
if (Array.isArray(results)) {
var bss = [];
results.sort(function(a, b) {
var diff = (b.quality - a.quality) || (a.channel - b.channel);
if (diff)
return diff;
if (a.ssid < b.ssid)
return -1;
else if (a.ssid > b.ssid)
return 1;
if (a.bssid < b.bssid)
return -1;
else if (a.bssid > b.bssid)
return 1;
}).forEach(function(res) {
bss.push([
fade(res, format_signal(res)),
fade(res, res.ssid ? '%h'.format(res.ssid) : E('em', {}, _('hidden'))),
fade(res, res.channel),
fade(res, res.mode),
fade(res, res.bssid),
fade(res, format_encryption(res)),
format_actions(dev, type, res)
]);
});
cbi_update_table(tbl, bss, E('em', {}, _('No networks in range')));
}
else {
cbi_update_table(tbl, [], E('em', { class: 'spinning' }, _('No scan results available yet...')));
}
if (count++ >= 3) {
count = 0;
L.post(L.url('admin/network/wireless_scan_trigger', dev, 1), null, function() {});
}
});
L.run();
});
}
document.addEventListener('DOMContentLoaded', scan);

View file

@ -1,59 +0,0 @@
requestAnimationFrame(function() {
document.querySelectorAll('[data-wifi-status]').forEach(function(container) {
var ifname = container.getAttribute('data-wifi-status'),
small = container.querySelector('small'),
info = container.querySelector('span');
L.poll(5, L.url('admin/network/wireless_status', ifname), null, function(xhr, iws) {
var iw = Array.isArray(iws) ? iws[0] : null;
if (!iw)
return;
var is_assoc = (iw.bssid && iw.bssid != '00:00:00:00:00:00' && iw.channel && !iw.disabled);
var p = iw.quality;
var q = iw.disabled ? -1 : p;
var icon;
if (q < 0)
icon = L.resource('icons/signal-none.png');
else if (q == 0)
icon = L.resource('icons/signal-0.png');
else if (q < 25)
icon = L.resource('icons/signal-0-25.png');
else if (q < 50)
icon = L.resource('icons/signal-25-50.png');
else if (q < 75)
icon = L.resource('icons/signal-50-75.png');
else
icon = L.resource('icons/signal-75-100.png');
L.dom.content(small, [
E('img', {
src: icon,
title: '%s: %d %s / %s: %d %s'.format(
_('Signal'), iw.signal, _('dBm'),
_('Noise'), iw.noise, _('dBm'))
}),
'\u00a0', E('br'), '%d%%\u00a0'.format(p)
]);
L.itemlist(info, [
_('Mode'), iw.mode,
_('SSID'), iw.ssid || '?',
_('BSSID'), is_assoc ? iw.bssid : null,
_('Encryption'), is_assoc ? iw.encryption || _('None') : null,
_('Channel'), is_assoc ? '%d (%.3f %s)'.format(iw.channel, iw.frequency || 0, _('GHz')) : null,
_('Tx-Power'), is_assoc ? '%d %s'.format(iw.txpower, _('dBm')) : null,
_('Signal'), is_assoc ? '%d %s'.format(iw.signal, _('dBm')) : null,
_('Noise'), is_assoc ? '%d %s'.format(iw.noise, _('dBm')) : null,
_('Bitrate'), is_assoc ? '%.1f %s'.format(iw.bitrate || 0, _('Mbit/s')) : null,
_('Country'), is_assoc ? iw.country : null
], [ ' | ', E('br'), E('br'), E('br'), E('br'), E('br'), ' | ', E('br'), ' | ' ]);
if (!is_assoc)
L.dom.append(info, E('em', iw.disabled ? _('Wireless is disabled') : _('Wireless is not associated')));
});
L.run();
});
});

View file

@ -37,42 +37,14 @@ function index()
end)
if has_wifi then
page = entry({"admin", "network", "wireless_join"}, post("wifi_join"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_add"}, post("wifi_add"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_status"}, call("wifi_status"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_reconnect"}, post("wifi_reconnect"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless_scan_trigger"}, post("wifi_scan_trigger"), nil)
page = entry({"admin", "network", "wireless"}, view("network/wireless"), _('Wireless'), 15)
page.leaf = true
page = entry({"admin", "network", "wireless_scan_results"}, call("wifi_scan_results"), nil)
page.leaf = true
page = entry({"admin", "network", "wireless"}, arcombine(cbi("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wireless"), 15)
page.leaf = true
page.subindex = true
if page.inreq then
local wdev
local net = require "luci.model.network".init(uci)
for _, wdev in ipairs(net:get_wifidevs()) do
local wnet
for _, wnet in ipairs(wdev:get_wifinets()) do
entry(
{"admin", "network", "wireless", wnet:id()},
alias("admin", "network", "wireless"),
wdev:name() .. ": " .. wnet:shortname()
)
end
end
end
end
@ -129,50 +101,6 @@ function index()
-- end
end
function wifi_join()
local tpl = require "luci.template"
local http = require "luci.http"
local dev = http.formvalue("device")
local ssid = http.formvalue("join")
if dev and ssid then
local cancel = (http.formvalue("cancel") or http.formvalue("cbi.cancel"))
if not cancel then
local cbi = require "luci.cbi"
local map = luci.cbi.load("admin_network/wifi_add")[1]
if map:parse() ~= cbi.FORM_DONE then
tpl.render("header")
map:render()
tpl.render("footer")
end
return
end
end
tpl.render("admin_network/wifi_join")
end
function wifi_add()
local dev = luci.http.formvalue("device")
local ntm = require "luci.model.network".init()
dev = dev and ntm:get_wifidev(dev)
if dev then
local net = dev:add_wifinet({
mode = "ap",
ssid = "OpenWrt",
encryption = "none",
disabled = 1
})
ntm:save("wireless")
luci.http.redirect(net:adminlink())
end
end
function iface_status(ifaces)
local netm = require "luci.model.network".init()
local rv = { }
@ -334,7 +262,7 @@ function wifi_status(devs)
end
function wifi_reconnect(radio)
local rc = luci.sys.call("env -i /sbin/wifi up %s" % luci.util.shellquote(radio))
local rc = luci.sys.call("env -i /sbin/wifi up %s >/dev/null" % luci.util.shellquote(radio))
if rc == 0 then
luci.http.status(200, "Reconnected")
@ -343,80 +271,6 @@ function wifi_reconnect(radio)
end
end
local function _wifi_get_scan_results(cache_key)
local results = luci.util.ubus("session", "get", {
ubus_rpc_session = luci.model.uci:get_session_id(),
keys = { cache_key }
})
if type(results) == "table" and
type(results.values) == "table" and
type(results.values[cache_key]) == "table"
then
return results.values[cache_key]
end
return nil
end
function wifi_scan_trigger(radio, update)
local iw = radio and luci.sys.wifi.getiwinfo(radio)
if not iw then
luci.http.status(404, "No such radio device")
return
end
luci.http.status(204, "Scan scheduled")
if nixio.fork() == 0 then
io.stderr:close()
io.stdout:close()
local _, bss
local data, bssids = { }, { }
local cache_key = "scan_%s" % radio
luci.util.ubus("session", "set", {
ubus_rpc_session = luci.model.uci:get_session_id(),
values = { [cache_key] = nil }
})
for _, bss in ipairs(iw.scanlist or { }) do
data[_] = bss
bssids[bss.bssid] = bss
end
if update then
local cached = _wifi_get_scan_results(cache_key)
if cached then
for _, bss in ipairs(cached) do
if not bssids[bss.bssid] then
bss.stale = true
data[#data + 1] = bss
end
end
end
end
luci.util.ubus("session", "set", {
ubus_rpc_session = luci.model.uci:get_session_id(),
values = { [cache_key] = data }
})
end
end
function wifi_scan_results(radio)
local results = radio and _wifi_get_scan_results("scan_%s" % radio)
if results then
luci.http.prepare_content("application/json")
luci.http.write_json(results)
else
luci.http.status(404, "No wireless scan results")
end
end
function switch_status(switches)
local s = require "luci.tools.status"

View file

@ -1,168 +0,0 @@
-- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local nw = require "luci.model.network"
local fw = require "luci.model.firewall"
local uci = require "luci.model.uci".cursor()
local http = require "luci.http"
local iw = luci.sys.wifi.getiwinfo(http.formvalue("device"))
local has_firewall = fs.access("/etc/config/firewall")
if not iw then
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
return
end
m = SimpleForm("network", translatef("Joining Network: %q", http.formvalue("join")))
m.cancel = translate("Back to scan results")
m.reset = false
function m.on_cancel()
local dev = http.formvalue("device")
http.redirect(luci.dispatcher.build_url(
dev and "admin/network/wireless_join?device=" .. dev
or "admin/network/wireless"
))
end
nw.init(uci)
fw.init(uci)
m.hidden = {
device = http.formvalue("device"),
join = http.formvalue("join"),
channel = http.formvalue("channel"),
mode = http.formvalue("mode"),
bssid = http.formvalue("bssid"),
wep = http.formvalue("wep"),
wpa_suites = http.formvalue("wpa_suites"),
wpa_version = http.formvalue("wpa_version")
}
if iw and iw.mbssid_support then
replace = m:field(Flag, "replace", translate("Replace wireless configuration"),
translate("Check this option to delete the existing networks from this radio."))
function replace.cfgvalue() return "0" end
else
replace = m:field(DummyValue, "replace", translate("Replace wireless configuration"))
replace.default = translate("The hardware is not multi-SSID capable and the existing " ..
"configuration will be replaced if you proceed.")
function replace.formvalue() return "1" end
end
if http.formvalue("wep") == "1" then
key = m:field(Value, "key", translate("WEP passphrase"),
translate("Specify the secret encryption key here."))
key.password = true
key.datatype = "wepkey"
elseif (tonumber(m.hidden.wpa_version) or 0) > 0 and
(m.hidden.wpa_suites == "PSK" or m.hidden.wpa_suites == "PSK2")
then
key = m:field(Value, "key", translate("WPA passphrase"),
translate("Specify the secret encryption key here."))
key.password = true
key.datatype = "wpakey"
--m.hidden.wpa_suite = (tonumber(http.formvalue("wpa_version")) or 0) >= 2 and "psk2" or "psk"
end
newnet = m:field(Value, "_netname_new", translate("Name of the new network"),
translate("The allowed characters are: <code>A-Z</code>, <code>a-z</code>, " ..
"<code>0-9</code> and <code>_</code>"
))
newnet.default = m.hidden.mode == "Ad-Hoc" and "mesh" or "wwan"
newnet.datatype = "uciname"
if has_firewall then
fwzone = m:field(Value, "_fwzone",
translate("Create / Assign firewall-zone"),
translate("Choose the firewall zone you want to assign to this interface. Select <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>create</em> field to define a new zone and attach the interface to it."))
fwzone.template = "cbi/firewall_zonelist"
fwzone.default = m.hidden.mode == "Ad-Hoc" and "mesh" or "wan"
end
function newnet.parse(self, section)
local net, zone
if has_firewall then
local value = fwzone:formvalue(section)
if value and #value > 0 then
zone = fw:get_zone(value) or fw:add_zone(value)
end
end
local wdev = nw:get_wifidev(m.hidden.device)
wdev:set("disabled", false)
wdev:set("channel", m.hidden.channel)
if replace:formvalue(section) then
local n
for _, n in ipairs(wdev:get_wifinets()) do
wdev:del_wifinet(n)
end
end
local wconf = {
device = m.hidden.device,
ssid = m.hidden.join,
mode = (m.hidden.mode == "Ad-Hoc" and "adhoc" or "sta")
}
if m.hidden.wep == "1" then
wconf.encryption = "wep-open"
wconf.key = "1"
wconf.key1 = key and key:formvalue(section) or ""
elseif (tonumber(m.hidden.wpa_version) or 0) > 0 then
wconf.encryption = (tonumber(m.hidden.wpa_version) or 0) >= 2 and "psk2" or "psk"
wconf.key = key and key:formvalue(section) or ""
else
wconf.encryption = "none"
end
if wconf.mode == "adhoc" or wconf.mode == "sta" then
wconf.bssid = m.hidden.bssid
end
local value = self:formvalue(section)
net = nw:add_network(value, { proto = "dhcp" })
if not net then
self.error = { [section] = "missing" }
else
wconf.network = net:name()
local wnet = wdev:add_wifinet(wconf)
if wnet then
if zone then
fw:del_network(net:name())
zone:add_network(net:name())
end
uci:save("wireless")
uci:save("network")
uci:save("firewall")
luci.http.redirect(wnet:adminlink())
end
end
end
if has_firewall then
function fwzone.cfgvalue(self, section)
self.iface = section
local z = fw:get_zone_by_network(section)
return z and z:name()
end
end
return m

View file

@ -1,153 +0,0 @@
-- Copyright 2018 Jo-Philipp Wich <jo@mein.io>
-- Licensed to the public under the Apache License 2.0.
local fs = require "nixio.fs"
local utl = require "luci.util"
local tpl = require "luci.template"
local ntm = require "luci.model.network"
local has_iwinfo = pcall(require, "iwinfo")
function guess_wifi_hw(dev)
local bands = ""
local ifname = dev:name()
local name, idx = ifname:match("^([a-z]+)(%d+)")
idx = tonumber(idx)
if has_iwinfo then
local bl = dev.iwinfo.hwmodelist
if bl and next(bl) then
if bl.a then bands = bands .. "a" end
if bl.b then bands = bands .. "b" end
if bl.g then bands = bands .. "g" end
if bl.n then bands = bands .. "n" end
if bl.ac then bands = bands .. "ac" end
end
local hw = dev.iwinfo.hardware_name
if hw then
return "%s 802.11%s" %{ hw, bands }
end
end
-- wl.o
if name == "wl" then
local name = translatef("Broadcom 802.11%s Wireless Controller", bands)
local nm = 0
local fd = nixio.open("/proc/bus/pci/devices", "r")
if fd then
local ln
for ln in fd:linesource() do
if ln:match("wl$") then
if nm == idx then
local version = ln:match("^%S+%s+%S%S%S%S([0-9a-f]+)")
name = translatef(
"Broadcom BCM%04x 802.11 Wireless Controller",
tonumber(version, 16)
)
break
else
nm = nm + 1
end
end
end
fd:close()
end
return name
-- dunno yet
else
return translatef("Generic 802.11%s Wireless Controller", bands)
end
end
m = Map("wireless", translate("Wireless Overview"))
m:chain("network")
m.pageaction = false
if not has_iwinfo then
s = m:section(NamedSection, "__warning__")
function s.render(self)
tpl.render_string([[
<div class="alert-message warning">
<h4><%:Package libiwinfo required!%></h4>
<p><%_The <em>libiwinfo-lua</em> package is not installed. You must install this component for working wireless configuration!%></p>
</div>
]])
end
end
local _, dev, net
for _, dev in ipairs(ntm:get_wifidevs()) do
s = m:section(TypedSection)
s.template = "admin_network/wifi_overview"
s.wnets = dev:get_wifinets()
s.dev = dev
s.hw = guess_wifi_hw(dev)
function s.cfgsections(self)
local _, net, sl = nil, nil, { }
for _, net in ipairs(self.wnets) do
sl[#sl+1] = net:name()
self.wnets[net:name()] = net
end
return sl
end
o = s:option(Value, "__disable__")
function o.cfgvalue(self, sid)
local wnet = self.section.wnets[sid]
local wdev = wnet:get_device()
return ((wnet and wnet:get("disabled") == "1") or
(wdev and wdev:get("disabled") == "1")) and "1" or "0"
end
function o.write(self, sid, value)
local wnet = self.section.wnets[sid]
local wdev = wnet:get_device()
if value ~= "1" then
wnet:set("disabled", nil)
wdev:set("disabled", nil)
else
wnet:set("disabled", "1")
end
end
o.remove = o.write
o = s:option(Value, "__delete__")
function o.write(self, sid, value)
local wnet = self.section.wnets[sid]
local nets = wnet:get_networks()
ntm:del_wifinet(wnet:id())
local _, net
for _, net in ipairs(nets) do
if net:is_empty() then
ntm:del_network(net:name())
end
end
end
end
s = m:section(NamedSection, "__assoclist__")
function s.render(self, sid)
tpl.render_string([[
<h2><%:Associated Stations%></h2>
<%+wifi_assoclist%>
]])
end
return m

View file

@ -1,59 +0,0 @@
<%#
Copyright 2009-2015 Jo-Philipp Wich <jow@openwrt.org>
Licensed to the public under the Apache License 2.0.
-%>
<%-
local sys = require "luci.sys"
local utl = require "luci.util"
local dev = luci.http.formvalue("device")
local iw = luci.sys.wifi.getiwinfo(dev)
if not iw then
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
return
end
-%>
<%+header%>
<h2 name="content"><%:Join Network: Wireless Scan%></h2>
<div class="cbi-map">
<div class="cbi-section">
<div class="table"<%=attr("data-wifi-scan", dev) .. attr("data-wifi-type", iw.type)%>>
<div class="tr table-titles">
<div class="th col-2 middle center"><%:Signal%></div>
<div class="th col-4 middle left"><%:SSID%></div>
<div class="th col-2 middle center hide-xs"><%:Channel%></div>
<div class="th col-2 middle left hide-xs"><%:Mode%></div>
<div class="th col-3 middle left hide-xs"><%:BSSID%></div>
<div class="th col-3 middle left"><%:Encryption%></div>
<div class="th cbi-section-actions">&#160;</div>
</div>
<div class="tr placeholder">
<div class="td">
<img src="<%=resource%>/icons/loading.gif" class="middle" />
<em><%:Collecting data...%></em>
</div>
</div>
</div>
</div>
</div>
<div class="cbi-page-actions right">
<form class="inline" action="<%=url("admin/network/wireless")%>" method="get">
<input class="cbi-button cbi-button-neutral" type="submit" value="<%:Back to overview%>" />
</form>
<form class="inline" action="<%=url('admin/network/wireless_join')%>" method="post">
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" />
<input type="button" class="cbi-button cbi-button-action" value="<%:Repeat scan%>" onclick="flush()" />
</form>
</div>
<script type="text/javascript" src="<%=resource%>/view/network/wifi_join.js"></script>
<%+footer%>

View file

@ -1,61 +0,0 @@
<div class="cbi-section-node">
<div class="table">
<!-- physical device -->
<div class="tr cbi-rowstyle-2">
<div class="td col-2 center middle">
<span class="ifacebadge"><img src="<%=resource%>/icons/wifi_disabled.png" id="<%=self.dev:name()%>-iw-upstate" /> <%=self.dev:name()%></span>
</div>
<div class="td col-7 left middle">
<big><strong><%=self.hw%></strong></big><br />
<span id="<%=self.dev:name()%>-iw-devinfo"></span>
</div>
<div class="td middle cbi-section-actions">
<div>
<input type="button" class="cbi-button cbi-button-neutral" title="<%:Restart radio interface%>" value="<%:Restart%>" data-radio="<%=self.dev:name()%>" onclick="wifi_restart(event)" />
<input type="button" class="cbi-button cbi-button-action important" title="<%:Find and join network%>" value="<%:Scan%>" onclick="cbi_submit(this, 'device', '<%=self.dev:name()%>', '<%=url('admin/network/wireless_join')%>')" />
<input type="button" class="cbi-button cbi-button-add" title="<%:Provide new network%>" value="<%:Add%>" onclick="cbi_submit(this, 'device', '<%=self.dev:name()%>', '<%=url('admin/network/wireless_add')%>')" />
</div>
</div>
</div>
<!-- /physical device -->
<!-- network list -->
<% if #self.wnets > 0 then %>
<% for i, net in ipairs(self.wnets) do local disabled = (self.dev:get("disabled") == "1" or net:get("disabled") == "1") %>
<div class="tr cbi-rowstyle-<%=1 + ((i-1) % 2)%>">
<div class="td col-2 center middle" id="<%=net:id()%>-iw-signal">
<span class="ifacebadge" title="<%:Not associated%>"><img src="<%=resource%>/icons/signal-<%= disabled and "none" or "0" %>.png" /> 0%</span>
</div>
<div class="td col-7 left middle" id="<%=net:id()%>-iw-status" data-network="<%=net:id()%>" data-disabled="<%= disabled and "true" or "false" %>">
<em><%= disabled and translate("Wireless is disabled") or translate("Collecting data...") %></em>
</div>
<div class="td middle cbi-section-actions">
<div>
<% if disabled then %>
<input name="cbid.wireless.<%=net:name()%>.__disable__" type="hidden" value="1" />
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-neutral" title="<%:Enable this network%>" value="<%:Enable%>" onclick="this.previousElementSibling.value='0'" />
<% else %>
<input name="cbid.wireless.<%=net:name()%>.__disable__" type="hidden" value="0" />
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-neutral" title="<%:Disable this network%>" value="<%:Disable%>" onclick="this.previousElementSibling.value='1'" />
<% end %>
<input type="button" class="cbi-button cbi-button-action important" onclick="location.href='<%=net:adminlink()%>'" title="<%:Edit this network%>" value="<%:Edit%>" />
<input name="cbid.wireless.<%=net:name()%>.__delete__" type="hidden" value="" />
<input name="cbi.apply" type="submit" class="cbi-button cbi-button-negative" title="<%:Delete this network%>" value="<%:Remove%>" onclick="wifi_delete(event)" />
</div>
</div>
</div>
<% end %>
<% else %>
<div class="tr placeholder">
<div class="td">
<em><%:No network configured on this device%></em>
</div>
</div>
<% end %>
<!-- /network list -->
</div>
</div>
<script type="text/javascript" src="<%=resource%>/view/network/wireless.js"></script>

View file

@ -1,14 +0,0 @@
<%+cbi/valueheader%>
<span class="ifacebadge large"<%=attr("data-wifi-status", self.ifname)%>>
<small>
<img src="<%=resource%>/icons/signal-none.png" title="<%:Not associated%>" />&#160;
</small>
<span>
<em class="spinning"><%:Collecting data...%></em>
</span>
</span>
<script type="text/javascript" src="<%=resource%>/view/network/wifi_status.js"></script>
<%+cbi/valuefooter%>