luci-base: support cidr list notation for option ipaddr and ip6addr
authorJo-Philipp Wich <jo@mein.io>
Thu, 13 Dec 2018 10:31:50 +0000 (11:31 +0100)
committerJo-Philipp Wich <jo@mein.io>
Thu, 13 Dec 2018 10:35:38 +0000 (11:35 +0100)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/luasrc/model/cbi/admin_network/proto_static.lua
modules/luci-base/luasrc/view/cbi/ipaddr.htm [new file with mode: 0644]

index 3f8b091cf3038052c60c5f02b6c190d99d81c287..242dc59b5eed54d6af20d901da5268eefd00742b 100644 (file)
@@ -4,17 +4,87 @@
 local map, section, net = ...
 local ifc = net:get_interface()
 
-local ipaddr, netmask, gateway, broadcast, dns, accept_ra, send_rs, ip6addr, ip6gw
-local mtu, metric
+local netmask, gateway, broadcast, dns, accept_ra, send_rs, ip6addr, ip6gw
+local mtu, metric, usecidr, ipaddr_single, ipaddr_multi
 
 
-ipaddr = section:taboption("general", Value, "ipaddr", translate("IPv4 address"))
-ipaddr.datatype = "ip4addr"
+usecidr = section:taboption("general", Value, "ipaddr_usecidr")
+usecidr.forcewrite = true
 
+usecidr.cfgvalue = function(self, section)
+       local cfgvalue = self.map:get(section, "ipaddr")
+       return (type(cfgvalue) == "table") and "1" or "0"
+end
+
+usecidr.render = function(self, section, scope)
+       luci.template.Template(nil, [[
+               <input type="hidden"<%= attr("id", cbid) .. attr("name", cbid) .. attr("value", value) %> />
+       ]]):render({
+               cbid = self:cbid(section),
+               value = self:cfgvalue(section)
+       })
+end
+
+usecidr.write = function(self, section)
+       local cfgvalue = self.map:get(section, "ipaddr")
+       local formvalue = (self:formvalue(section) == "1") and ipaddr_multi:formvalue(section) or ipaddr_single:formvalue(section)
+       local equal = (cfgvalue == formvalue)
+
+       if not equal and type(cfgvalue) == "table" and type(formvalue) == "table" then
+               equal = true
+
+               local _, v
+               for _, v in ipairs(cfgvalue) do
+                       if v ~= formvalue[_] then
+                               equal = false
+                               break
+                       end
+               end
+       end
+
+       if not equal then
+               self.map:set(section, "ipaddr", formvalue or "")
+       end
+
+       return not equal
+end
+
+
+ipaddr_multi = section:taboption("general", DynamicList, "ipaddrs", translate("IPv4 address"))
+ipaddr_multi:depends("ipaddr_usecidr", "1")
+ipaddr_multi.datatype = "or(cidr4,ipnet4)"
+ipaddr_multi.placeholder = translate("Add IPv4 address…")
+
+ipaddr_multi.alias = "ipaddr"
+ipaddr_multi.write = function() end
+ipaddr_multi.remove = function() end
+ipaddr_multi.cfgvalue = function(self, section)
+       local addr = self.map:get(section, "ipaddr")
+       local mask = self.map:get(section, "netmask")
+
+       if type(addr) == "string" and
+          type(mask) == "string" and
+          #addr > 0 and #mask > 0
+       then
+               return { "%s/%s" %{ addr, mask } }
+       elseif type(addr) == "table" then
+               return addr
+       else
+               return {}
+       end
+end
+
+
+ipaddr_single = section:taboption("general", Value, "ipaddr", translate("IPv4 address"))
+ipaddr_single:depends("ipaddr_usecidr", "0")
+ipaddr_single.datatype = "ip4addr"
+ipaddr_single.template = "cbi/ipaddr"
+ipaddr_single.write = function() end
+ipaddr_single.remove = function() end
 
-netmask = section:taboption("general", Value, "netmask",
-       translate("IPv4 netmask"))
 
+netmask = section:taboption("general", Value, "netmask", translate("IPv4 netmask"))
+netmask:depends("ipaddr_usecidr", "0")
 netmask.datatype = "ip4addr"
 netmask:value("255.255.255.0")
 netmask:value("255.255.0.0")
@@ -48,8 +118,9 @@ if luci.model.network:has_ipv6() then
                translate("Assign prefix parts using this hexadecimal subprefix ID for this interface."))
        for i=33,64 do ip6hint:depends("ip6assign", i) end
 
-       ip6addr = section:taboption("general", Value, "ip6addr", translate("IPv6 address"))
+       ip6addr = section:taboption("general", DynamicList, "ip6addr", translate("IPv6 address"))
        ip6addr.datatype = "ip6addr"
+       ip6addr.placeholder = translate("Add IPv6 address…")
        ip6addr:depends("ip6assign", "")
 
 
diff --git a/modules/luci-base/luasrc/view/cbi/ipaddr.htm b/modules/luci-base/luasrc/view/cbi/ipaddr.htm
new file mode 100644 (file)
index 0000000..1c924e1
--- /dev/null
@@ -0,0 +1,27 @@
+<%+cbi/valueheader%>
+       <script type="text/javascript">
+               function switchToCIDRList(ev) {
+                       var input = ev.target.previousElementSibling,
+                           usecidr = document.getElementById(input.id + '_usecidr');
+
+                       ev.preventDefault();
+
+                       usecidr.value = '1';
+                       cbi_d_update();
+               }
+       </script>
+       <input data-update="change"<%=
+               attr("id", cbid) ..
+               attr("name", cbid) ..
+               attr("type", "text") ..
+               attr("class", "cbi-input-text") ..
+               attr("value", self:cfgvalue(section) or self.default) ..
+               ifattr(self.size, "size") ..
+               ifattr(self.placeholder, "placeholder") ..
+               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 })
+       %> /><!--
+       --><button class="cbi-button cbi-button-neutral" title="<%:Switch to CIDR list notation%>" aria-label="<%:Switch to CIDR list notation%>" onclick="switchToCIDRList(event)">…</button>
+<%+cbi/valuefooter%>