Browse Source

gluon-web: extend ListValue with optional and unset values

If a value is unset or optional, an empty choice is added to the selection.
This empty choice will be marked as invalid if the value is not optional.

This is properly supported for the 'select' widget only for now, and not
for 'radio'.
Matthias Schiffer 6 years ago
parent
commit
ec532b95cf

+ 18 - 15
package/gluon-web/files/lib/gluon/web/view/model/lvalue.html

@@ -1,40 +1,43 @@
 <%
 	local br = self.orientation == "horizontal" and '&#160;&#160;&#160;' or '<br />'
+	local entries = self:entries()
 %>
 
 <% if self.widget == "select" then %>
 	<select class="gluon-input-select" data-update="change"<%=
 		attr("id", id) ..
 		attr("name", id) ..
-		attr("size", self.size)
+		attr("size", self.size) ..
+		attr("data-type", "minlength(1)") ..
+		attr("data-optional", self.optional)
 	%>>
-		<% for i, key in pairs(self.keylist) do -%>
+		<% for i, entry in pairs(entries) do -%>
 			<option<%=
-				attr("id", id.."."..key) ..
-				attr("value", key) ..
+				attr("id", id.."."..entry.key) ..
+				attr("value", entry.key) ..
 				attr("data-index", i) ..
-				attr("data-depends", self:deplist(self.valdeps[i])) ..
-				attr("selected", (self:cfgvalue() == key) and "selected")
-			%>><%=pcdata(self.vallist[i])%></option>
+				attr("data-depends", self:deplist(entry.deps)) ..
+				attr("selected", (self:cfgvalue() == entry.key) and "selected")
+			%>><%=pcdata(entry.value)%></option>
 		<%- end %>
 	</select>
 <% elseif self.widget == "radio" then %>
 	<div>
-		<% for i, key in pairs(self.keylist) do %>
+		<% for i, entry in pairs(entries) do %>
 			<label<%=
 				attr("data-index", i) ..
-				attr("data-depends", self:deplist(self.valdeps[i]))
+				attr("data-depends", self:deplist(entry.deps))
 			%>>
 				<input class="gluon-input-radio" data-update="click change" type="radio"<%=
-					attr("id", id.."."..key) ..
+					attr("id", id.."."..entry.key) ..
 					attr("name", id) ..
-					attr("value", key) ..
-					attr("checked", (self:cfgvalue() == key) and "checked")
+					attr("value", entry.key) ..
+					attr("checked", (self:cfgvalue() == entry.key) and "checked")
 				%> />
-				<label<%= attr("for", id.."."..key)%>></label>
-				<%=pcdata(self.vallist[i])%>
+				<label<%= attr("for", id.."."..entry.key)%>></label>
+				<%=pcdata(entry.value)%>
 			</label>
-			<% if i ~= #self.keylist then write(br) end %>
+			<% if i ~= #entries then write(br) end %>
 		<% end %>
 	</div>
 <% end %>

File diff suppressed because it is too large
+ 0 - 0
package/gluon-web/files/lib/gluon/web/www/static/resources/gluon-web.js


+ 2 - 6
package/gluon-web/javascript/gluon-web.js

@@ -471,7 +471,7 @@
 		bind(field, "blur",  validator);
 		bind(field, "keyup", validator);
 
-		if (field.nodeName == 'SELECT') {
+		if (field.nodeName.toLowerCase() == 'select') {
 			bind(field, "change", validator);
 			bind(field, "click",  validator);
 		}
@@ -497,7 +497,6 @@
 		var nodes;
 
 		nodes = document.querySelectorAll('[data-depends]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			var index = parseInt(node.getAttribute('data-index'), 10);
 			var depends = JSON.parse(node.getAttribute('data-depends'));
@@ -509,7 +508,6 @@
 		}
 
 		nodes = document.querySelectorAll('[data-update]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			var events = node.getAttribute('data-update').split(' ');
 			for (var j = 0, event; (event = events[j]) !== undefined; j++) {
@@ -518,14 +516,12 @@
 		}
 
 		nodes = document.querySelectorAll('[data-type]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			validate_field(node, node.getAttribute('data-optional') === 'true',
-			                   node.getAttribute('data-type'));
+				node.getAttribute('data-type'));
 		}
 
 		nodes = document.querySelectorAll('[data-dynlist]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			var attr = JSON.parse(node.getAttribute('data-dynlist'));
 

+ 36 - 8
package/gluon-web/luasrc/usr/lib/lua/gluon/web/model.lua

@@ -396,24 +396,52 @@ function ListValue:__init__(...)
 	self.size = 1
 	self.widget = "select"
 
-	self.keylist = {}
-	self.vallist = {}
-	self.valdeps = {}
+	self.keys = {}
+	self.entry_list = {}
 end
 
 function ListValue:value(key, val, ...)
-	if util.contains(self.keylist, key) then
+	if self.keys[key] then
 		return
 	end
 
 	val = val or key
-	table.insert(self.keylist, tostring(key))
-	table.insert(self.vallist, tostring(val))
-	table.insert(self.valdeps, {...})
+	self.keys[key] = true
+	table.insert(self.entry_list, {
+		key = tostring(key),
+		value = tostring(val),
+		deps = {...},
+	})
+end
+
+function ListValue:entries()
+	local ret = {unpack(self.entry_list)}
+
+	if self:cfgvalue() == nil or self.optional then
+		table.insert(ret, 1, {
+			key = '',
+			value = '',
+			deps = {},
+		})
+	end
+
+	return ret
 end
 
 function ListValue:validate()
-	return util.contains(self.keylist, self.data)
+	if self.keys[self.data] then
+		return true
+	end
+
+	if type(self.data) == "string" and #self.data == 0 then
+		self.data = nil
+	end
+
+	if self.data == nil then
+		return self.optional
+	end
+
+	return false
 end
 
 

Some files were not shown because too many files changed in this diff