summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js22
-rw-r--r--modules/luci-base/luasrc/view/cbi/footer.htm56
-rw-r--r--modules/luci-base/luasrc/view/cbi/simpleform.htm122
-rw-r--r--modules/luci-base/luasrc/view/cbi/tblsection.htm126
-rw-r--r--modules/luci-mod-admin-full/luasrc/controller/admin/network.lua78
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua4
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua4
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm301
-rw-r--r--modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview_status.htm8
-rw-r--r--themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css36
-rw-r--r--themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css18
11 files changed, 524 insertions, 251 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index ddbff83418..89dfac9e46 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -1306,6 +1306,28 @@ function cbi_tag_last(container)
}
}
+function cbi_submit(elem, name, value, action)
+{
+ var form = elem.form || findParent(elem, 'form');
+
+ if (!form)
+ return false;
+
+ if (action)
+ form.action = action;
+
+ if (name) {
+ var hidden = form.querySelector('input[type="hidden"][name="%s"]'.format(name)) ||
+ E('input', { type: 'hidden', name: name });
+
+ hidden.value = value || '1';
+ form.appendChild(hidden);
+ }
+
+ form.submit();
+ return true;
+}
+
String.prototype.format = function()
{
if (!RegExp)
diff --git a/modules/luci-base/luasrc/view/cbi/footer.htm b/modules/luci-base/luasrc/view/cbi/footer.htm
index 5f939b6469..ed632202ce 100644
--- a/modules/luci-base/luasrc/view/cbi/footer.htm
+++ b/modules/luci-base/luasrc/view/cbi/footer.htm
@@ -1,23 +1,39 @@
- <%- if pageaction then -%>
- <div class="cbi-page-actions">
- <% if redirect and not flow.hidebackbtn then %>
- <input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" />
- <% end %>
-
- <% if flow.skip then %>
- <input class="cbi-button cbi-button-skip" type="submit" name="cbi.skip" value="<%:Skip%>" />
- <% end %>
- <% if not autoapply and not flow.hideapplybtn then %>
- <input class="cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
- <% end %>
- <% if not flow.hidesavebtn then %>
- <input class="cbi-button cbi-button-save" type="submit" value="<%:Save%>" />
- <% end %>
- <% if not flow.hideresetbtn then %>
- <input class="cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
- <% end %>
- </div>
- <%- end -%>
+<%
+ local display_back = (redirect and not flow.hidebackbtn)
+ local display_skip = (flow.skip)
+ local display_apply = (not autoapply and not flow.hideapplybtn)
+ local display_save = (not flow.hidesavebtn)
+ local display_reset = (not flow.hideresetbtn)
+
+ if pageaction and
+ (display_back or display_skip or display_apply or display_save or display_reset)
+ then
+ %><div class="cbi-page-actions"><%
+
+ if display_back then
+ %><input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" /> <%
+ end
+
+ if display_skip then
+ %><input class="cbi-button cbi-button-skip" type="button" value="<%:Skip%>" onclick="cbi_submit(this, 'cbi.skip')" /> <%
+ end
+
+ if display_apply then
+ %><input class="cbi-button cbi-button-apply" type="button" value="<%:Save & Apply%>" onclick="cbi_submit(this, 'cbi.apply')" /> <%
+ end
+
+ if display_save then
+ %><input class="cbi-button cbi-button-save" type="submit" value="<%:Save%>" /> <%
+ end
+
+ if display_reset then
+ %><input class="cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" /> <%
+ end
+
+ %></div><%
+ end
+%>
+
</form>
<script type="text/javascript">cbi_init();</script>
diff --git a/modules/luci-base/luasrc/view/cbi/simpleform.htm b/modules/luci-base/luasrc/view/cbi/simpleform.htm
index 5069e9f407..3e10724ec5 100644
--- a/modules/luci-base/luasrc/view/cbi/simpleform.htm
+++ b/modules/luci-base/luasrc/view/cbi/simpleform.htm
@@ -1,55 +1,77 @@
-<% if not self.embedded then %>
-<form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>">
- <div>
- <input type="hidden" name="token" value="<%=token%>" />
- <input type="hidden" name="cbi.submit" value="1" />
- </div>
-<% end %>
- <div class="cbi-map" id="cbi-<%=self.config%>">
- <% if self.title and #self.title > 0 then %><h2 name="content"><%=self.title%></h2><% end %>
- <% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
- <% self:render_children() %>
- </div>
-<%- if self.message then %>
- <div><%=self.message%></div>
-<%- end %>
-<%- if self.errmessage then %>
- <div class="error"><%=self.errmessage%></div>
-<%- end %>
-<% if not self.embedded then %>
- <div class="cbi-page-actions">
-<%-
- if type(self.hidden) == "table" then
- for k, v in pairs(self.hidden) do
--%>
- <input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" />
-<%-
+<%
+ if not self.embedded then
+ %><form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>">
+ <input type="hidden" name="token" value="<%=token%>" />
+ <input type="hidden" name="cbi.submit" value="1" /><%
+ end
+
+ %><div class="cbi-map" id="cbi-<%=self.config%>"><%
+
+ if self.title and #self.title > 0 then
+ %><h2 name="content"><%=self.title%></h2><%
+ end
+
+ if self.description and #self.description > 0 then
+ %><div class="cbi-map-descr"><%=self.description%></div><%
+ end
+
+ self:render_children()
+
+ %></div><%
+
+ if self.message then
+ %><div class="alert-message notice"><%=self.message%></div><%
+ end
+
+ if self.errmessage then
+ %><div class="alert-message warning"><%=self.errmessage%></div><%
+ end
+
+ if not self.embedded then
+ if type(self.hidden) == "table" then
+ local k, v
+ for k, v in pairs(self.hidden) do
+ %><input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" /><%
+ end
end
+
+ local display_back = (redirect)
+ local display_cancel = (self.cancel ~= false and self.on_cancel)
+ local display_skip = (self.flow and self.flow.skip)
+ local display_submit = (self.submit ~= false)
+ local display_reset = (self.reset ~= false)
+
+ if display_back or display_cancel or display_skip or display_submit or display_reset then
+ %><div class="cbi-page-actions"><%
+
+ if display_back then
+ %><input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" /> <%
+ end
+
+ if display_cancel then
+ local label = pcdata(self.cancel or translate("Cancel"))
+ %><input class="cbi-button cbi-button-link" type="button" value="<%=label%>" onclick="cbi_submit(this, 'cbi.cancel')" /> <%
+ end
+
+ if display_skip then
+ %><input class="cbi-button cbi-button-neutral" type="button" value="<%:Skip%>" onclick="cbi_submit(this, 'cbi.skip')" /> <%
+ end
+
+ if display_submit then
+ local label = pcdata(self.submit or translate("Submit"))
+ %><input class="cbi-button cbi-button-save" type="submit" value="<%=label%>" /> <%
+ end
+
+ if display_reset then
+ local label = pcdata(self.reset or translate("Reset"))
+ %><input class="cbi-button cbi-button-reset" type="reset" value="<%=label%>" /> <%
+ end
+
+ %></div><%
+ end
+
+ %></form><%
end
%>
-<% if redirect then %>
- <input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" />
-<% end %>
-<%- if self.cancel ~= false and self.on_cancel then %>
- <input class="cbi-button cbi-button-link" type="submit" name="cbi.cancel" value="
- <%- if not self.cancel then -%><%-:Cancel-%><%-else-%><%=self.cancel%><%end-%>
- " />
-<% end %>
-<%- if self.flow and self.flow.skip then %>
- <input class="cbi-button cbi-button-skip" type="submit" name="cbi.skip" value="<%:Skip%>" />
-<% end %>
-<%- if self.submit ~= false then %>
- <input class="cbi-button cbi-button-save" type="submit" value="
- <%- if not self.submit then -%><%-:Submit-%><%-else-%><%=self.submit%><%end-%>
- " />
-<% end %>
-<%- if self.reset ~= false then %>
- <input class="cbi-button cbi-button-reset" type="reset" value="
- <%- if not self.reset then -%><%-:Reset-%><%-else-%><%=self.reset%><%end-%>
- " />
-<% end %>
- </div>
-</form>
-<% end %>
<script type="text/javascript">cbi_init();</script>
diff --git a/modules/luci-base/luasrc/view/cbi/tblsection.htm b/modules/luci-base/luasrc/view/cbi/tblsection.htm
index 7067aa5876..9505f4ac4e 100644
--- a/modules/luci-base/luasrc/view/cbi/tblsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/tblsection.htm
@@ -1,8 +1,13 @@
<%-
-local rowcnt = 1
+local rowcnt = 0
+
function rowstyle()
rowcnt = rowcnt + 1
- return (rowcnt % 2) + 1
+ if rowcnt % 2 == 0 then
+ return "cbi-rowstyle-1"
+ else
+ return "cbi-rowstyle-2"
+ end
end
function width(o)
@@ -15,54 +20,115 @@ function width(o)
return ''
end
+local has_titles = false
+local has_descriptions = false
+
local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous"
local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name"))
+local i, k
+for i, k in pairs(self.children) do
+ if not k.typename then
+ k.typename = k.template and k.template:gsub("^.+/", "") or ""
+ end
+
+ if not has_titles and k.title and #k.title > 0 then
+ has_titles = true
+ end
+
+ if not has_descriptions and k.description and #k.description > 0 then
+ has_descriptions = true
+ end
+end
+
+function render_titles()
+ if not has_titles then
+ return
+ end
+
+ %><div class="tr cbi-section-table-titles <%=anonclass%>"<%=titlename%>><%
+
+ local i, k
+ for i, k in ipairs(self.children) do
+ if not k.optional then
+ %><div class="th cbi-section-table-cell"<%=
+ width(k) .. attr('data-type', k.typename) %>><%
+
+ if k.titleref then
+ %><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%
+ end
+
+ write(k.title)
+
+ if k.titleref then
+ %></a><%
+ end
+
+ %></div><%
+ end
+ end
+
+ if self.sortable or self.extedit or self.addremove then
+ %><div class="th cbi-section-table-cell cbi-section-actions"></div><%
+ end
+
+ %></div><%
+
+ rowcnt = rowcnt + 1
+end
+
+function render_descriptions()
+ if not has_descriptions then
+ return
+ end
+
+ %><div class="tr cbi-section-table-descr <%=anonclass%>"><%
+
+ local i, k
+ for i, k in ipairs(self.children) do
+ if not k.optional then
+ %><div class="th cbi-section-table-cell"<%=
+ width(k) .. attr("data-type", k.typename) %>><%
+
+ write(k.description)
+
+ %></div><%
+ end
+ end
+
+ if self.sortable or self.extedit or self.addremove then
+ %><div class="th cbi-section-table-cell cbi-section-actions"></div><%
+ end
+
+ %></div><%
+
+ rowcnt = rowcnt + 1
+end
+
-%>
<!-- tblsection -->
<div class="cbi-section cbi-tblsection" id="cbi-<%=self.config%>-<%=self.sectiontype%>">
<% if self.title and #self.title > 0 then -%>
- <legend><%=self.title%></legend>
+ <h3><%=self.title%></h3>
<%- end %>
<%- if self.sortable then -%>
<input type="hidden" id="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" name="cbi.sts.<%=self.config%>.<%=self.sectiontype%>" value="" />
<%- end -%>
<div class="cbi-section-descr"><%=self.description%></div>
- <%- local count = 0 -%>
<div class="table cbi-section-table">
- <div class="tr cbi-section-table-titles <%=anonclass%>"<%=titlename%>>
- <%- for i, k in pairs(self.children) do if not k.optional then -%>
- <div class="th cbi-section-table-cell"<%=
- width(k) ..
- attr("data-type", k.template and k.template:gsub("^.+/", "") or "")
- %>>
- <%- if k.titleref then -%><a title="<%=self.titledesc or translate('Go to relevant configuration page')%>" class="cbi-title-ref" href="<%=k.titleref%>"><%- end -%>
- <%-=k.title-%>
- <%- if k.titleref then -%></a><%- end -%>
- </div>
- <%- count = count + 1; end; end; if self.sortable or self.extedit or self.addremove then -%>
- <div class="th cbi-section-table-cell cbi-section-actions"></div>
- <%- count = count + 1; end -%>
- </div>
- <div class="tr cbi-section-table-descr <%=anonclass%>">
- <%- for i, k in pairs(self.children) do if not k.optional then -%>
- <div class="th cbi-section-table-cell"<%=
- width(k) ..
- attr("data-type", k.template and k.template:gsub("^.+/", "") or "")
- %>><%=k.description%></div>
- <%- end; end; if self.sortable or self.extedit or self.addremove then -%>
- <div class="th cbi-section-table-cell cbi-section-actions"></div>
- <%- end -%>
- </div>
- <%- local isempty, section, i, k = true, nil, nil
+ <%-
+ render_titles()
+ render_descriptions()
+
+ local isempty, section, i, k = true, nil, nil
for i, k in ipairs(self:cfgsections()) do
isempty = false
section = k
local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname)
- local colorclass = (self.extedit or self.rowcolors) and " cbi-rowstyle-%d" % rowstyle() or ""
+ local colorclass = (self.extedit or self.rowcolors) and rowstyle() or ""
local scope = {
valueheader = "cbi/cell_valueheader",
valuefooter = "cbi/cell_valuefooter"
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
index 31b9416253..c45605a983 100644
--- a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
+++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua
@@ -58,6 +58,12 @@ function index()
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.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
@@ -309,6 +315,78 @@ function wifi_assoclist()
luci.http.write_json(s.wifi_assoclist())
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 { }
+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(200, "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
+ for _, bss in ipairs(_wifi_get_scan_results(cache_key)) do
+ if not bssids[bss.bssid] then
+ bss.stale = true
+ data[#data + 1] = bss
+ 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 and #results > 0 then
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(results)
+ else
+ luci.http.status(404, "No wireless scan results")
+ end
+end
+
function lease_status()
local s = require "luci.tools.status"
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua
index e48e3b4bdf..ca66e9f365 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/iface_add.lua
@@ -10,6 +10,10 @@ m = SimpleForm("network", translate("Create Interface"))
m.redirect = luci.dispatcher.build_url("admin/network/network")
m.reset = false
+function m.on_cancel()
+ luci.http.redirect(luci.dispatcher.build_url("admin/network/network"))
+end
+
newnet = m:field(Value, "_netname", translate("Name of the new interface"),
translate("The allowed characters are: <code>A-Z</code>, <code>a-z</code>, " ..
"<code>0-9</code> and <code>_</code>"
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua
index dcd03cb0fe..32bf1965f3 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi_overview.lua
@@ -79,8 +79,8 @@ local tpl_radio = tpl.Template(nil, [[
<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="<%=dev:name()%>" onclick="wifi_restart(event)" />
- <input type="submit" class="cbi-button cbi-button-action important" title="<%:Find and join network%>" value="<%:Scan%>" data-radio="<%=dev:name()%>" onclick="wifi_action(event, 'join')" />
- <input type="submit" class="cbi-button cbi-button-add" title="<%:Provide new network%>" value="<%:Add%>" data-radio="<%=dev:name()%>" onclick="wifi_action(event, 'add')" />
+ <input type="button" class="cbi-button cbi-button-action important" title="<%:Find and join network%>" value="<%:Scan%>" onclick="cbi_submit(this, 'device', '<%=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', '<%=dev:name()%>', '<%=url('admin/network/wireless_add')%>')" />
</div>
</div>
</div>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm
index 9b93942c88..987123642f 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_join.htm
@@ -8,56 +8,6 @@
local sys = require "luci.sys"
local utl = require "luci.util"
- function guess_wifi_signal(info)
- local scale = (100 / (info.quality_max or 100) * (info.quality or 0))
- local icon
-
- if not info.bssid or info.bssid == "00:00:00:00:00:00" then
- icon = resource .. "/icons/signal-none.png"
- elseif scale < 15 then
- icon = resource .. "/icons/signal-0.png"
- elseif scale < 35 then
- icon = resource .. "/icons/signal-0-25.png"
- elseif scale < 55 then
- icon = resource .. "/icons/signal-25-50.png"
- elseif scale < 75 then
- icon = resource .. "/icons/signal-50-75.png"
- else
- icon = resource .. "/icons/signal-75-100.png"
- end
-
- return icon
- end
-
- function percent_wifi_signal(info)
- local qc = info.quality or 0
- local qm = info.quality_max or 0
-
- if info.bssid and qc > 0 and qm > 0 then
- return math.floor((100 / qm) * qc)
- else
- return 0
- end
- end
-
- function format_wifi_encryption(info)
- if info.wep == true then
- return "WEP"
- elseif info.wpa > 0 then
- return translatef("<abbr title='Pairwise: %s / Group: %s'>%s - %s</abbr>",
- table.concat(info.pair_ciphers, ", "),
- table.concat(info.group_ciphers, ", "),
- (info.wpa == 3) and translate("mixed WPA/WPA2")
- or (info.wpa == 2 and "WPA2" or "WPA"),
- table.concat(info.auth_suites, ", ")
- )
- elseif info.enabled then
- return "<em>%s</em>" % translate("unknown")
- else
- return "<em>%s</em>" % translate("open")
- end
- end
-
local dev = luci.http.formvalue("device")
local iw = luci.sys.wifi.getiwinfo(dev)
@@ -65,91 +15,198 @@
luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless"))
return
end
-
-
- function scanlist(times)
- local i, k, v
- local l = { }
- local s = { }
-
- for i = 1, times do
- for k, v in ipairs(iw.scanlist or { }) do
- if not s[v.bssid] then
- l[#l+1] = v
- s[v.bssid] = true
- end
- end
- end
-
- return l
- end
-%>
<%+header%>
+<script type="text/javascript">//<![CDATA[
+ var xhr = new XHR(),
+ 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: '<%:Signal%>: %d<%:dB%> / <%:Quality%>: %d/%d'.format(bss.signal, qval, qmax)
+ }, [
+ E('img', { src: '<%=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 if (enc.enabled)
+ return '<em><%:unknown%></em>';
+ else
+ return '<em><%:open%></em>';
+ }
+
+ function format_actions(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: '<%=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: <%=iw.type == "wl" and 1 or 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: '<%=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() {
+ XHR.stop(poll);
+ XHR.halt();
+
+ scan();
+ }
+
+ function scan() {
+ var tbl = document.getElementById('scan_results');
+
+ cbi_update_table(tbl, [], '<em><img src="<%=resource%>/icons/loading.gif" class="middle" /> <%:Starting wireless scan...%></em>');
+
+ xhr.post('<%=url("admin/network/wireless_scan_trigger", dev)%>', { token: '<%=token%>' },
+ function(s) {
+ if (s.status !== 200) {
+ cbi_update_table(tbl, [], '<em><%:Scan request failed%></em>');
+ return;
+ }
+
+ var count = 0;
+
+ poll = XHR.poll(3, '<%=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(res)
+ ]);
+ });
+
+ cbi_update_table(tbl, bss, '<em><img src="<%=resource%>/icons/loading.gif" class="middle" /> <%:No scan results available yet...%>');
+ }
+
+ if (count++ >= 3) {
+ count = 0;
+ xhr.post('<%=url("admin/network/wireless_scan_trigger", dev, "1")%>',
+ { token: '<%=token%>' }, function() { });
+ }
+ });
+
+ XHR.run();
+ });
+ }
+
+ document.addEventListener('DOMContentLoaded', scan);
+
+//]]></script>
+
<h2 name="content"><%:Join Network: Wireless Scan%></h2>
<div class="cbi-map">
<div class="cbi-section">
- <div class="table">
+ <div class="table" id="scan_results">
<div class="tr table-titles">
- <div class="th col-1 center"><%:Signal%></div>
- <div class="th col-5 left"><%:SSID%></div>
- <div class="th col-2 center"><%:Channel%></div>
- <div class="th col-2 left"><%:Mode%></div>
- <div class="th col-3 left"><%:BSSID%></div>
- <div class="th col-2 left"><%:Encryption%></div>
+ <div class="th col-1 middle center"><%:Signal%></div>
+ <div class="th col-5 middle left"><%:SSID%></div>
+ <div class="th col-2 middle center"><%:Channel%></div>
+ <div class="th col-2 middle left"><%:Mode%></div>
+ <div class="th col-3 middle left"><%:BSSID%></div>
+ <div class="th col-2 middle left"><%:Encryption%></div>
<div class="th cbi-section-actions">&#160;</div>
</div>
- <!-- scan list -->
- <% for i, net in ipairs(scanlist(3)) do net.encryption = net.encryption or { } %>
- <div class="tr cbi-rowstyle-<%=1 + ((i-1) % 2)%>">
- <div class="td col-1 center">
- <abbr title="<%:Signal%>: <%=net.signal%> <%:dB%> / <%:Quality%>: <%=net.quality%>/<%=net.quality_max%>">
- <img src="<%=guess_wifi_signal(net)%>" /><br />
- <small><%=percent_wifi_signal(net)%>%</small>
- </abbr>
- </div>
- <div class="td col-5 left" data-title="<%:SSID%>">
- <strong><%=net.ssid and utl.pcdata(net.ssid) or "<em>%s</em>" % translate("hidden")%></strong>
- </div>
- <div class="td col-2 center" data-title="<%:Channel%>">
- <%=net.channel%>
- </div>
- <div class="td col-2 left" data-title="<%:Mode%>">
- <%=net.mode%>
- </div>
- <div class="td col-3 left" data-title="<%:BSSID%>">
- <%=net.bssid%>
- </div>
- <div class="td col-2 left" data-title="<%:Encryption%>">
- <%=format_wifi_encryption(net.encryption)%>
- </div>
- <div class="td cbi-section-actions">
- <form 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="hidden" name="join" value="<%=utl.pcdata(net.ssid)%>" />
- <input type="hidden" name="mode" value="<%=net.mode%>" />
- <input type="hidden" name="bssid" value="<%=net.bssid%>" />
- <input type="hidden" name="channel" value="<%=net.channel%>" />
- <input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>" />
- <% if net.encryption.wpa then %>
- <input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>" />
- <% for _, v in ipairs(net.encryption.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>" />
- <% end; for _, v in ipairs(net.encryption.group_ciphers) do %><input type="hidden" name="wpa_group" value="<%=v%>" />
- <% end; for _, v in ipairs(net.encryption.pair_ciphers) do %><input type="hidden" name="wpa_pairwise" value="<%=v%>" />
- <% end; end %>
-
- <input type="hidden" name="clbridge" value="<%=iw.type == "wl" and 1 or 0%>" />
-
- <input class="cbi-button cbi-button-action important" type="submit" value="<%:Join Network%>" />
- </form>
+ <div class="tr placeholder">
+ <div class="td">
+ <img src="<%=resource%>/icons/loading.gif" class="middle" />
+ <em><%:Collecting data...%></em>
</div>
</div>
- <% end %>
- <!-- /scan list -->
</div>
</div>
</div>
@@ -160,7 +217,7 @@
<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 class="cbi-button cbi-button-action" type="submit" value="<%:Repeat scan%>" />
+ <input type="button" class="cbi-button cbi-button-action" value="<%:Repeat scan%>" onclick="flush()" />
</form>
</div>
diff --git a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview_status.htm b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview_status.htm
index cc6db1721f..9730bc2c92 100644
--- a/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview_status.htm
+++ b/modules/luci-mod-admin-full/luasrc/view/admin_network/wifi_overview_status.htm
@@ -26,14 +26,6 @@
{ token: '<%=token%>' }, XHR.run);
}
- function wifi_action(ev, action) {
- var i = ev.target,
- e = i.getAttribute('data-radio');
-
- i.parentNode.appendChild(E('input', { type: 'hidden', name: 'device', value: e }));
- i.form.action = '<%=url('admin/network/wireless_')%>' + action;
- }
-
var networks = [ ];
document.querySelectorAll('[data-network]').forEach(function(n) {
diff --git a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
index 4ca9e84f41..d0348a197e 100644
--- a/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
+++ b/themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
@@ -39,6 +39,7 @@ form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td,
abbr[title], acronym[title] {
border-bottom: 1px dotted;
+ font-weight: inherit;
cursor: help;
}
@@ -644,6 +645,7 @@ textarea[readonly] {
.cbi-page-actions > form {
display: inline;
+ margin: 0;
}
.help-inline, .help-block {
@@ -693,13 +695,13 @@ textarea[readonly] {
text-align: left;
}
-.table .th {
+.table .tr:first-child .th {
padding-top: 9px;
font-weight: bold;
- vertical-align: middle;
+ vertical-align: top;
}
-.table .td, .table .tbody .th {
+.table .td, .table .th {
border-top: 1px solid #ddd;
}
@@ -1257,9 +1259,15 @@ footer {
color: #c44;
}
-.cbi-page-actions .cbi-button-link,
-.cbi-page-actions form[method="get"]:first-child {
+.cbi-page-actions::after {
+ display: table;
+ content: "";
+ clear: both;
+}
+
+.cbi-page-actions > :not([method="post"]):not(.cbi-button-apply):not(.cbi-button-save):not(.cbi-button-reset) {
float: left;
+ margin-right: .4em;
}
.btn.primary,
@@ -1649,7 +1657,7 @@ a.label:hover {
cursor: pointer;
}
-form.inline { display: inline }
+form.inline { display: inline; margin-bottom: 0; }
header .pull-right { padding-top: 8px; }
@@ -1657,15 +1665,13 @@ header .pull-right { padding-top: 8px; }
#syslog { width: 100%; }
-.cbi-section-table tbody tr:nth-child(odd) td, .cbi-section-table tbody tr:nth-child(odd) th {
- background-color: #f9f9f9;
-}
-
-.cbi-section-table tbody tr:hover td, .cbi-section-table tbody tr:hover th {
+.cbi-section-table .tr:hover .td,
+.cbi-section-table .tr:hover .th,
+.cbi-section-table .tr:hover::before {
background-color: #f5f5f5;
}
-.cbi-section-table tr.cbi-section-table-descr th {
+.cbi-section-table .tr.cbi-section-table-descr .th {
font-weight: normal;
}
@@ -1680,6 +1686,8 @@ header .pull-right { padding-top: 8px; }
vertical-align: middle;
}
+.cbi-section-table-titles.named::before,
+.cbi-section-table-descr.named::before,
.cbi-section-table-row[data-title]::before {
border-top: 1px solid #ddd;
}
@@ -1744,7 +1752,9 @@ table table td,
vertical-align: middle;
}
-.cbi-rowstyle-2 {
+.cbi-rowstyle-2,
+.tr.table-titles,
+.tr.cbi-section-table-titles {
background: #f9f9f9;
}
diff --git a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css
index 29e7827aa4..dc36ab3f95 100644
--- a/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css
+++ b/themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css
@@ -837,15 +837,21 @@ div.cbi-optionals {
margin: 0 3px 0 0;
}
-.cbi-page-actions > .cbi-button-link,
-.cbi-page-actions > form[method="get"]:first-child {
- margin-right: auto;
+.cbi-page-actions > .cbi-button-save,
+.cbi-page-actions > .cbi-button-apply,
+.cbi-page-actions > form[method="post"] {
+ margin-left: auto;
}
*::-ms-backdrop,
-.cbi-page-actions > .cbi-button-link,
-.cbi-page-actions > form[method="get"]:first-child {
- margin-right: 50%;
+.cbi-page-actions > .cbi-button-save,
+.cbi-page-actions > .cbi-button-apply,
+.cbi-page-actions > form[method="post"] {
+ margin-left: 50%;
+}
+
+.cbi-page-actions > .cbi-button-apply + .cbi-button-save {
+ margin-left: 3px;
}
.th[data-type="button"], .td[data-type="button"],