(function($) { var Alpaca = $.alpaca; Alpaca.Fields.SelectField = Alpaca.Fields.ListField.extend( /** * @lends Alpaca.Fields.SelectField.prototype */ { /** * @see Alpaca.Field#getFieldType */ getFieldType: function() { return "select"; }, /** * @see Alpaca.Fields.ListField#setup */ setup: function() { this.base(); }, /** * @see Alpaca.ControlField#getControlValue */ getControlValue: function() { var val = this._getControlVal(true); if (typeof(val) === "undefined") { val = this.data; } return this.convertValue(val); }, /** * @see Alpaca.Field#setValue */ setValue: function(val) { if (Alpaca.isArray(val)) { if (!Alpaca.compareArrayContent(val, this.getValue())) { if (!Alpaca.isEmpty(val) && this.control) { this.control.val(val); } this.base(val); } } else { if (val !== this.getValue()) { /* if (!Alpaca.isEmpty(val) && this.control) { this.control.val(val); } */ if (this.control && typeof(val) != "undefined" && val != null) { this.control.val(val); } this.base(val); } } }, /** * @see Alpaca.ListField#getEnum */ getEnum: function() { if (this.schema) { if (this.schema["enum"]) { return this.schema["enum"]; } else if (this.schema["type"] && this.schema["type"] === "array" && this.schema["items"] && this.schema["items"]["enum"]) { return this.schema["items"]["enum"]; } } }, initControlEvents: function() { var self = this; self.base(); if (self.options.multiple) { var button = this.control.parent().find("button.multiselect"); button.focus(function(e) { if (!self.suspendBlurFocus) { self.onFocus.call(self, e); self.trigger("focus", e); } }); button.blur(function(e) { if (!self.suspendBlurFocus) { self.onBlur.call(self, e); self.trigger("blur", e); } }); } }, beforeRenderControl: function(model, callback) { var self = this; this.base(model, function() { if (self.schema["type"] && self.schema["type"] === "array") { self.options.multiple = true; } callback(); }); }, prepareControlModel: function(callback) { var self = this; this.base(function(model) { model.selectOptions = self.selectOptions; callback(model); }); }, afterRenderControl: function(model, callback) { var self = this; this.base(model, function() { // if emptySelectFirst and nothing currently checked, then pick first item in the value list // set data and visually select it if (Alpaca.isUndefined(self.data) && self.options.emptySelectFirst && self.selectOptions && self.selectOptions.length > 0) { self.data = self.selectOptions[0].value; } // do this little trick so that if we have a default value, it gets set during first render // this causes the state of the control if (self.data) { self.setValue(self.data); } // if we are in multiple mode and the bootstrap multiselect plugin is available, bind it in if (self.options.multiple && $.fn.multiselect) { var settings = null; if (self.options.multiselect) { settings = self.options.multiselect; } else { settings = {}; } if (!settings.nonSelectedText) { settings.nonSelectedText = "None"; if (self.options.noneLabel) { settings.nonSelectedText = self.options.noneLabel; } } if (self.options.hideNone) { delete settings.nonSelectedText; } $(self.getControlEl()).multiselect(settings); } callback(); }); }, /** * Validate against enum property. * * @returns {Boolean} True if the element value is part of the enum list, false otherwise. */ _validateEnum: function() { var _this = this; if (this.schema["enum"]) { var val = this.data; if (!this.isRequired() && Alpaca.isValEmpty(val)) { return true; } if (this.options.multiple) { var isValid = true; if (!val) { val = []; } if (!Alpaca.isArray(val) && !Alpaca.isObject(val)) { val = [val]; } $.each(val, function(i,v) { if ($.inArray(v, _this.schema["enum"]) <= -1) { isValid = false; return false; } }); return isValid; } else { return ($.inArray(val, this.schema["enum"]) > -1); } } else { return true; } }, /** * @see Alpaca.Field#onChange */ onChange: function(e) { this.base(e); var _this = this; Alpaca.later(25, this, function() { var v = _this.getValue(); _this.setValue(v); _this.refreshValidationState(); }); }, /** * Validates if number of items has been less than minItems. * @returns {Boolean} true if number of items has been less than minItems */ _validateMinItems: function() { if (this.schema.items && this.schema.items.minItems) { if ($(":selected",this.control).length < this.schema.items.minItems) { return false; } } return true; }, /** * Validates if number of items has been over maxItems. * @returns {Boolean} true if number of items has been over maxItems */ _validateMaxItems: function() { if (this.schema.items && this.schema.items.maxItems) { if ($(":selected",this.control).length > this.schema.items.maxItems) { return false; } } return true; }, /** * @see Alpaca.ContainerField#handleValidate */ handleValidate: function() { var baseStatus = this.base(); var valInfo = this.validation; var status = this._validateMaxItems(); valInfo["tooManyItems"] = { "message": status ? "" : Alpaca.substituteTokens(this.getMessage("tooManyItems"), [this.schema.items.maxItems]), "status": status }; status = this._validateMinItems(); valInfo["notEnoughItems"] = { "message": status ? "" : Alpaca.substituteTokens(this.getMessage("notEnoughItems"), [this.schema.items.minItems]), "status": status }; return baseStatus && valInfo["tooManyItems"]["status"] && valInfo["notEnoughItems"]["status"]; }, /** * @see Alpaca.Field#focus */ focus: function(onFocusCallback) { if (this.control && this.control.length > 0) { // set focus onto the select var el = $(this.control).get(0); el.focus(); if (onFocusCallback) { onFocusCallback(this); } } } /* builder_helpers */ , /** * @see Alpaca.Field#getTitle */ getTitle: function() { return "Select Field"; }, /** * @see Alpaca.Field#getDescription */ getDescription: function() { return "Select Field"; }, /** * @private * @see Alpaca.Fields.ListField#getSchemaOfOptions */ getSchemaOfOptions: function() { return Alpaca.merge(this.base(), { "properties": { "multiple": { "title": "Mulitple Selection", "description": "Allow multiple selection if true.", "type": "boolean", "default": false }, "size": { "title": "Displayed Options", "description": "Number of options to be shown.", "type": "number" }, "emptySelectFirst": { "title": "Empty Select First", "description": "If the data is empty, then automatically select the first item in the list.", "type": "boolean", "default": false }, "multiselect": { "title": "Multiselect Plugin Settings", "description": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect", "type": "any" } } }); }, /** * @private * @see Alpaca.Fields.ListField#getOptionsForOptions */ getOptionsForOptions: function() { return Alpaca.merge(this.base(), { "fields": { "multiple": { "rightLabel": "Allow multiple selection ?", "helper": "Allow multiple selection if checked", "type": "checkbox" }, "size": { "type": "integer" }, "emptySelectFirst": { "type": "checkbox", "rightLabel": "Empty Select First" }, "multiselect": { "type": "object", "rightLabel": "Multiselect plugin properties - http://davidstutz.github.io/bootstrap-multiselect" } } }); } /* end_builder_helpers */ }); Alpaca.registerFieldClass("select", Alpaca.Fields.SelectField); })(jQuery);