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 br = self.orientation == "horizontal" and '&#160;&#160;&#160;' or '<br />'
+	local entries = self:entries()
 %>
 %>
 
 
 <% if self.widget == "select" then %>
 <% if self.widget == "select" then %>
 	<select class="gluon-input-select" data-update="change"<%=
 	<select class="gluon-input-select" data-update="change"<%=
 		attr("id", id) ..
 		attr("id", id) ..
 		attr("name", 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<%=
 			<option<%=
-				attr("id", id.."."..key) ..
-				attr("value", key) ..
+				attr("id", id.."."..entry.key) ..
+				attr("value", entry.key) ..
 				attr("data-index", i) ..
 				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 %>
 		<%- end %>
 	</select>
 	</select>
 <% elseif self.widget == "radio" then %>
 <% elseif self.widget == "radio" then %>
 	<div>
 	<div>
-		<% for i, key in pairs(self.keylist) do %>
+		<% for i, entry in pairs(entries) do %>
 			<label<%=
 			<label<%=
 				attr("data-index", i) ..
 				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"<%=
 				<input class="gluon-input-radio" data-update="click change" type="radio"<%=
-					attr("id", id.."."..key) ..
+					attr("id", id.."."..entry.key) ..
 					attr("name", id) ..
 					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>
 			</label>
-			<% if i ~= #self.keylist then write(br) end %>
+			<% if i ~= #entries then write(br) end %>
 		<% end %>
 		<% end %>
 	</div>
 	</div>
 <% end %>
 <% 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, "blur",  validator);
 		bind(field, "keyup", validator);
 		bind(field, "keyup", validator);
 
 
-		if (field.nodeName == 'SELECT') {
+		if (field.nodeName.toLowerCase() == 'select') {
 			bind(field, "change", validator);
 			bind(field, "change", validator);
 			bind(field, "click",  validator);
 			bind(field, "click",  validator);
 		}
 		}
@@ -497,7 +497,6 @@
 		var nodes;
 		var nodes;
 
 
 		nodes = document.querySelectorAll('[data-depends]');
 		nodes = document.querySelectorAll('[data-depends]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			var index = parseInt(node.getAttribute('data-index'), 10);
 			var index = parseInt(node.getAttribute('data-index'), 10);
 			var depends = JSON.parse(node.getAttribute('data-depends'));
 			var depends = JSON.parse(node.getAttribute('data-depends'));
@@ -509,7 +508,6 @@
 		}
 		}
 
 
 		nodes = document.querySelectorAll('[data-update]');
 		nodes = document.querySelectorAll('[data-update]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			var events = node.getAttribute('data-update').split(' ');
 			var events = node.getAttribute('data-update').split(' ');
 			for (var j = 0, event; (event = events[j]) !== undefined; j++) {
 			for (var j = 0, event; (event = events[j]) !== undefined; j++) {
@@ -518,14 +516,12 @@
 		}
 		}
 
 
 		nodes = document.querySelectorAll('[data-type]');
 		nodes = document.querySelectorAll('[data-type]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			validate_field(node, node.getAttribute('data-optional') === 'true',
 			validate_field(node, node.getAttribute('data-optional') === 'true',
-			                   node.getAttribute('data-type'));
+				node.getAttribute('data-type'));
 		}
 		}
 
 
 		nodes = document.querySelectorAll('[data-dynlist]');
 		nodes = document.querySelectorAll('[data-dynlist]');
-
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 		for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
 			var attr = JSON.parse(node.getAttribute('data-dynlist'));
 			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.size = 1
 	self.widget = "select"
 	self.widget = "select"
 
 
-	self.keylist = {}
-	self.vallist = {}
-	self.valdeps = {}
+	self.keys = {}
+	self.entry_list = {}
 end
 end
 
 
 function ListValue:value(key, val, ...)
 function ListValue:value(key, val, ...)
-	if util.contains(self.keylist, key) then
+	if self.keys[key] then
 		return
 		return
 	end
 	end
 
 
 	val = val or key
 	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
 end
 
 
 function ListValue:validate()
 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
 end
 
 
 
 

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