summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/luasrc
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-base/luasrc')
-rw-r--r--modules/luci-base/luasrc/cbi/datatypes.lua4
-rw-r--r--modules/luci-base/luasrc/controller/admin/index.lua18
-rw-r--r--modules/luci-base/luasrc/dispatcher.lua84
-rw-r--r--modules/luci-base/luasrc/dispatcher.luadoc9
-rw-r--r--modules/luci-base/luasrc/model/ipkg.lua247
-rw-r--r--modules/luci-base/luasrc/model/ipkg.luadoc125
-rw-r--r--modules/luci-base/luasrc/model/network.lua8
-rw-r--r--modules/luci-base/luasrc/sys.lua94
-rw-r--r--modules/luci-base/luasrc/sys.luadoc36
-rw-r--r--modules/luci-base/luasrc/view/cbi/apply_widget.htm92
-rw-r--r--modules/luci-base/luasrc/view/cbi/browser.htm2
-rw-r--r--modules/luci-base/luasrc/view/cbi/dynlist.htm18
-rw-r--r--modules/luci-base/luasrc/view/cbi/map.htm34
-rw-r--r--modules/luci-base/luasrc/view/cbi/nsection.htm1
-rw-r--r--modules/luci-base/luasrc/view/cbi/tabcontainer.htm15
-rw-r--r--modules/luci-base/luasrc/view/cbi/tabmenu.htm12
-rw-r--r--modules/luci-base/luasrc/view/cbi/tsection.htm2
-rw-r--r--modules/luci-base/luasrc/view/cbi/value.htm2
-rw-r--r--modules/luci-base/luasrc/view/header.htm11
-rw-r--r--modules/luci-base/luasrc/view/wifi_assoclist.htm40
20 files changed, 291 insertions, 563 deletions
diff --git a/modules/luci-base/luasrc/cbi/datatypes.lua b/modules/luci-base/luasrc/cbi/datatypes.lua
index 99113e0b7a..b4206e98df 100644
--- a/modules/luci-base/luasrc/cbi/datatypes.lua
+++ b/modules/luci-base/luasrc/cbi/datatypes.lua
@@ -460,3 +460,7 @@ function dateyyyymmdd(val)
end
return false
end
+
+function unique(val)
+ return true
+end
diff --git a/modules/luci-base/luasrc/controller/admin/index.lua b/modules/luci-base/luasrc/controller/admin/index.lua
index 39004c6760..1f7db0cb38 100644
--- a/modules/luci-base/luasrc/controller/admin/index.lua
+++ b/modules/luci-base/luasrc/controller/admin/index.lua
@@ -80,6 +80,9 @@ function index()
if has_wifi then
page = entry({"admin", "wireless_assoclist"}, call("wifi_assoclist"), nil)
page.leaf = true
+
+ page = entry({"admin", "wireless_deauth"}, post("wifi_deauth"), nil)
+ page.leaf = true
end
page = entry({"admin", "translations"}, call("action_translations"), nil)
@@ -144,3 +147,18 @@ function wifi_assoclist()
luci.http.prepare_content("application/json")
luci.http.write_json(s.wifi_assoclist())
end
+
+function wifi_deauth()
+ local iface = luci.http.formvalue("iface")
+ local bssid = luci.http.formvalue("bssid")
+
+ if iface and bssid then
+ luci.util.ubus("hostapd.%s" % iface, "del_client", {
+ addr = bssid,
+ deauth = true,
+ reason = 5,
+ ban_time = 60000
+ })
+ end
+ luci.http.status(200, "OK")
+end
diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua
index 1e610e7489..d85cb58243 100644
--- a/modules/luci-base/luasrc/dispatcher.lua
+++ b/modules/luci-base/luasrc/dispatcher.lua
@@ -40,6 +40,28 @@ function build_url(...)
return table.concat(url, "")
end
+function _ordered_children(node)
+ local name, child, children = nil, nil, {}
+
+ for name, child in pairs(node.nodes) do
+ children[#children+1] = {
+ name = name,
+ node = child,
+ order = child.order or 100
+ }
+ end
+
+ table.sort(children, function(a, b)
+ if a.order == b.order then
+ return a.name < b.name
+ else
+ return a.order < b.order
+ end
+ end)
+
+ return children
+end
+
function node_visible(node)
if node then
return not (
@@ -55,15 +77,10 @@ end
function node_childs(node)
local rv = { }
if node then
- local k, v
- for k, v in util.spairs(node.nodes,
- function(a, b)
- return (node.nodes[a].order or 100)
- < (node.nodes[b].order or 100)
- end)
- do
- if node_visible(v) then
- rv[#rv+1] = k
+ local _, child
+ for _, child in ipairs(_ordered_children(node)) do
+ if node_visible(child.node) then
+ rv[#rv+1] = child.name
end
end
end
@@ -417,6 +434,7 @@ function dispatch(request)
context.path = {}
http.status(403, "Forbidden")
+ http.header("X-LuCI-Login-Required", "yes")
tmpl.render(track.sysauth_template or "sysauth", {
duser = default_user,
fuser = user
@@ -433,6 +451,7 @@ function dispatch(request)
if not sid or not sdat then
http.status(403, "Forbidden")
+ http.header("X-LuCI-Login-Required", "yes")
return
end
@@ -593,11 +612,9 @@ function createtree()
local ctx = context
local tree = {nodes={}, inreq=true}
- local modi = {}
ctx.treecache = setmetatable({}, {__mode="v"})
ctx.tree = tree
- ctx.modifiers = modi
local scope = setmetatable({}, {__index = luci.dispatcher})
@@ -607,28 +624,9 @@ function createtree()
v()
end
- local function modisort(a,b)
- return modi[a].order < modi[b].order
- end
-
- for _, v in util.spairs(modi, modisort) do
- scope._NAME = v.module
- setfenv(v.func, scope)
- v.func()
- end
-
return tree
end
-function modifier(func, order)
- context.modifiers[#context.modifiers+1] = {
- func = func,
- order = order or 0,
- module
- = getfenv(2)._NAME
- }
-end
-
function assign(path, clone, title, order)
local obj = node(unpack(path))
obj.nodes = nil
@@ -718,24 +716,7 @@ end
-- Subdispatchers --
function _find_eligible_node(root, prefix, deep, types, descend)
- local _, cur_name, cur_node
- local childs = { }
-
- for cur_name, cur_node in pairs(root.nodes) do
- childs[#childs+1] = {
- node = cur_node,
- name = cur_name,
- order = cur_node.order or 100
- }
- end
-
- table.sort(childs, function(a, b)
- if a.order == b.order then
- return a.name < b.name
- else
- return a.order < b.order
- end
- end)
+ local children = _ordered_children(root)
if not root.leaf and deep ~= nil then
local sub_path = { unpack(prefix) }
@@ -744,10 +725,11 @@ function _find_eligible_node(root, prefix, deep, types, descend)
deep = nil
end
- for _, cur_node in ipairs(childs) do
- sub_path[#prefix+1] = cur_node.name
+ local _, child
+ for _, child in ipairs(children) do
+ sub_path[#prefix+1] = child.name
- local res_path = _find_eligible_node(cur_node.node, sub_path,
+ local res_path = _find_eligible_node(child.node, sub_path,
deep, types, true)
if res_path then
diff --git a/modules/luci-base/luasrc/dispatcher.luadoc b/modules/luci-base/luasrc/dispatcher.luadoc
index f26256953a..a77f8d8b07 100644
--- a/modules/luci-base/luasrc/dispatcher.luadoc
+++ b/modules/luci-base/luasrc/dispatcher.luadoc
@@ -82,15 +82,6 @@ Build the index before if it does not exist yet.
]]
---[[
-Register a tree modifier.
-
-@class function
-@name modifier
-@param func Modifier function
-@param order Modifier order value (optional)
-]]
-
----[[
Clone a node of the dispatching tree to another position.
@class function
diff --git a/modules/luci-base/luasrc/model/ipkg.lua b/modules/luci-base/luasrc/model/ipkg.lua
deleted file mode 100644
index e27ea52895..0000000000
--- a/modules/luci-base/luasrc/model/ipkg.lua
+++ /dev/null
@@ -1,247 +0,0 @@
--- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
--- Copyright 2008 Steven Barth <steven@midlink.org>
--- Licensed to the public under the Apache License 2.0.
-
-local os = require "os"
-local io = require "io"
-local fs = require "nixio.fs"
-local util = require "luci.util"
-
-local type = type
-local pairs = pairs
-local error = error
-local table = table
-
-local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
-local icfg = "/etc/opkg.conf"
-
-module "luci.model.ipkg"
-
-
--- Internal action function
-local function _action(cmd, ...)
- local cmdline = { ipkg, cmd }
-
- local k, v
- for k, v in pairs({...}) do
- cmdline[#cmdline+1] = util.shellquote(v)
- end
-
- local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ")
- local r = os.execute(c)
- local e = fs.readfile("/tmp/opkg.stderr")
- local o = fs.readfile("/tmp/opkg.stdout")
-
- fs.unlink("/tmp/opkg.stderr")
- fs.unlink("/tmp/opkg.stdout")
-
- return r, o or "", e or ""
-end
-
--- Internal parser function
-local function _parselist(rawdata)
- if type(rawdata) ~= "function" then
- error("OPKG: Invalid rawdata given")
- end
-
- local data = {}
- local c = {}
- local l = nil
-
- for line in rawdata do
- if line:sub(1, 1) ~= " " then
- local key, val = line:match("(.-): ?(.*)%s*")
-
- if key and val then
- if key == "Package" then
- c = {Package = val}
- data[val] = c
- elseif key == "Status" then
- c.Status = {}
- for j in val:gmatch("([^ ]+)") do
- c.Status[j] = true
- end
- else
- c[key] = val
- end
- l = key
- end
- else
- -- Multi-line field
- c[l] = c[l] .. "\n" .. line
- end
- end
-
- return data
-end
-
--- Internal lookup function
-local function _lookup(cmd, pkg)
- local cmdline = { ipkg, cmd }
- if pkg then
- cmdline[#cmdline+1] = util.shellquote(pkg)
- end
-
- -- OPKG sometimes kills the whole machine because it sucks
- -- Therefore we have to use a sucky approach too and use
- -- tmpfiles instead of directly reading the output
- local tmpfile = os.tmpname()
- os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile })
-
- local data = _parselist(io.lines(tmpfile))
- os.remove(tmpfile)
- return data
-end
-
-
-function info(pkg)
- return _lookup("info", pkg)
-end
-
-function status(pkg)
- return _lookup("status", pkg)
-end
-
-function install(...)
- return _action("install", ...)
-end
-
-function installed(pkg)
- local p = status(pkg)[pkg]
- return (p and p.Status and p.Status.installed)
-end
-
-function remove(...)
- return _action("remove", ...)
-end
-
-function update()
- return _action("update")
-end
-
-function upgrade()
- return _action("upgrade")
-end
-
--- List helper
-local function _list(action, pat, cb)
- local cmdline = { ipkg, action }
- if pat then
- cmdline[#cmdline+1] = util.shellquote(pat)
- end
-
- local fd = io.popen(table.concat(cmdline, " "))
- if fd then
- local name, version, sz, desc
- while true do
- local line = fd:read("*l")
- if not line then break end
-
- name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
-
- if not name then
- name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
- desc = ""
- end
-
- if name and version then
- if #version > 26 then
- version = version:sub(1,21) .. ".." .. version:sub(-3,-1)
- end
-
- cb(name, version, sz, desc)
- end
-
- name = nil
- version = nil
- sz = nil
- desc = nil
- end
-
- fd:close()
- end
-end
-
-function list_all(pat, cb)
- _list("list --size", pat, cb)
-end
-
-function list_installed(pat, cb)
- _list("list_installed --size", pat, cb)
-end
-
-function find(pat, cb)
- _list("find --size", pat, cb)
-end
-
-
-function overlay_root()
- local od = "/"
- local fd = io.open(icfg, "r")
-
- if fd then
- local ln
-
- repeat
- ln = fd:read("*l")
- if ln and ln:match("^%s*option%s+overlay_root%s+") then
- od = ln:match("^%s*option%s+overlay_root%s+(%S+)")
-
- local s = fs.stat(od)
- if not s or s.type ~= "dir" then
- od = "/"
- end
-
- break
- end
- until not ln
-
- fd:close()
- end
-
- return od
-end
-
-function compare_versions(ver1, comp, ver2)
- if not ver1 or not ver2
- or not comp or not (#comp > 0) then
- error("Invalid parameters")
- return nil
- end
- -- correct compare string
- if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
- elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
- elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
- elseif comp == "=" or comp == "==" then comp = "=="
- elseif comp == "<<" then comp = "<"
- elseif comp == ">>" then comp = ">"
- else
- error("Invalid compare string")
- return nil
- end
-
- local av1 = util.split(ver1, "[%.%-]", nil, true)
- local av2 = util.split(ver2, "[%.%-]", nil, true)
-
- local max = table.getn(av1)
- if (table.getn(av1) < table.getn(av2)) then
- max = table.getn(av2)
- end
-
- for i = 1, max, 1 do
- local s1 = av1[i] or ""
- local s2 = av2[i] or ""
-
- -- first "not equal" found return true
- if comp == "~=" and (s1 ~= s2) then return true end
- -- first "lower" found return true
- if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
- -- first "greater" found return true
- if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
- -- not equal then return false
- if (s1 ~= s2) then return false end
- end
-
- -- all equal and not compare greater or lower then true
- return not (comp == "<" or comp == ">")
-end
diff --git a/modules/luci-base/luasrc/model/ipkg.luadoc b/modules/luci-base/luasrc/model/ipkg.luadoc
deleted file mode 100644
index 4e1548dda6..0000000000
--- a/modules/luci-base/luasrc/model/ipkg.luadoc
+++ /dev/null
@@ -1,125 +0,0 @@
----[[
-LuCI OPKG call abstraction library
-]]
-module "luci.model.ipkg"
-
----[[
-Return information about installed and available packages.
-
-@class function
-@name info
-@param pkg Limit output to a (set of) packages
-@return Table containing package information
-]]
-
----[[
-Return the package status of one or more packages.
-
-@class function
-@name status
-@param pkg Limit output to a (set of) packages
-@return Table containing package status information
-]]
-
----[[
-Install one or more packages.
-
-@class function
-@name install
-@param ... List of packages to install
-@return Boolean indicating the status of the action
-@return OPKG return code, STDOUT and STDERR
-]]
-
----[[
-Determine whether a given package is installed.
-
-@class function
-@name installed
-@param pkg Package
-@return Boolean
-]]
-
----[[
-Remove one or more packages.
-
-@class function
-@name remove
-@param ... List of packages to install
-@return Boolean indicating the status of the action
-@return OPKG return code, STDOUT and STDERR
-]]
-
----[[
-Update package lists.
-
-@class function
-@name update
-@return Boolean indicating the status of the action
-@return OPKG return code, STDOUT and STDERR
-]]
-
----[[
-Upgrades all installed packages.
-
-@class function
-@name upgrade
-@return Boolean indicating the status of the action
-@return OPKG return code, STDOUT and STDERR
-]]
-
----[[
-List all packages known to opkg.
-
-@class function
-@name list_all
-@param pat Only find packages matching this pattern, nil lists all packages
-@param cb Callback function invoked for each package, receives name, version and description as arguments
-@return nothing
-]]
-
----[[
-List installed packages.
-
-@class function
-@name list_installed
-@param pat Only find packages matching this pattern, nil lists all packages
-@param cb Callback function invoked for each package, receives name, version and description as arguments
-@return nothing
-]]
-
----[[
-Find packages that match the given pattern.
-
-@class function
-@name find
-@param pat Find packages whose names or descriptions match this pattern, nil results in zero results
-@param cb Callback function invoked for each patckage, receives name, version and description as arguments
-@return nothing
-]]
-
----[[
-Determines the overlay root used by opkg.
-
-@class function
-@name overlay_root
-@return String containing the directory path of the overlay root.
-]]
-
----[[
-lua version of opkg compare-versions
-
-@class function
-@name compare_versions
-@param ver1 string version 1
-@param ver2 string version 2
-@param comp string compare versions using
- "<=" or "<" lower-equal
- ">" or ">=" greater-equal
- "=" equal
- "<<" lower
- ">>" greater
- "~=" not equal
-@return Boolean indicating the status of the compare
-]]
-
diff --git a/modules/luci-base/luasrc/model/network.lua b/modules/luci-base/luasrc/model/network.lua
index 7f7397032f..49e1657aae 100644
--- a/modules/luci-base/luasrc/model/network.lua
+++ b/modules/luci-base/luasrc/model/network.lua
@@ -855,6 +855,14 @@ function get_status_by_address(self, addr)
end
end
end
+ if s and s['ipv6-prefix-assignment'] then
+ local a
+ for _, a in ipairs(s['ipv6-prefix-assignment']) do
+ if a and a['local-address'] and a['local-address'].address == addr then
+ return net, s
+ end
+ end
+ end
end
end
end
diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-base/luasrc/sys.lua
index 1436a3a235..7e4a9d63cf 100644
--- a/modules/luci-base/luasrc/sys.lua
+++ b/modules/luci-base/luasrc/sys.lua
@@ -13,8 +13,8 @@ local luci = {}
luci.util = require "luci.util"
luci.ip = require "luci.ip"
-local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select =
- tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select
+local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack =
+ tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select, unpack
module "luci.sys"
@@ -436,6 +436,96 @@ end
process.signal = nixio.kill
+local function xclose(fd)
+ if fd and fd:fileno() > 2 then
+ fd:close()
+ end
+end
+
+function process.exec(command, stdout, stderr, nowait)
+ local out_r, out_w, err_r, err_w
+ if stdout then out_r, out_w = nixio.pipe() end
+ if stderr then err_r, err_w = nixio.pipe() end
+
+ local pid = nixio.fork()
+ if pid == 0 then
+ nixio.chdir("/")
+
+ local null = nixio.open("/dev/null", "w+")
+ if null then
+ nixio.dup(out_w or null, nixio.stdout)
+ nixio.dup(err_w or null, nixio.stderr)
+ nixio.dup(null, nixio.stdin)
+ xclose(out_w)
+ xclose(out_r)
+ xclose(err_w)
+ xclose(err_r)
+ xclose(null)
+ end
+
+ nixio.exec(unpack(command))
+ os.exit(-1)
+ end
+
+ local _, pfds, rv = nil, {}, { code = -1, pid = pid }
+
+ xclose(out_w)
+ xclose(err_w)
+
+ if out_r then
+ pfds[#pfds+1] = {
+ fd = out_r,
+ cb = type(stdout) == "function" and stdout,
+ name = "stdout",
+ events = nixio.poll_flags("in", "err", "hup")
+ }
+ end
+
+ if err_r then
+ pfds[#pfds+1] = {
+ fd = err_r,
+ cb = type(stderr) == "function" and stderr,
+ name = "stderr",
+ events = nixio.poll_flags("in", "err", "hup")
+ }
+ end
+
+ while #pfds > 0 do
+ local nfds, err = nixio.poll(pfds, -1)
+ if not nfds and err ~= nixio.const.EINTR then
+ break
+ end
+
+ local i
+ for i = #pfds, 1, -1 do
+ local rfd = pfds[i]
+ if rfd.revents > 0 then
+ local chunk, err = rfd.fd:read(4096)
+ if chunk and #chunk > 0 then
+ if rfd.cb then
+ rfd.cb(chunk)
+ else
+ rfd.buf = rfd.buf or {}
+ rfd.buf[#rfd.buf + 1] = chunk
+ end
+ else
+ table.remove(pfds, i)
+ if rfd.buf then
+ rv[rfd.name] = table.concat(rfd.buf, "")
+ end
+ rfd.fd:close()
+ end
+ end
+ end
+ end
+
+ if not nowait then
+ _, _, rv.code = nixio.waitpid(pid)
+ end
+
+ return rv
+end
+
user = {}
diff --git a/modules/luci-base/luasrc/sys.luadoc b/modules/luci-base/luasrc/sys.luadoc
index 3c7f69c6e9..162650e7ac 100644
--- a/modules/luci-base/luasrc/sys.luadoc
+++ b/modules/luci-base/luasrc/sys.luadoc
@@ -272,6 +272,42 @@ Send a signal to a process identified by given pid.
]]
---[[
+Execute a process, optionally capturing stdio.
+
+Executes the process specified by the given argv vector, e.g.
+`{ "/bin/sh", "-c", "echo 1" }` and waits for it to terminate unless a true
+value has been passed for the "nowait" parameter.
+
+When a function value is passed for the stdout or stderr arguments, the passed
+function is repeatedly called for each chunk read from the corresponding stdio
+stream. The read data is passed as string containing at most 4096 bytes at a
+time.
+
+When a true, non-function value is passed for the stdout or stderr arguments,
+the data of the corresponding stdio stream is read into an internal string
+buffer and returned as "stdout" or "stderr" field respectively in the result
+table.
+
+When a true value is passed to the nowait parameter, the function does not
+await process termination but returns as soon as all captured stdio streams
+have been closed or - if no streams are captured - immediately after launching
+the process.
+
+@class function
+@name process.exec
+@param commend Table containing the argv vector to execute
+@param stdout Callback function or boolean to indicate capturing (optional)
+@param stderr Callback function or boolean to indicate capturing (optional)
+@param nowait Don't wait for process termination when true (optional)
+@return Table containing at least the fields "code" which holds the exit
+ status of the invoked process or "-1" on error and "pid", which
+ contains the process id assigned to the spawned process. When
+ stdout and/or stderr capturing has been requested, it additionally
+ contains "stdout" and "stderr" fields respectively, holding the
+ captured stdio data as string.
+]]
+
+---[[
LuCI system utilities / user related functions.
@class module
diff --git a/modules/luci-base/luasrc/view/cbi/apply_widget.htm b/modules/luci-base/luasrc/view/cbi/apply_widget.htm
index 0df16e88c8..0f9667390e 100644
--- a/modules/luci-base/luasrc/view/cbi/apply_widget.htm
+++ b/modules/luci-base/luasrc/view/cbi/apply_widget.htm
@@ -1,49 +1,4 @@
<% export("cbi_apply_widget", function(redirect_ok, rollback_token) -%>
-<style type="text/css">
- #cbi_apply_overlay {
- position: absolute;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- background: rgba(0, 0, 0, 0.7);
- display: none;
- z-index: 20000;
- }
-
- #cbi_apply_overlay .alert-message {
- position: relative;
- top: 10%;
- width: 60%;
- margin: auto;
- display: flex;
- flex-wrap: wrap;
- min-height: 32px;
- align-items: center;
- }
-
- #cbi_apply_overlay .alert-message > h4,
- #cbi_apply_overlay .alert-message > p,
- #cbi_apply_overlay .alert-message > div {
- flex-basis: 100%;
- }
-
- #cbi_apply_overlay .alert-message > img {
- margin-right: 1em;
- flex-basis: 32px;
- }
-
- body.apply-overlay-active {
- overflow: hidden;
- height: 100vh;
- }
-
- body.apply-overlay-active #cbi_apply_overlay {
- display: block;
- }
-</style>
-
-<script type="text/javascript" src="<%=resource%>/cbi.js?v=git-18.138.59467-72fe5dd"></script>
<script type="text/javascript">//<![CDATA[
var xhr = new XHR(),
uci_apply_auth = { sid: '<%=luci.dispatcher.context.authsession%>', token: '<%=token%>' },
@@ -55,28 +10,22 @@
was_xhr_poll_running = false;
function uci_status_message(type, content) {
- var overlay = document.getElementById('cbi_apply_overlay') || document.body.appendChild(E('<div id="cbi_apply_overlay"><div class="alert-message"></div></div>')),
- message = overlay.querySelector('.alert-message');
-
- if (message && type) {
- if (!message.classList.contains(type)) {
- message.classList.remove('notice');
- message.classList.remove('warning');
- message.classList.add(type);
- }
+ if (type) {
+ var message = showModal('', '');
+
+ message.classList.add('alert-message');
+ DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/));
if (content)
message.innerHTML = content;
- document.body.classList.add('apply-overlay-active');
-
if (!was_xhr_poll_running) {
was_xhr_poll_running = XHR.running();
XHR.halt();
}
}
else {
- document.body.classList.remove('apply-overlay-active');
+ hideModal();
if (was_xhr_poll_running)
XHR.run();
@@ -85,9 +34,8 @@
function uci_rollback(checked) {
if (checked) {
- uci_status_message('warning',
- '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
- '<%:Failed to confirm apply within %ds, waiting for rollback…%>'.format(uci_apply_rollback));
+ uci_status_message('warning spinning',
+ '<p><%:Failed to confirm apply within %ds, waiting for rollback…%></p>'.format(uci_apply_rollback));
var call = function(r, data, duration) {
if (r.status === 204) {
@@ -126,6 +74,7 @@
var call = function(r, data, duration) {
if (Date.now() >= deadline) {
+ window.clearTimeout(tt);
uci_rollback(checked);
return;
}
@@ -133,7 +82,7 @@
var indicator = document.querySelector('.uci_change_indicator');
if (indicator) indicator.style.display = 'none';
- uci_status_message('notice', '<%:Configuration has been applied.%>');
+ uci_status_message('notice', '<p><%:Configuration has been applied.%></p>');
window.clearTimeout(tt);
window.setTimeout(function() {
@@ -156,9 +105,8 @@
var tick = function() {
var now = Date.now();
- uci_status_message('notice',
- '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
- '<%:Waiting for configuration to be applied… %ds%>'.format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0)));
+ uci_status_message('notice spinning',
+ '<p><%:Waiting for configuration to be applied… %ds%></p>'.format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0)));
if (now >= deadline)
return;
@@ -174,9 +122,7 @@
}
function uci_apply(checked) {
- uci_status_message('notice',
- '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
- '<%:Starting configuration apply…%>');
+ uci_status_message('notice spinning', '<p><%:Starting configuration apply…%></p>');
xhr.post('<%=url("admin/uci")%>/' + (checked ? 'apply_rollback' : 'apply_unchecked'), uci_apply_auth, function(r, tok) {
if (r.status === (checked ? 200 : 204)) {
@@ -186,7 +132,7 @@
uci_confirm(checked, Date.now() + uci_apply_rollback * 1000);
}
else if (checked && r.status === 204) {
- uci_status_message('notice', '<%:There are no changes to apply.%>');
+ uci_status_message('notice', '<p><%:There are no changes to apply.%></p>');
window.setTimeout(function() {
<% if redirect_ok then -%>
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
@@ -196,20 +142,18 @@
}, uci_apply_display * 1000);
}
else {
- uci_status_message('warning', '<%_Apply request failed with status <code>%h</code>%>'.format(r.responseText || r.statusText || r.status));
+ uci_status_message('warning', '<p><%_Apply request failed with status <code>%h</code>%></p>'.format(r.responseText || r.statusText || r.status));
window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
}
});
}
function uci_revert() {
- uci_status_message('notice',
- '<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
- '<%:Reverting configuration…%>');
+ uci_status_message('notice spinning', '<p><%:Reverting configuration…%></p>');
xhr.post('<%=url("admin/uci/revert")%>', uci_apply_auth, function(r) {
if (r.status === 200) {
- uci_status_message('notice', '<%:Changes have been reverted.%>');
+ uci_status_message('notice', '<p><%:Changes have been reverted.%></p>');
window.setTimeout(function() {
<% if redirect_ok then -%>
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
@@ -219,7 +163,7 @@
}, uci_apply_display * 1000);
}
else {
- uci_status_message('warning', '<%_Revert request failed with status <code>%h</code>%>'.format(r.statusText || r.status));
+ uci_status_message('warning', '<p><%_Revert request failed with status <code>%h</code>%></p>'.format(r.statusText || r.status));
window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
}
});
diff --git a/modules/luci-base/luasrc/view/cbi/browser.htm b/modules/luci-base/luasrc/view/cbi/browser.htm
index 2abc975e8d..362c40bec1 100644
--- a/modules/luci-base/luasrc/view/cbi/browser.htm
+++ b/modules/luci-base/luasrc/view/cbi/browser.htm
@@ -1,4 +1,4 @@
-<% local v = self:cfgvalue(section) -%>
+<% local v = self:cfgvalue(section) or self.default -%>
<%+cbi/valueheader%>
<input class="cbi-input-text" type="text"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
<script type="text/javascript">
diff --git a/modules/luci-base/luasrc/view/cbi/dynlist.htm b/modules/luci-base/luasrc/view/cbi/dynlist.htm
index 4d0b50942b..fa7dbdb418 100644
--- a/modules/luci-base/luasrc/view/cbi/dynlist.htm
+++ b/modules/luci-base/luasrc/view/cbi/dynlist.htm
@@ -6,22 +6,8 @@
self.keylist, self.vallist,
self.datatype, self.optional or self.rmempty
})) ..
-
+ attr("data-values", luci.util.serialize_json(self:cfgvalue(section))) ..
ifattr(self.size, "data-size", self.size) ..
ifattr(self.placeholder, "data-placeholder", self.placeholder)
-%>>
-<%
- local vals = self:cfgvalue(section) or {}
- for i=1, #vals + 1 do
- local val = vals[i]
- if (val and #val > 0) or (i == 1) then
-%>
- <input class="cbi-input-text" value="<%=pcdata(val)%>" data-update="change" type="text"<%=
- attr("id", cbid .. "." .. i) ..
- attr("name", cbid) ..
- ifattr(self.size, "size") ..
- ifattr(i == 1 and self.placeholder, "placeholder", self.placeholder)
- %> /><br />
-<% end end %>
-</div>
+%>></div>
<%+cbi/valuefooter%>
diff --git a/modules/luci-base/luasrc/view/cbi/map.htm b/modules/luci-base/luasrc/view/cbi/map.htm
index d65a161673..cda4d3530c 100644
--- a/modules/luci-base/luasrc/view/cbi/map.htm
+++ b/modules/luci-base/luasrc/view/cbi/map.htm
@@ -3,25 +3,25 @@
<%- end 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 %>
+ <% 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 %>
<% if self.tabbed then %>
- <ul class="cbi-tabmenu map">
- <%- self.selected_tab = luci.http.formvalue("tab.m-" .. self.config) %>
- <% for i, section in ipairs(self.children) do %>
- <%- if not self.selected_tab then self.selected_tab = section.sectiontype end %>
- <li id="tab.m-<%=self.config%>.<%=section.section or section.sectiontype%>" class="cbi-tab<%=(section.sectiontype == self.selected_tab) and '' or '-disabled'%>">
- <a onclick="this.blur(); return cbi_t_switch('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')" href="<%=REQUEST_URI%>?tab.m-<%=self.config%>=<%=section.section or section.sectiontype%>"><%=section.title or section.section or section.sectiontype %></a>
- <% if section.sectiontype == self.selected_tab then %><input type="hidden" id="tab.m-<%=self.config%>" name="tab.m-<%=self.config%>" value="<%=section.section or section.sectiontype%>" /><% end %>
- </li>
+ <div>
+ <% for i, section in ipairs(self.children) do
+ tab = section.section or section.sectiontype %>
+ <div class="cbi-tabcontainer"<%=
+ attr("id", "container.m-%s.%s" %{ self.config, tab }) ..
+ attr("data-tab", tab) ..
+ attr("data-tab-title", section.title or tab)
+ %>>
+ <% section:render() %>
+ </div>
<% end %>
- </ul>
- <% for i, section in ipairs(self.children) do %>
- <div class="cbi-tabcontainer" id="container.m-<%=self.config%>.<%=section.section or section.sectiontype%>"<% if section.sectiontype ~= self.selected_tab then %> style="display:none"<% end %>>
- <% section:render() %>
- </div>
- <script type="text/javascript">cbi_t_add('m-<%=self.config%>', '<%=section.section or section.sectiontype%>')</script>
- <% end %>
+ </div>
<% if not self.save then -%>
<div class="cbi-section-error">
diff --git a/modules/luci-base/luasrc/view/cbi/nsection.htm b/modules/luci-base/luasrc/view/cbi/nsection.htm
index 63abc57734..14232e3d94 100644
--- a/modules/luci-base/luasrc/view/cbi/nsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/nsection.htm
@@ -11,7 +11,6 @@
<input type="submit" class="cbi-button" name="cbi.rns.<%=self.config%>.<%=section%>" value="<%:Delete%>" />
</div>
<%- end %>
- <%+cbi/tabmenu%>
<div class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>">
<%+cbi/ucisection%>
</div>
diff --git a/modules/luci-base/luasrc/view/cbi/tabcontainer.htm b/modules/luci-base/luasrc/view/cbi/tabcontainer.htm
index 38c435d6a1..7fcb835783 100644
--- a/modules/luci-base/luasrc/view/cbi/tabcontainer.htm
+++ b/modules/luci-base/luasrc/view/cbi/tabcontainer.htm
@@ -1,7 +1,14 @@
-<% for tab, data in pairs(self.tabs) do %>
- <div class="cbi-tabcontainer" id="container.<%=self.config%>.<%=section%>.<%=tab%>"<% if tab ~= self.selected_tab then %> style="display:none"<% end %>>
- <% if data.description then %><div class="cbi-tab-descr"><%=data.description%></div><% end %>
+<% for _, tab in ipairs(self.tab_names) do data = self.tabs[tab] %>
+ <div class="cbi-tabcontainer"<%=
+ attr("id", "container.%s.%s.%s" %{ self.config, section, tab }) ..
+ attr("data-tab", tab) ..
+ attr("data-tab-title", data.title) ..
+ attr("data-tab-active", tostring(tab == self.selected_tab))
+ %>>
+ <% if data.description then %>
+ <div class="cbi-tab-descr"><%=data.description%></div>
+ <% end %>
+
<% self:render_tab(tab, section, scope or {}) %>
</div>
- <script type="text/javascript">cbi_t_add('<%=self.config%>.<%=section%>', '<%=tab%>')</script>
<% end %>
diff --git a/modules/luci-base/luasrc/view/cbi/tabmenu.htm b/modules/luci-base/luasrc/view/cbi/tabmenu.htm
deleted file mode 100644
index 06c1414bf3..0000000000
--- a/modules/luci-base/luasrc/view/cbi/tabmenu.htm
+++ /dev/null
@@ -1,12 +0,0 @@
-<%- if self.tabs then %>
- <ul class="cbi-tabmenu">
- <%- self.selected_tab = luci.http.formvalue("tab." .. self.config .. "." .. section) %>
- <%- for _, tab in ipairs(self.tab_names) do if #self.tabs[tab].childs > 0 then %>
- <%- if not self.selected_tab then self.selected_tab = tab end %>
- <li id="tab.<%=self.config%>.<%=section%>.<%=tab%>" class="cbi-tab<%=(tab == self.selected_tab) and '' or '-disabled'%>">
- <a onclick="this.blur(); return cbi_t_switch('<%=self.config%>.<%=section%>', '<%=tab%>')" href="<%=REQUEST_URI%>?tab.<%=self.config%>.<%=section%>=<%=tab%>"><%=self.tabs[tab].title%></a>
- <% if tab == self.selected_tab then %><input type="hidden" id="tab.<%=self.config%>.<%=section%>" name="tab.<%=self.config%>.<%=section%>" value="<%=tab%>" /><% end %>
- </li>
- <% end end -%>
- </ul>
-<% end -%>
diff --git a/modules/luci-base/luasrc/view/cbi/tsection.htm b/modules/luci-base/luasrc/view/cbi/tsection.htm
index 1a13df0c04..547a793329 100644
--- a/modules/luci-base/luasrc/view/cbi/tsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/tsection.htm
@@ -18,8 +18,6 @@
<h3><%=section:upper()%></h3>
<%- end %>
- <%+cbi/tabmenu%>
-
<div class="cbi-section-node<% if self.tabs then %> cbi-section-node-tabbed<% end %>" id="cbi-<%=self.config%>-<%=section%>">
<%+cbi/ucisection%>
</div>
diff --git a/modules/luci-base/luasrc/view/cbi/value.htm b/modules/luci-base/luasrc/view/cbi/value.htm
index 8eec865348..27f3cb2bd9 100644
--- a/modules/luci-base/luasrc/view/cbi/value.htm
+++ b/modules/luci-base/luasrc/view/cbi/value.htm
@@ -21,6 +21,6 @@
ifattr(#self.keylist > 0, "data-choices", { self.keylist, self.vallist })
%> />
<%- if self.password then -%>
- <div class="cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'">∗</div>
+ <button class="cbi-button cbi-button-neutral" title="<%:Reveal/hide password%>" aria-label="<%:Reveal/hide password%>" onclick="var e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'; event.preventDefault()">∗</button>
<% end %>
<%+cbi/valuefooter%>
diff --git a/modules/luci-base/luasrc/view/header.htm b/modules/luci-base/luasrc/view/header.htm
index f6e20c9a40..2813c4d943 100644
--- a/modules/luci-base/luasrc/view/header.htm
+++ b/modules/luci-base/luasrc/view/header.htm
@@ -10,3 +10,14 @@
luci.dispatcher.context.template_header_sent = true
end
%>
+
+<script type="text/javascript" src="<%=resource%>/luci.js"></script>
+<script type="text/javascript">
+ L = new LuCI(<%= luci.http.write_json({
+ token = token,
+ resource = resource,
+ scriptname = luci.http.getenv("SCRIPT_NAME"),
+ pathinfo = luci.http.getenv("PATH_INFO"),
+ requestpath = luci.dispatcher.context.requestpath
+ }) %>);
+</script>
diff --git a/modules/luci-base/luasrc/view/wifi_assoclist.htm b/modules/luci-base/luasrc/view/wifi_assoclist.htm
index 700d998ad8..b7147bfb71 100644
--- a/modules/luci-base/luasrc/view/wifi_assoclist.htm
+++ b/modules/luci-base/luasrc/view/wifi_assoclist.htm
@@ -1,4 +1,21 @@
+<%
+ local supports_deauth = {}
+
+ local _, v
+ for _, v in ipairs(luci.util.ubus()) do
+ local iface = v:match("^hostapd%.(.+)$")
+ if iface then
+ local funcs = luci.util.ubus(v)
+ if type(funcs) == "table" and funcs.del_client then
+ supports_deauth[iface] = true
+ end
+ end
+ end
+%>
+
<script type="text/javascript">//<![CDATA[
+ var supports_deauth = <%= luci.http.write_json(supports_deauth) %>;
+
function wifirate(bss, rx) {
var p = rx ? 'rx_' : 'tx_',
s = '%.1f <%:Mbit/s%>, %d<%:MHz%>'
@@ -17,6 +34,16 @@
return s;
}
+ function handleDeauth(ev) {
+ (new XHR()).post('<%=url('admin/wireless_deauth')%>', {
+ token: '<%=token%>',
+ iface: ev.target.getAttribute('data-iface'),
+ bssid: ev.target.getAttribute('data-bssid')
+ }, function() {
+ ev.target.disabled = true;
+ });
+ }
+
XHR.poll(5, '<%=url('admin/wireless_assoclist')%>', null,
function(x, st)
{
@@ -58,7 +85,15 @@
E('span', wifirate(bss, true)),
E('br'),
E('span', wifirate(bss, false))
- ])
+ ]),
+ supports_deauth[bss.ifname] ? E('input', {
+ type: 'button',
+ class: 'cbi-button cbi-button-remove',
+ value: '<%:Disconnect%>',
+ 'data-bssid': bss.bssid,
+ 'data-iface': bss.ifname,
+ click: handleDeauth
+ }) : '-'
]);
});
@@ -75,6 +110,9 @@
<div class="th nowrap"><%:Host%></div>
<div class="th nowrap"><%:Signal%> / <%:Noise%></div>
<div class="th nowrap"><%:RX Rate%> / <%:TX Rate%></div>
+ <% if next(supports_deauth) then %>
+ <div class="th right"><%:Disconnect%></div>
+ <% end %>
</div>
<div class="tr placeholder">
<div class="td"><em><%:Collecting data...%></em></div>