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(); });