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/model/ipkg.lua247
-rw-r--r--modules/luci-base/luasrc/model/ipkg.luadoc125
-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.htm96
-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/value.htm2
8 files changed, 152 insertions, 468 deletions
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/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..05511c9ab0 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,19 +34,18 @@
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) {
uci_status_message('warning',
'<h4><%:Configuration has been rolled back!%></h4>' +
- '<p><%:The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, proceed by applying anyway. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.%></p>'.format(uci_apply_rollback) +
+ '<p><%:The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, perform an unchecked configuration apply. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.%></p>'.format(uci_apply_rollback) +
'<div class="right">' +
'<input type="button" class="btn" onclick="uci_status_message(false)" value="<%:Dismiss%>" /> ' +
'<input type="button" class="btn cbi-button-action important" onclick="uci_revert()" value="<%:Revert changes%>" /> ' +
- '<input type="button" class="btn cbi-button-negative important" onclick="uci_apply(false)" value="<%:Apply anyway%>" />' +
+ '<input type="button" class="btn cbi-button-negative important" onclick="uci_apply(false)" value="<%:Apply unchecked%>" />' +
'</div>');
return;
@@ -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 get 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/value.htm b/modules/luci-base/luasrc/view/cbi/value.htm
index 8eec865348..79a358b305 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'">∗</button>
<% end %>
<%+cbi/valuefooter%>