diff --git a/lib/widgets.js b/lib/widgets.js
index bd30a2b..5e8ee77 100644
--- a/lib/widgets.js
+++ b/lib/widgets.js
@@ -104,15 +104,28 @@ exports.select = function (opt) {
classes: opt.classes,
type: 'select'
};
+ function groupHTML(group, label, value) {
+ return tag('optgroup', {
+ label: label
+ }, choicesHTML(group, value));
+ }
+ function choicesHTML(choices, value) {
+ return Object.keys(choices).reduce(function (html, k) {
+ if (is.object(choices[k])) {
+ return html + groupHTML(choices[k], String(k), value)
+ } else {
+ return html + tag('option', {
+ value: k,
+ selected: !!(value && String(value) === String(k))
+ }, choices[k]);
+ }
+ }, '')
+ }
+
var userAttrs = getUserAttrs(opt);
w.toHTML = function (name, f) {
if (!f) { f = {}; }
- var optionsHTML = Object.keys(f.choices).reduce(function (html, k) {
- return html + tag('option', {
- value: k,
- selected: !!(f.value && String(f.value) === String(k))
- }, f.choices[k]);
- }, '');
+ var optionsHTML = choicesHTML(f.choices, f.value, '');
return tag('select', [{
name: name,
id: f.id === false ? false : (f.id || true),
@@ -228,16 +241,33 @@ exports.multipleSelect = function (opt) {
classes: opt.classes,
type: 'multipleSelect'
};
+
+ function groupHTML(group, label, value) {
+ return tag('optgroup', {
+ label: label
+ }, choicesHTML(group, value));
+ }
+
+ function choicesHTML(choices, value) {
+ return Object.keys(choices).reduce(function (html, k) {
+ if (is.object(choices[k])) {
+ return html + groupHTML(choices[k], String(k), value)
+ } else {
+ var selected = value && (Array.isArray(value) ? value.some(function (v) {
+ return String(v) === String(k);
+ }) : String(value) === String(k));
+ return html + tag('option', {
+ value: k,
+ selected: !!selected
+ }, choices[k]);
+ }
+ }, '')
+ }
+
var userAttrs = getUserAttrs(opt);
w.toHTML = function (name, f) {
if (!f) { f = {}; }
- var optionsHTML = Object.keys(f.choices).reduce(function (html, k) {
- var selected = f.value && (Array.isArray(f.value) ? f.value.some(function (v) { return String(v) === String(k); }) : String(f.value) === String(k));
- return html + tag('option', {
- value: k,
- selected: !!selected
- }, f.choices[k]);
- }, '');
+ var optionsHTML = choicesHTML(f.choices, f.value);
return tag('select', [{
multiple: true,
name: name,
diff --git a/test/test-widgets.js b/test/test-widgets.js
index df7c21e..d93f9f1 100644
--- a/test/test-widgets.js
+++ b/test/test-widgets.js
@@ -125,7 +125,37 @@ test('select', function (t) {
var expectedHTML = '';
+ '';
+ st.equal(html, expectedHTML);
+ st.end();
+ });
+ t.test('provides option groups', function (st) {
+ var html = widget.toHTML('name', {
+ choices: {
+ regular: 'value',
+ group1: {
+ 1: 'one',
+ 2: 'two'
+ },
+ 'Group Two': {
+ 3: 'three',
+ 4: 'four'
+ }
+ },
+ id: 'someid',
+ value: '3'
+ });
+ var expectedHTML = '';
st.equal(html, expectedHTML);
st.end();
});
@@ -400,7 +430,37 @@ test('multipleSelect', function (t) {
st.end();
});
-
+ t.test('provides option groups', function (st) {
+ var widget = forms.widgets.multipleSelect({classes: ['one', 'two']});
+ var html = widget.toHTML('name', {
+ choices: {
+ 'Long groupname': {
+ 1: 'one',
+ 2: 'two'
+ },
+ regular: 'value',
+ Hamster: {
+ 3: 'dance',
+ 4: 'dance!!!'
+ }
+ },
+ id: 'someid',
+ value: ['2','regular']
+ });
+ var expectedHTML = '';
+ st.equal(html, expectedHTML);
+ st.end();
+ });
t.end();
});