summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-base')
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js228
-rw-r--r--modules/luci-base/luasrc/dispatcher.lua7
-rw-r--r--modules/luci-base/luasrc/view/cbi/dynlist.htm29
-rw-r--r--modules/luci-base/luasrc/view/cbi/header.htm13
-rw-r--r--modules/luci-base/luasrc/view/cbi/lvalue.htm50
-rw-r--r--modules/luci-base/luasrc/view/cbi/mvalue.htm51
-rw-r--r--modules/luci-base/luasrc/view/cbi/nsection.htm2
-rw-r--r--modules/luci-base/luasrc/view/cbi/tblsection.htm3
-rw-r--r--modules/luci-base/luasrc/view/cbi/tsection.htm3
-rw-r--r--modules/luci-base/luasrc/view/cbi/ucisection.htm59
-rw-r--r--modules/luci-base/luasrc/view/cbi/value.htm34
11 files changed, 273 insertions, 206 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index 2274610705..26fd92471f 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -13,27 +13,36 @@
var cbi_d = [];
var cbi_t = [];
+var cbi_strings = { path: {}, label: {} };
+
+function Int(x) {
+ return (/^-?\d+$/.test(x) ? +x : NaN);
+}
+
+function Dec(x) {
+ return (/^-?\d+(?:\.\d+)?$/.test(x) ? +x : NaN);
+}
var cbi_validators = {
'integer': function()
{
- return (this.match(/^-?[0-9]+$/) != null);
+ return !!Int(this);
},
'uinteger': function()
{
- return (cbi_validators.integer.apply(this) && (this >= 0));
+ return (Int(this) >= 0);
},
'float': function()
{
- return !isNaN(parseFloat(this));
+ return !!Dec(this);
},
'ufloat': function()
{
- return (cbi_validators['float'].apply(this) && (this >= 0));
+ return (Dec(this) >= 0);
},
'ipaddr': function()
@@ -111,26 +120,20 @@ var cbi_validators = {
'port': function()
{
- return cbi_validators.integer.apply(this) &&
- (this >= 0) && (this <= 65535);
+ var p = Int(this);
+ return (p >= 0 && p <= 65535);
},
'portrange': function()
{
if (this.match(/^(\d+)-(\d+)$/))
{
- var p1 = RegExp.$1;
- var p2 = RegExp.$2;
-
- return cbi_validators.port.apply(p1) &&
- cbi_validators.port.apply(p2) &&
- (parseInt(p1) <= parseInt(p2))
- ;
- }
- else
- {
- return cbi_validators.port.apply(this);
+ var p1 = +RegExp.$1;
+ var p2 = +RegExp.$2;
+ return (p1 <= p2 && p2 <= 65535);
}
+
+ return cbi_validators.port.apply(this);
},
'macaddr': function()
@@ -234,56 +237,34 @@ var cbi_validators = {
'range': function(min, max)
{
- var val = parseFloat(this);
- if (!isNaN(min) && !isNaN(max) && !isNaN(val))
- return ((val >= min) && (val <= max));
-
- return false;
+ var val = Dec(this);
+ return (val >= +min && val <= +max);
},
'min': function(min)
{
- var val = parseFloat(this);
- if (!isNaN(min) && !isNaN(val))
- return (val >= min);
-
- return false;
+ return (Dec(this) >= +min);
},
'max': function(max)
{
- var val = parseFloat(this);
- if (!isNaN(max) && !isNaN(val))
- return (val <= max);
-
- return false;
+ return (Dec(this) <= +max);
},
'rangelength': function(min, max)
{
var val = '' + this;
- if (!isNaN(min) && !isNaN(max))
- return ((val.length >= min) && (val.length <= max));
-
- return false;
+ return ((val.length >= +min) && (val.length <= +max));
},
'minlength': function(min)
{
- var val = '' + this;
- if (!isNaN(min))
- return (val.length >= min);
-
- return false;
+ return ((''+this).length >= +min);
},
'maxlength': function(max)
{
- var val = '' + this;
- if (!isNaN(max))
- return (val.length <= max);
-
- return false;
+ return ((''+this).length <= +max);
},
'or': function()
@@ -473,7 +454,7 @@ function cbi_d_update() {
if (node && node.parentNode && !cbi_d_check(entry.deps)) {
node.parentNode.removeChild(node);
state = true;
- } else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) {
+ } else if (parent && (!node || !node.parentNode) && cbi_d_check(entry.deps)) {
var next = undefined;
for (next = parent.firstChild; next; next = next.nextSibling) {
@@ -490,6 +471,10 @@ function cbi_d_update() {
state = true;
}
+
+ // hide optionals widget if no choices remaining
+ if (parent && parent.parentNode && parent.getAttribute('data-optionals'))
+ parent.parentNode.style.display = (parent.options.length <= 1) ? 'none' : '';
}
if (entry && entry.parent) {
@@ -503,7 +488,21 @@ function cbi_d_update() {
}
function cbi_init() {
- var nodes = document.querySelectorAll('[data-depends]');
+ var nodes;
+
+ nodes = document.querySelectorAll('[data-strings]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ var str = JSON.parse(node.getAttribute('data-strings'));
+ for (var key in str) {
+ for (var key2 in str[key]) {
+ var dst = cbi_strings[key] || (cbi_strings[key] = { });
+ dst[key2] = str[key][key2];
+ }
+ }
+ }
+
+ nodes = document.querySelectorAll('[data-depends]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
var index = parseInt(node.getAttribute('data-index'), 10);
@@ -524,6 +523,45 @@ function cbi_init() {
}
}
+ nodes = document.querySelectorAll('[data-type]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ cbi_validate_field(node, node.getAttribute('data-optional') === 'true',
+ node.getAttribute('data-type'));
+ }
+
+ nodes = document.querySelectorAll('[data-choices]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ var choices = JSON.parse(node.getAttribute('data-choices'));
+ var options = {};
+
+ for (var j = 0; j < choices[0].length; j++)
+ options[choices[0][j]] = choices[1][j];
+
+ var def = (node.getAttribute('data-optional') === 'true')
+ ? node.placeholder || '' : null;
+
+ cbi_combobox_init(node, options, def,
+ node.getAttribute('data-manual'));
+ }
+
+ nodes = document.querySelectorAll('[data-dynlist]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ var choices = JSON.parse(node.getAttribute('data-dynlist'));
+ var options = null;
+
+ if (choices[0] && choices[0].length) {
+ options = {};
+
+ for (var j = 0; j < choices[0].length; j++)
+ options[choices[0][j]] = choices[1][j];
+ }
+
+ cbi_dynlist_init(node, choices[2], choices[3], options);
+ }
+
cbi_d_update();
}
@@ -572,7 +610,7 @@ function cbi_combobox(id, values, def, man, focus) {
if (obj.value == "") {
var optdef = document.createElement("option");
optdef.value = "";
- optdef.appendChild(document.createTextNode(def));
+ optdef.appendChild(document.createTextNode(typeof(def) === 'string' ? def : cbi_strings.label.choose));
sel.appendChild(optdef);
} else {
var opt = document.createElement("option");
@@ -597,7 +635,7 @@ function cbi_combobox(id, values, def, man, focus) {
var optman = document.createElement("option");
optman.value = "";
- optman.appendChild(document.createTextNode(man));
+ optman.appendChild(document.createTextNode(typeof(man) === 'string' ? man : cbi_strings.label.custom));
sel.appendChild(optman);
obj.style.display = "none";
@@ -627,27 +665,27 @@ function cbi_combobox(id, values, def, man, focus) {
}
function cbi_combobox_init(id, values, def, man) {
- var obj = document.getElementById(id);
+ var obj = (typeof(id) === 'string') ? document.getElementById(id) : id;
cbi_bind(obj, "blur", function() {
- cbi_combobox(id, values, def, man, true);
+ cbi_combobox(obj.id, values, def, man, true);
});
- cbi_combobox(id, values, def, man, false);
+ cbi_combobox(obj.id, values, def, man, false);
}
-function cbi_filebrowser(id, url, defpath) {
+function cbi_filebrowser(id, defpath) {
var field = document.getElementById(id);
var browser = window.open(
- url + ( field.value || defpath || '' ) + '?field=' + id,
+ cbi_strings.path.browser + ( field.value || defpath || '' ) + '?field=' + id,
"luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
);
browser.focus();
}
-function cbi_browser_init(id, respath, url, defpath)
+function cbi_browser_init(id, defpath)
{
function cbi_browser_btnclick(e) {
- cbi_filebrowser(id, url, defpath);
+ cbi_filebrowser(id, defpath);
return false;
}
@@ -655,18 +693,16 @@ function cbi_browser_init(id, respath, url, defpath)
var btn = document.createElement('img');
btn.className = 'cbi-image-button';
- btn.src = respath + '/cbi/folder.gif';
+ btn.src = cbi_strings.path.resource + '/cbi/folder.gif';
field.parentNode.insertBefore(btn, field.nextSibling);
cbi_bind(btn, 'click', cbi_browser_btnclick);
}
-function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choices)
+function cbi_dynlist_init(parent, datatype, optional, choices)
{
- var input0 = document.getElementsByName(name)[0];
- var prefix = input0.name;
- var parent = input0.parentNode;
- var holder = input0.placeholder;
+ var prefix = parent.getAttribute('data-prefix');
+ var holder = parent.getAttribute('data-placeholder');
var values;
@@ -677,7 +713,7 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
while (parent.firstChild)
{
var n = parent.firstChild;
- var i = parseInt(n.index);
+ var i = +n.index;
if (i != del)
{
@@ -717,14 +753,14 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
}
var b = document.createElement('img');
- b.src = respath + ((i+1) < values.length ? '/cbi/remove.gif' : '/cbi/add.gif');
+ b.src = cbi_strings.path.resource + ((i+1) < values.length ? '/cbi/remove.gif' : '/cbi/add.gif');
b.className = 'cbi-image-button';
parent.appendChild(t);
parent.appendChild(b);
if (datatype == 'file')
{
- cbi_browser_init(t.id, respath, url, defpath);
+ cbi_browser_init(t.id, parent.getAttribute('data-browser-path'));
}
parent.appendChild(document.createElement('br'));
@@ -736,7 +772,7 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
if (choices)
{
- cbi_combobox_init(t.id, choices[0], '', choices[1]);
+ cbi_combobox_init(t.id, choices, '', cbi_strings.label.custom);
b.index = i;
cbi_bind(b, 'keydown', cbi_dynlist_keydown);
@@ -816,15 +852,15 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
se = se.parentNode;
var prev = se.previousSibling;
- while (prev && prev.name != name)
+ while (prev && prev.name != prefix)
prev = prev.previousSibling;
var next = se.nextSibling;
- while (next && next.name != name)
+ while (next && next.name != prefix)
next = next.nextSibling;
/* advance one further in combobox case */
- if (next && next.nextSibling.name == name)
+ if (next && next.nextSibling.name == prefix)
next = next.nextSibling;
switch (ev.keyCode)
@@ -880,7 +916,7 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
var se = ev.target ? ev.target : ev.srcElement;
var input = se.previousSibling;
- while (input && input.name != name) {
+ while (input && input.name != prefix) {
input = input.previousSibling;
}
@@ -889,14 +925,14 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
input.value = '';
cbi_dynlist_keydown({
- target: input,
+ target: se,
keyCode: 8
});
}
else
{
cbi_dynlist_keydown({
- target: input,
+ target: se,
keyCode: 13
});
}
@@ -1273,7 +1309,7 @@ String.prototype.format = function()
var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t|m))/;
var a = b = [], numSubstitutions = 0, numMatches = 0;
- while( a = re.exec(str) )
+ while (a = re.exec(str))
{
var m = a[1];
var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
@@ -1296,6 +1332,8 @@ String.prototype.format = function()
pad = leftpart.substr(1,1);
else if (pPad)
pad = pPad;
+ else
+ pad = ' ';
var justifyRight = true;
if (pJustify && pJustify === "-")
@@ -1303,40 +1341,40 @@ String.prototype.format = function()
var minLength = -1;
if (pMinLength)
- minLength = parseInt(pMinLength);
+ minLength = +pMinLength;
var precision = -1;
if (pPrecision && pType == 'f')
- precision = parseInt(pPrecision.substring(1));
+ precision = +pPrecision.substring(1);
var subst = param;
switch(pType)
{
case 'b':
- subst = (parseInt(param) || 0).toString(2);
+ subst = (+param || 0).toString(2);
break;
case 'c':
- subst = String.fromCharCode(parseInt(param) || 0);
+ subst = String.fromCharCode(+param || 0);
break;
case 'd':
- subst = (parseInt(param) || 0);
+ subst = ~~(+param || 0);
break;
case 'u':
- subst = Math.abs(parseInt(param) || 0);
+ subst = ~~Math.abs(+param || 0);
break;
case 'f':
subst = (precision > -1)
- ? ((parseFloat(param) || 0.0)).toFixed(precision)
- : (parseFloat(param) || 0.0);
+ ? ((+param || 0.0)).toFixed(precision)
+ : (+param || 0.0);
break;
case 'o':
- subst = (parseInt(param) || 0).toString(8);
+ subst = (+param || 0).toString(8);
break;
case 's':
@@ -1344,11 +1382,11 @@ String.prototype.format = function()
break;
case 'x':
- subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase();
+ subst = ('' + (+param || 0).toString(16)).toLowerCase();
break;
case 'X':
- subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase();
+ subst = ('' + (+param || 0).toString(16)).toUpperCase();
break;
case 'h':
@@ -1391,22 +1429,32 @@ String.prototype.format = function()
break;
case 'm':
- var mf = pMinLength ? parseInt(pMinLength) : 1000;
- var pr = pPrecision ? Math.floor(10*parseFloat('0'+pPrecision)) : 2;
+ var mf = pMinLength ? +pMinLength : 1000;
+ var pr = pPrecision ? ~~(10 * +('0' + pPrecision)) : 2;
var i = 0;
- var val = parseFloat(param || 0);
- var units = [ '', 'K', 'M', 'G', 'T', 'P', 'E' ];
+ var val = (+param || 0);
+ var units = [ ' ', ' K', ' M', ' G', ' T', ' P', ' E' ];
for (i = 0; (i < units.length) && (val > mf); i++)
val /= mf;
- subst = val.toFixed(pr) + ' ' + units[i];
+ subst = (i ? val.toFixed(pr) : val) + units[i];
+ pMinLength = null;
break;
}
}
}
+ if (pMinLength) {
+ subst = subst.toString();
+ for (var i = subst.length; i < pMinLength; i++)
+ if (pJustify == '-')
+ subst = subst + ' ';
+ else
+ subst = pad + subst;
+ }
+
out += leftpart + subst;
str = str.substr(m.length);
}
diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua
index 91a4c63a67..c7903e6384 100644
--- a/modules/luci-base/luasrc/dispatcher.lua
+++ b/modules/luci-base/luasrc/dispatcher.lua
@@ -273,6 +273,13 @@ function dispatch(request)
if cond then
local env = getfenv(3)
local scope = (type(env.self) == "table") and env.self
+ if type(val) == "table" then
+ if not next(val) then
+ return ''
+ else
+ val = util.serialize_json(val)
+ end
+ end
return string.format(
' %s="%s"', tostring(key),
util.pcdata(tostring( val
diff --git a/modules/luci-base/luasrc/view/cbi/dynlist.htm b/modules/luci-base/luasrc/view/cbi/dynlist.htm
index 80cbee8394..4d0b50942b 100644
--- a/modules/luci-base/luasrc/view/cbi/dynlist.htm
+++ b/modules/luci-base/luasrc/view/cbi/dynlist.htm
@@ -1,5 +1,15 @@
<%+cbi/valueheader%>
-<div>
+<div<%=
+ attr("data-prefix", cbid) ..
+ attr("data-browser-path", self.default_path) ..
+ attr("data-dynlist", luci.util.serialize_json({
+ self.keylist, self.vallist,
+ self.datatype, self.optional or self.rmempty
+ })) ..
+
+ 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
@@ -7,22 +17,11 @@
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") ..
+ attr("id", cbid .. "." .. i) ..
+ attr("name", cbid) ..
+ ifattr(self.size, "size") ..
ifattr(i == 1 and self.placeholder, "placeholder", self.placeholder)
%> /><br />
<% end end %>
</div>
-<script type="text/javascript">
-cbi_dynlist_init(
- '<%=cbid%>', '<%=resource%>', '<%=self.datatype%>',
- <%=tostring(self.optional or self.rmempty)%>,
- '<%=url('admin/filebrowser')%>',
- '<%=self.default_path and self.default_path%>'
- <%- if #self.keylist > 0 then -%>, [{
- <%- for i, k in ipairs(self.keylist) do -%>
- <%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%>
- <%-if i<#self.keylist then-%>,<%-end-%>
- <%- end -%>
- }, '<%: -- custom -- %>']<% end -%>);
-</script>
<%+cbi/valuefooter%>
diff --git a/modules/luci-base/luasrc/view/cbi/header.htm b/modules/luci-base/luasrc/view/cbi/header.htm
index 302df1d2fd..9710bae8f4 100644
--- a/modules/luci-base/luasrc/view/cbi/header.htm
+++ b/modules/luci-base/luasrc/view/cbi/header.htm
@@ -1,7 +1,18 @@
<%+header%>
<form method="post" name="cbi" action="<%=REQUEST_URI%>" enctype="multipart/form-data" onreset="return cbi_validate_reset(this)" onsubmit="return cbi_validate_form(this, '<%:Some fields are invalid, cannot save values!%>')">
<div>
- <script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+ <script type="text/javascript" src="<%=resource%>/cbi.js"<%=
+ attr("data-strings", luci.util.serialize_json({
+ label = {
+ choose = translate('-- Please choose --'),
+ custom = translate('-- custom --'),
+ },
+ path = {
+ resource = resource,
+ browser = url("admin/filebrowser")
+ }
+ }))
+ %>></script>
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="cbi.submit" value="1" />
<input type="submit" value="<%:Save%>" class="hidden" />
diff --git a/modules/luci-base/luasrc/view/cbi/lvalue.htm b/modules/luci-base/luasrc/view/cbi/lvalue.htm
index ac63e9efd4..61759fdd41 100644
--- a/modules/luci-base/luasrc/view/cbi/lvalue.htm
+++ b/modules/luci-base/luasrc/view/cbi/lvalue.htm
@@ -1,18 +1,42 @@
+<%
+ local i, key
+ local br = self.orientation == "horizontal" and '&#160;' or '<br />'
+%>
+
<%+cbi/valueheader%>
<% if self.widget == "select" then %>
- <select class="cbi-input-select" data-update="change"<%= attr("id", cbid) .. attr("name", cbid) .. ifattr(self.size, "size") %>>
- <% for i, key in pairs(self.keylist) do -%>
- <option id="cbi-<%=self.config.."-"..section.."-"..self.option.."-"..key%>"<%= attr("value", key) .. ifattr(tostring(self:cfgvalue(section) or self.default) == key, "selected", "selected") .. attr("data-index", i) .. attr("data-depends", self:deplist2json(section, self.deplist[i])) %>><%=striptags(self.vallist[i])%></option>
- <%- end %>
+ <select class="cbi-input-select" data-update="change"<%=
+ attr("id", cbid) ..
+ attr("name", cbid) ..
+ ifattr(self.size, "size")
+ %>>
+ <% for i, key in pairs(self.keylist) do -%>
+ <option<%=
+ attr("id", cbid.."-"..key) ..
+ attr("value", key) ..
+ attr("data-index", i) ..
+ attr("data-depends", self:deplist2json(section, self.deplist[i])) ..
+ ifattr(tostring(self:cfgvalue(section) or self.default) == key, "selected", "selected")
+ %>><%=pcdata(self.vallist[i])%></option>
+ <%- end %>
</select>
-<% elseif self.widget == "radio" then
- local c = 0
- for i, key in pairs(self.keylist) do
- c = c + 1
-%>
- <input class="cbi-input-radio" data-update="click change" type="radio"<%= attr("id", cbid.."-"..key) .. attr("name", cbid) .. attr("value", key) .. ifattr((self:cfgvalue(section) or self.default) == key, "checked", "checked") .. attr("data-index", i) .. attr("data-depends", self:deplist2json(section, self.deplist[i])) %> />
- <label<%= attr("for", cbid.."-"..key) %>><%=self.vallist[i]%></label>
-<% if c == self.size then c = 0 %><% if self.orientation == "horizontal" then %>&#160;<% else %><br /><% end %>
-<% end end %>
+<% elseif self.widget == "radio" then %>
+ <div<%= attr("id", cbid) %>>
+ <% for i, key in pairs(self.keylist) do %>
+ <label<%=
+ attr("id", cbid.."-"..key) ..
+ attr("data-index", i) ..
+ attr("data-depends", self:deplist2json(section, self.deplist[i]))
+ %>>
+ <input class="cbi-input-radio" data-update="click change" type="radio"<%=
+ attr("name", cbid) ..
+ attr("value", key) ..
+ ifattr((self:cfgvalue(section) or self.default) == key, "checked", "checked")
+ %> />
+ <%=pcdata(self.vallist[i])%>
+ </label>
+ <% if i == self.size then write(br) end %>
+ <% end %>
+ </div>
<% end %>
<%+cbi/valuefooter%>
diff --git a/modules/luci-base/luasrc/view/cbi/mvalue.htm b/modules/luci-base/luasrc/view/cbi/mvalue.htm
index 79950cee2b..ccdd6fcab3 100644
--- a/modules/luci-base/luasrc/view/cbi/mvalue.htm
+++ b/modules/luci-base/luasrc/view/cbi/mvalue.htm
@@ -1,19 +1,42 @@
-<% local v = self:valuelist(section) or {} -%>
+<%
+ local i, key
+ local v = self:valuelist(section) or {}
+-%>
+
<%+cbi/valueheader%>
<% if self.widget == "select" then %>
- <select class="cbi-input-select" multiple="multiple" data-update="click change"<%= attr("name", cbid) .. ifattr(self.size, "size") %>>
- <% for i, key in pairs(self.keylist) do -%>
- <option<%= attr("id", cbid.."-"..key) .. attr("value", key) .. ifattr(luci.util.contains(v, key), "selected", "selected") .. attr("data-index", i) .. attr("data-depends", self:deplist2json(section, self.deplist[i])) %>><%=striptags(self.vallist[i])%></option>
- <%- end %>
+ <select class="cbi-input-select" multiple="multiple" data-update="click change"<%=
+ attr("id", cbid) ..
+ attr("name", cbid) ..
+ ifattr(self.size, "size")
+ %>>
+ <% for i, key in pairs(self.keylist) do -%>
+ <option<%=
+ attr("id", cbid.."-"..key) ..
+ attr("value", key) ..
+ attr("data-index", i) ..
+ attr("data-depends", self:deplist2json(section, self.deplist[i])) ..
+ ifattr(luci.util.contains(v, key), "selected", "selected")
+ %>><%=pcdata(self.vallist[i])%></option>
+ <%- end %>
</select>
-<% elseif self.widget == "checkbox" then
- local c = 0;
- for i, key in pairs(self.keylist) do
- c = c + 1
-%>
- <input class="cbi-input-checkbox" type="checkbox" data-update="click change"<%= attr("id", cbid.."-"..key) .. attr("name", cbid) .. attr("value", key) .. ifattr(luci.util.contains(v, key), "checked", "checked") .. attr("data-index", i) .. attr("data-depends", self:deplist2json(section, self.deplist[i])) %> />
- <label<%= attr("for", cbid.."-"..key) %>><%=self.vallist[i]%></label><br />
-<% if c == self.size then c = 0 %><br />
-<% end end %>
+<% elseif self.widget == "checkbox" then %>
+ <div<%= attr("id", cbid) %>>
+ <% for i, key in pairs(self.keylist) do %>
+ <label<%=
+ attr("id", cbid.."-"..key) ..
+ attr("data-index", i) ..
+ attr("data-depends", self:deplist2json(section, self.deplist[i]))
+ %>>
+ <input class="cbi-input-checkbox" type="checkbox" data-update="click change"<%=
+ attr("name", cbid) ..
+ attr("value", key) ..
+ ifattr(luci.util.contains(v, key), "checked", "checked")
+ %> />
+ <%=pcdata(self.vallist[i])%>
+ </label>
+ <% if i == self.size then write('<br />') end %>
+ <% end %>
+ </div>
<% end %>
<%+cbi/valuefooter%>
diff --git a/modules/luci-base/luasrc/view/cbi/nsection.htm b/modules/luci-base/luasrc/view/cbi/nsection.htm
index 32e73e748d..abf67596f0 100644
--- a/modules/luci-base/luasrc/view/cbi/nsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/nsection.htm
@@ -1,5 +1,5 @@
<% if self:cfgvalue(self.section) then section = self.section %>
- <fieldset class="cbi-section" id="cbi-<%=self.config%>-<%=section%>">
+ <fieldset class="cbi-section">
<% if self.title and #self.title > 0 then -%>
<legend><%=self.title%></legend>
<%- end %>
diff --git a/modules/luci-base/luasrc/view/cbi/tblsection.htm b/modules/luci-base/luasrc/view/cbi/tblsection.htm
index fcf216125b..26d13f9372 100644
--- a/modules/luci-base/luasrc/view/cbi/tblsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/tblsection.htm
@@ -131,8 +131,7 @@ end
<input class="cbi-button cbi-button-add" type="submit" value="<%:Add%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" title="<%:Add%>" />
<% else %>
<% if self.invalid_cts then -%><div class="cbi-section-error"><% end %>
- <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" />
- <script type="text/javascript">cbi_validate_field('cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>', true, 'uciname');</script>
+ <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname" data-optional="true" />
<input class="cbi-button cbi-button-add" type="submit" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" title="<%:Add%>" />
<% if self.invalid_cts then -%>
<br /><%:Invalid%></div>
diff --git a/modules/luci-base/luasrc/view/cbi/tsection.htm b/modules/luci-base/luasrc/view/cbi/tsection.htm
index fcffbe0e7b..726521ae3f 100644
--- a/modules/luci-base/luasrc/view/cbi/tsection.htm
+++ b/modules/luci-base/luasrc/view/cbi/tsection.htm
@@ -37,8 +37,7 @@
<input type="submit" class="cbi-button cbi-button-add" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" value="<%:Add%>" />
<%- else -%>
<% if self.invalid_cts then -%><div class="cbi-section-error"><% end %>
- <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" />
- <script type="text/javascript">cbi_validate_field('cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>', true, 'uciname');</script>
+ <input type="text" class="cbi-section-create-name" id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname" data-optional="true" />
<input type="submit" class="cbi-button cbi-button-add" onclick="this.form.cbi_state='add-section'; return true" value="<%:Add%>" />
<% if self.invalid_cts then -%>
<br /><%:Invalid%></div>
diff --git a/modules/luci-base/luasrc/view/cbi/ucisection.htm b/modules/luci-base/luasrc/view/cbi/ucisection.htm
index 3b69f12f2e..2cb1e75d0e 100644
--- a/modules/luci-base/luasrc/view/cbi/ucisection.htm
+++ b/modules/luci-base/luasrc/view/cbi/ucisection.htm
@@ -15,7 +15,7 @@
<% end %>
<% if self.error and self.error[section] then -%>
- <div class="cbi-section-error">
+ <div class="cbi-section-error" data-index="<%=#self.children + 1%>">
<ul><% for _, e in ipairs(self.error[section]) do -%>
<li>
<%- if e == "invalid" then -%>
@@ -31,45 +31,26 @@
<%- end %>
<% if self.optionals[section] and #self.optionals[section] > 0 or self.dynamic then %>
- <div class="cbi-optionals">
- <% if self.dynamic then %>
- <input type="text" id="cbi.opt.<%=self.config%>.<%=section%>" name="cbi.opt.<%=self.config%>.<%=section%>" />
- <% if self.optionals[section] and #self.optionals[section] > 0 then %>
- <script type="text/javascript">
- cbi_combobox_init('cbi.opt.<%=self.config%>.<%=section%>', {
- <%-
- for i, val in pairs(self.optionals[section]) do
- -%>
- <%-=string.format("%q", val.option) .. ":" .. string.format("%q", striptags(val.title))-%>
- <%-if next(self.optionals[section], i) then-%>,<%-end-%>
- <%-
- end
- -%>
- }, '', '<%-: -- custom -- -%>');
- </script>
- <% end %>
- <% else %>
- <select id="cbi.opt.<%=self.config%>.<%=section%>" name="cbi.opt.<%=self.config%>.<%=section%>">
- <option><%: -- Additional Field -- %></option>
- <% for key, val in pairs(self.optionals[section]) do -%>
- <option id="cbi-<%=self.config.."-"..section.."-"..val.option%>" value="<%=val.option%>"><%=striptags(val.title)%></option>
- <%- end %>
- </select>
- <script type="text/javascript"><% for key, val in pairs(self.optionals[section]) do %>
- <% if #val.deps > 0 then %><% for j, d in ipairs(val.deps) do -%>
- cbi_d_add("cbi-<%=self.config.."-"..section.."-"..val.option..d.add%>", {
- <%-
- for k,v in pairs(d.deps) do
- -%>
- <%-=string.format('"cbid.%s.%s.%s"', self.config, section, k) .. ":" .. string.format("%q", v)-%>
- <%-if next(d.deps, k) then-%>,<%-end-%>
- <%-
+ <div class="cbi-optionals" data-index="<%=#self.children + 1%>">
+ <%
+ if self.dynamic then
+ local keys, vals, name, opt = { }, { }
+ for name, opt in pairs(self.optionals[section]) do
+ keys[#keys+1] = name
+ vals[#vals+1] = opt.title
end
- -%>
- });
- <%- end %><% end %>
- <% end %></script>
- <% end %>
+ %>
+ <input type="text" id="cbi.opt.<%=self.config%>.<%=section%>" name="cbi.opt.<%=self.config%>.<%=section%>" data-type="uciname" data-optional="true"<%=
+ ifattr(#keys > 0, "data-choices", luci.util.json_encode({keys, vals}))
+ %> />
+ <% else %>
+ <select id="cbi.opt.<%=self.config%>.<%=section%>" name="cbi.opt.<%=self.config%>.<%=section%>" data-optionals="true">
+ <option><%: -- Additional Field -- %></option>
+ <% for key, val in pairs(self.optionals[section]) do -%>
+ <option id="cbi-<%=self.config.."-"..section.."-"..val.option%>" value="<%=val.option%>" data-index="<%=val.index%>" data-depends="<%=pcdata(val:deplist2json(section))%>"><%=striptags(val.title)%></option>
+ <%- end %>
+ </select>
+ <% end %>
<input type="submit" class="cbi-button cbi-button-fieldadd" value="<%:Add%>" />
</div>
<% end %>
diff --git a/modules/luci-base/luasrc/view/cbi/value.htm b/modules/luci-base/luasrc/view/cbi/value.htm
index 9bb4f3b0f6..c8c905eb11 100644
--- a/modules/luci-base/luasrc/view/cbi/value.htm
+++ b/modules/luci-base/luasrc/view/cbi/value.htm
@@ -8,35 +8,11 @@
ifattr(self.size, "size") ..
ifattr(self.placeholder, "placeholder") ..
ifattr(self.readonly, "readonly") ..
- ifattr(self.maxlength, "maxlength")
+ ifattr(self.maxlength, "maxlength") ..
+ ifattr(self.datatype, "data-type", self.datatype) ..
+ ifattr(self.datatype, "data-optional", self.optional or self.rmempty) ..
+ ifattr(self.combobox_manual, "data-manual", self.combobox_manual) ..
+ ifattr(#self.keylist > 0, "data-choices", { self.keylist, self.vallist })
%> />
<% if self.password then %><img src="<%=resource%>/cbi/reload.gif" style="vertical-align:middle" title="<%:Reveal/hide password%>" onclick="var e = document.getElementById('<%=cbid%>'); e.type = (e.type=='password') ? 'text' : 'password';" /><% end %>
- <% if #self.keylist > 0 or self.datatype then -%>
- <script type="text/javascript">//<![CDATA[
- <% if #self.keylist > 0 then -%>
- cbi_combobox_init('<%=cbid%>', {
- <%-
- for i, k in ipairs(self.keylist) do
- -%>
- <%-=string.format("%q", k) .. ":" .. string.format("%q", self.vallist[i])-%>
- <%-if i<#self.keylist then-%>,<%-end-%>
- <%-
- end
- -%>
- }, '<%- if not self.rmempty and not self.optional then -%>
- <%-: -- Please choose -- -%>
- <%- elseif self.placeholder then -%>
- <%-= pcdata(self.placeholder) -%>
- <%- end -%>', '
- <%- if self.combobox_manual then -%>
- <%-=self.combobox_manual-%>
- <%- else -%>
- <%-: -- custom -- -%>
- <%- end -%>');
- <%- end %>
- <% if self.datatype then -%>
- cbi_validate_field('<%=cbid%>', <%=tostring((self.optional or self.rmempty) == true)%>, '<%=self.datatype:gsub("\\", "\\\\"):gsub("'", "\\'")%>');
- <%- end %>
- //]]></script>
- <% end -%>
<%+cbi/valuefooter%>