libs/web: rework DynamicList widget
This commit is contained in:
parent
eecec8b0f2
commit
70706cf388
4 changed files with 223 additions and 58 deletions
|
@ -265,22 +265,19 @@ function cbi_d_update() {
|
|||
}
|
||||
|
||||
function cbi_bind(obj, type, callback, mode) {
|
||||
if (typeof mode == "undefined") {
|
||||
mode = false;
|
||||
}
|
||||
if (!obj.addEventListener) {
|
||||
ieCallback = function(){
|
||||
obj.attachEvent('on' + type,
|
||||
function(){
|
||||
var e = window.event;
|
||||
if (!e.target && e.srcElement) {
|
||||
|
||||
if (!e.target && e.srcElement)
|
||||
e.target = e.srcElement;
|
||||
};
|
||||
e.target['_eCB' + type + callback] = callback;
|
||||
e.target['_eCB' + type + callback](e);
|
||||
e.target['_eCB' + type + callback] = null;
|
||||
};
|
||||
obj.attachEvent('on' + type, ieCallback);
|
||||
|
||||
return !!callback(e);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
obj.addEventListener(type, callback, mode);
|
||||
obj.addEventListener(type, callback, !!mode);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
@ -345,7 +342,9 @@ function cbi_combobox(id, values, def, man) {
|
|||
obj.focus();
|
||||
} else {
|
||||
obj.value = sel.options[sel.selectedIndex].value;
|
||||
sel.className = (!obj.validate || obj.validate())
|
||||
|
||||
var vld = obj.getAttribute("cbi_validate");
|
||||
sel.className = (!vld || vld())
|
||||
? 'cbi-input-select' : 'cbi-input-select cbi-input-invalid';
|
||||
}
|
||||
|
||||
|
@ -375,6 +374,152 @@ function cbi_filebrowser(id, url, defpath) {
|
|||
browser.focus();
|
||||
}
|
||||
|
||||
function cbi_dynlist_init(name)
|
||||
{
|
||||
function cbi_dynlist_renumber(e)
|
||||
{
|
||||
var count = 1;
|
||||
var childs = e.parentNode.childNodes;
|
||||
|
||||
for( var i = 0; i < childs.length; i++ )
|
||||
if( childs[i].name == name )
|
||||
childs[i].id = name + '.' + (count++);
|
||||
|
||||
e.focus();
|
||||
}
|
||||
|
||||
function cbi_dynlist_keypress(ev)
|
||||
{
|
||||
ev = ev ? ev : window.event;
|
||||
|
||||
var se = ev.target ? ev.target : ev.srcElement;
|
||||
|
||||
if (se.nodeType == 3)
|
||||
se = se.parentNode;
|
||||
|
||||
switch (ev.keyCode)
|
||||
{
|
||||
/* backspace, delete */
|
||||
case 8:
|
||||
case 46:
|
||||
if (se.value.length == 0)
|
||||
{
|
||||
if (ev.preventDefault)
|
||||
ev.preventDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
/* enter, arrow up, arrow down */
|
||||
case 13:
|
||||
case 38:
|
||||
case 40:
|
||||
if (ev.preventDefault)
|
||||
ev.preventDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function cbi_dynlist_keydown(ev)
|
||||
{
|
||||
ev = ev ? ev : window.event;
|
||||
|
||||
var se = ev.target ? ev.target : ev.srcElement;
|
||||
|
||||
if (se.nodeType == 3)
|
||||
se = se.parentNode;
|
||||
|
||||
var prev = se.previousSibling;
|
||||
while (prev && prev.name != name)
|
||||
prev = prev.previousSibling;
|
||||
|
||||
var next = se.nextSibling;
|
||||
while (next && next.name != name)
|
||||
next = next.nextSibling;
|
||||
|
||||
switch (ev.keyCode)
|
||||
{
|
||||
/* backspace, delete */
|
||||
case 8:
|
||||
case 46:
|
||||
var jump = (ev.keyCode == 8)
|
||||
? (prev || next) : (next || prev);
|
||||
|
||||
if (se.value.length == 0 && jump)
|
||||
{
|
||||
se.parentNode.removeChild(se.nextSibling);
|
||||
se.parentNode.removeChild(se);
|
||||
|
||||
cbi_dynlist_renumber(jump);
|
||||
|
||||
if (ev.preventDefault)
|
||||
ev.preventDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/* enter */
|
||||
case 13:
|
||||
var n = document.createElement('input');
|
||||
n.name = se.name;
|
||||
n.type = se.type;
|
||||
|
||||
cbi_bind(n, 'keydown', cbi_dynlist_keydown);
|
||||
cbi_bind(n, 'keypress', cbi_dynlist_keypress);
|
||||
|
||||
if (next)
|
||||
{
|
||||
se.parentNode.insertBefore(n, next);
|
||||
se.parentNode.insertBefore(document.createElement('br'), next);
|
||||
}
|
||||
else
|
||||
{
|
||||
se.parentNode.appendChild(n);
|
||||
se.parentNode.appendChild(document.createElement('br'));
|
||||
}
|
||||
|
||||
var dt = se.getAttribute('cbi_datatype');
|
||||
var op = se.getAttribute('cbi_optional') == 'true';
|
||||
|
||||
if (dt)
|
||||
cbi_validate_field(n, op, dt);
|
||||
|
||||
cbi_dynlist_renumber(n);
|
||||
break;
|
||||
|
||||
/* arrow up */
|
||||
case 38:
|
||||
if (prev)
|
||||
prev.focus();
|
||||
|
||||
break;
|
||||
|
||||
/* arrow down */
|
||||
case 40:
|
||||
if (next)
|
||||
next.focus();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var inputs = document.getElementsByName(name);
|
||||
for( var i = 0; i < inputs.length; i++ )
|
||||
{
|
||||
cbi_bind(inputs[i], 'keydown', cbi_dynlist_keydown);
|
||||
cbi_bind(inputs[i], 'keypress', cbi_dynlist_keypress);
|
||||
}
|
||||
}
|
||||
|
||||
//Hijacks the CBI form to send via XHR (requires Prototype)
|
||||
function cbi_hijack_forms(layer, win, fail, load) {
|
||||
var forms = layer.getElementsByTagName('form');
|
||||
|
@ -484,7 +629,7 @@ function cbi_validate_reset(form)
|
|||
|
||||
function cbi_validate_field(cbid, optional, type)
|
||||
{
|
||||
var field = document.getElementById(cbid);
|
||||
var field = (typeof cbid == "string") ? document.getElementById(cbid) : cbid;
|
||||
var vldcb = cbi_validators[type];
|
||||
|
||||
if( field && vldcb )
|
||||
|
@ -513,7 +658,13 @@ function cbi_validate_field(cbid, optional, type)
|
|||
field.form.cbi_validators = [ ];
|
||||
|
||||
field.form.cbi_validators.push(validator);
|
||||
field.onblur = field.onkeyup = field.validate = validator;
|
||||
|
||||
cbi_bind(field, "blur", validator);
|
||||
cbi_bind(field, "keyup", validator);
|
||||
|
||||
field.setAttribute("cbi_validate", validator);
|
||||
field.setAttribute("cbi_datatype", type);
|
||||
field.setAttribute("cbi_optional", (!!optional).toString());
|
||||
|
||||
validator();
|
||||
}
|
||||
|
|
|
@ -1641,25 +1641,48 @@ function DynamicList.value(self, key, val)
|
|||
table.insert(self.vallist, tostring(val))
|
||||
end
|
||||
|
||||
function DynamicList.write(self, ...)
|
||||
self.map.proceed = true
|
||||
return AbstractValue.write(self, ...)
|
||||
function DynamicList.write(self, section, value)
|
||||
if self.cast == "string" and type(value) == "table" then
|
||||
value = table.concat(value, " ")
|
||||
elseif self.cast == "table" and type(value) == "string" then
|
||||
local x, t = { }
|
||||
for x in value:gmatch("%S+") do
|
||||
t[#t+1] = x
|
||||
end
|
||||
value = t
|
||||
end
|
||||
|
||||
return AbstractValue.write(self, section, value)
|
||||
end
|
||||
|
||||
function DynamicList.cfgvalue(self, section)
|
||||
local value = AbstractValue.cfgvalue(self, section)
|
||||
|
||||
if type(value) == "string" then
|
||||
local x
|
||||
local t = { }
|
||||
for x in value:gmatch("%S+") do
|
||||
t[#t+1] = x
|
||||
end
|
||||
value = t
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
function DynamicList.formvalue(self, section)
|
||||
local value = AbstractValue.formvalue(self, section)
|
||||
value = (type(value) == "table") and value or {value}
|
||||
|
||||
local valid = {}
|
||||
for i, v in ipairs(value) do
|
||||
if v and #v > 0
|
||||
and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i)
|
||||
and not self.map:formvalue("cbi.rle."..section.."."..self.option.."."..i..".x") then
|
||||
table.insert(valid, v)
|
||||
if type(value) == "string" then
|
||||
local x
|
||||
local t = { }
|
||||
for x in value:gmatch("%S+") do
|
||||
t[#t+1] = x
|
||||
end
|
||||
value = t
|
||||
end
|
||||
|
||||
return valid
|
||||
return value
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -13,40 +13,31 @@ $Id$
|
|||
|
||||
-%>
|
||||
<%+cbi/valueheader%>
|
||||
<div>
|
||||
<%
|
||||
local vals = self:cfgvalue(section) or {}
|
||||
for i=1, #vals + 1 do
|
||||
local val = vals[i]
|
||||
%>
|
||||
<input class="cbi-input-text" value="<%=pcdata(val)%>" onchange="cbi_d_update(this.id)" type="text"<%= attr("id", cbid .. "." .. i) .. attr("name", cbid) .. ifattr(self.size, "size")%> />
|
||||
<% if i <= #vals then %>
|
||||
<input class="cbi-input-image" type="image" value="<%:Delete%>" name="cbi.rle.<%=section .. "." .. self.option .. "." .. i%>" alt="<%:Delete%>" title="<%:Delete%>" src="<%=resource%>/cbi/remove.gif" />
|
||||
<% else %>
|
||||
<input class="cbi-input-image" type="image" value="<%:Add%>" name="cbi.ale.<%=section .. "." .. self.option%>" alt="<%:Add%>" title="<%:Add%>" src="<%=resource%>/cbi/add.gif" />
|
||||
<% end %>
|
||||
<input class="cbi-input-text" value="<%=pcdata(val)%>" onchange="cbi_d_update(this.id)" type="text"<%= attr("id", cbid .. "." .. i) .. attr("name", cbid) .. ifattr(self.size, "size")%> /><br />
|
||||
<% end %>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
cbi_dynlist_init('<%=cbid%>');
|
||||
<% if self.datatype then -%>
|
||||
<% if #self.keylist > 0 then -%>
|
||||
<script type="text/javascript">
|
||||
cbi_combobox_init('<%=cbid .. "." .. i%>', {
|
||||
<%-
|
||||
for i, k in ipairs(self.keylist) do
|
||||
-%>
|
||||
<%- 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
|
||||
-%>
|
||||
<%- end -%>
|
||||
}, '<%- if not self.rmempty and not self.optional then -%>
|
||||
<%-:cbi_select-%>
|
||||
<%- end -%>', '<%: -- custom -- %>');
|
||||
</script>
|
||||
<% end -%>
|
||||
<% if i <= #vals then %><br />
|
||||
<% end end %>
|
||||
<% if self.datatype then -%>
|
||||
<script type="text/javascript">
|
||||
<% for i=1, #vals + 1 do -%>
|
||||
cbi_validate_field('<%=cbid%>.<%=i%>', <%=tostring(self.optional == true or i > #vals)%>, '<%=self.datatype%>');
|
||||
<%- end %>
|
||||
</script>
|
||||
<% end -%>
|
||||
</script>
|
||||
<%+cbi/valuefooter%>
|
||||
|
|
|
@ -14,7 +14,7 @@ $Id$
|
|||
-%>
|
||||
|
||||
<% if self.description and #self.description > 0 then -%>
|
||||
<% if not luci.util.instanceof( self, luci.cbi.Flag ) or self.orientation == "horizontal" then -%>
|
||||
<% if not luci.util.instanceof(self, luci.cbi.DynamicList) and (not luci.util.instanceof(self, luci.cbi.Flag) or self.orientation == "horizontal") then -%>
|
||||
<br />
|
||||
<%- end %>
|
||||
<div class="cbi-value-description">
|
||||
|
|
Loading…
Reference in a new issue