// vim: et:ts=4:sw=4:sts=4:ft=javascript 'use strict'; /*@ Ox.Form Form Object () -> Form Object (options) -> Form Object (options, self) -> Form Object options Options object error error id id items [] submit on submit function self shared private variable @*/ Ox.Form = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ error: '', id: '', items: [], submit: null }) .options(options || {}) // fixme: the || {} can be done once, in the options function .addClass('OxForm'); Ox.extend(self, { $items: [], $messages: [], formIsValid: false, itemIds: [], itemIsValid: [] }); self.options.items.forEach(function(item, i) { var validateItem = item.options('validate'); if (validateItem) { validateItem(item.value(), function(data) { self.itemIsValid[i] = data.valid; }); } else { self.itemIsValid[i] = item.value().length > 0; } self.itemIds[i] = item.options('id') || item.id; that.append(self.$items[i] = Ox.FormItem({element: item})); item.bindEvent({ /* blur: function(data) { validate(i, data.valid); if (data.valid) { self.$messages[i].html('').hide(); } else { self.$messages[i].html(data.message).show(); } }, */ autovalidate: function(data) { validateForm(i, data.valid); data.valid && self.$items[i].setMessage(''); }, /* // fixme: should't inputs also trigger a change event? blur: function(data) { that.triggerEvent('change', { id: self.itemIds[i], data: data }); }, */ change: function(data) { // fixme: shouldn't this be key/value instead of id/data? that.triggerEvent('change', { id: self.itemIds[i], data: data }); }, submit: function(data) { self.formIsValid && that.submit(); }, validate: function(data) { validateForm(i, data.valid); // timeout needed for cases where the form is removed // from the DOM, triggering blur of an empty item - // in this case, we don't want the message to appear setTimeout(function() { self.$items[i].setMessage(data.valid ? '' : data.message); }, 0); } }); }); function getItemIndexById(id) { return self.itemIds.indexOf(id); } function submitCallback(data) { Ox.forEach(data, function(v, i) { self.$items[getItemIndexById(v.id)].setMessage(v.message); }); } function validateForm(pos, valid) { self.itemIsValid[pos] = valid; Ox.Log('Form', 'VALID???', self.itemIsValid) if (Ox.every(self.itemIsValid) != self.formIsValid) { self.formIsValid = !self.formIsValid; that.triggerEvent('validate', { valid: self.formIsValid }); } } that.addItem = function(pos, item) { Ox.Log('Form', 'addItem', pos) self.options.items.splice(pos, 0, item); self.$items.splice(pos, 0, Ox.FormItem({element: item})); pos == 0 ? self.$items[pos].insertBefore(self.$items[0]) : self.$items[pos].insertAfter(self.$items[pos - 1]); } that.removeItem = function(pos) { Ox.Log('Form', 'removeItem', pos); self.$items[pos].remove(); self.options.items.splice(pos, 1); self.$items.splice(pos, 1); } that.submit = function() { // fixme: this seems to be unneeded //Ox.Log('Form', '---- that.values()', that.values()) self.options.submit(that.values(), submitCallback); }; that.values = function() { // fixme: can this be private? /* get/set form values call without arguments to get current form values pass values as array to set values (not implemented) */ var values = {}; if (arguments.length == 0) { self.$items.forEach(function($item, i) { values[self.itemIds[i]] = self.$items[i].value(); //fixme: make the following work //values[self.itemIds[i]] = self.$items[i].options('value'); }); //Ox.Log('Form', 'VALUES', values) return values; } else { Ox.Log('Form', 'SET FORM VALUES', arguments[0]) Ox.forEach(arguments[0], function(value, key) { var index = getItemIndexById(key); //index > -1 && Ox.Log('Form', ':::::::', key, value) index > -1 && self.options.items[index].options({value: value}); }); return that; } }; return that; };