(function($) { // NOTE: this requires bootstrap-datetimepicker.js // NOTE: this requires moment.js var Alpaca = $.alpaca; Alpaca.Fields.DateField = Alpaca.Fields.TextField.extend( /** * @lends Alpaca.Fields.DateField.prototype */ { /** * @see Alpaca.Fields.TextField#getFieldType */ getFieldType: function() { return "date"; }, getDefaultFormat: function() { return "MM/DD/YYYY"; }, getDefaultExtraFormats: function() { return []; }, /** * @see Alpaca.Fields.TextField#setup */ setup: function() { var self = this; // default html5 input type = "date"; //this.inputType = "date"; this.base(); if (!self.options.picker) { self.options.picker = {}; } if (typeof(self.options.picker.useCurrent) === "undefined") { self.options.picker.useCurrent = false; } // date format if (self.options.picker.format) { self.options.dateFormat = self.options.picker.format; } if (!self.options.dateFormat) { self.options.dateFormat = self.getDefaultFormat(); } if (!self.options.picker.format) { self.options.picker.format = self.options.dateFormat; } if (!self.options.picker.locale) { self.options.picker.locale = "en_US"; } if (!self.options.picker.dayViewHeaderFormat) { self.options.picker.dayViewHeaderFormat = "MMMM YYYY"; } // extra formats if (!self.options.picker.extraFormats) { var extraFormats = self.getDefaultExtraFormats(); if (extraFormats) { self.options.picker.extraFormats = extraFormats; } } if (typeof(self.options.manualEntry) === "undefined") { self.options.manualEntry = false; } }, onKeyPress: function(e) { if (this.options.manualEntry) { e.preventDefault(); e.stopImmediatePropagation(); } else { this.base(e); return; } }, onKeyDown: function(e) { if (this.options.manualEntry) { e.preventDefault(); e.stopImmediatePropagation(); } else { this.base(e); return; } }, beforeRenderControl: function(model, callback) { this.field.css("position", "relative"); callback(); }, /** * @see Alpaca.Fields.TextField#afterRenderControl */ afterRenderControl: function(model, callback) { var self = this; this.base(model, function() { if (self.view.type !== "display") { if ($.fn.datetimepicker) { self.getControlEl().datetimepicker(self.options.picker); self.picker = self.getControlEl().data("DateTimePicker"); if (self.picker && self.options.dateFormat) { self.picker.format(self.options.dateFormat); } if (self.picker) { self.options.dateFormat = self.picker.format(); } // with date-time picker, trigger change using plugin self.getFieldEl().on("dp.change", function(e) { // we use a timeout here because we want this to run AFTER control click handlers setTimeout(function() { self.onChange.call(self, e); self.triggerWithPropagation("change", e); }, 250); }); // set value if provided if (self.data) { self.picker.date(self.data); } } } callback(); }); }, /** * Allows manual entry mode to be toggled on and off. * * @param manualEntry */ setManualEntry: function(manualEntry) { this.options.manualEntry = manualEntry; }, /** * Returns field value as a JavaScript Date. * * @returns {Date} Field value. */ getDate: function() { var self = this; var date = null; try { if (self.picker) { date = (self.picker.date() ? self.picker.date()._d: null); } else { date = new Date(this.getValue()); } } catch (e) { console.error(e); } return date; }, /** * Returns field value as a JavaScript Date. * * @returns {Date} Field value. */ date: function() { return this.getDate(); }, /** * @see Alpaca.Field#onChange */ onChange: function(e) { this.base(); this.refreshValidationState(); }, isAutoFocusable: function() { return false; }, /** * @see Alpaca.Fields.TextField#handleValidate */ handleValidate: function() { var baseStatus = this.base(); var valInfo = this.validation; var status = this._validateDateFormat(); valInfo["invalidDate"] = { "message": status ? "" : Alpaca.substituteTokens(this.getMessage("invalidDate"), [this.options.dateFormat]), "status": status }; return baseStatus && valInfo["invalidDate"]["status"]; }, /** * Validates date format. * * @returns {Boolean} True if it is a valid date, false otherwise. */ _validateDateFormat: function() { var self = this; var isValid = true; if (self.options.dateFormat) { var value = self.getValue(); if (value || self.isRequired()) { // collect all formats var dateFormats = []; dateFormats.push(self.options.dateFormat); if (self.options.picker && self.options.picker.extraFormats) { for (var i = 0; i < self.options.picker.extraFormats.length; i++) { dateFormats.push(self.options.picker.extraFormats[i]); } } for (var i = 0; i < dateFormats.length; i++) { isValid = isValid || Alpaca.moment(value, self.options.dateFormat, true).isValid(); } } } return isValid; }, /** * @see Alpaca.Fields.TextField#setValue */ setValue: function(value) { var self = this; this.base(value); if (this.picker) { if (Alpaca.moment(value, self.options.dateFormat, true).isValid()) { this.picker.date(value); } } }, destroy: function() { this.base(); this.picker = null; } /* builder_helpers */ , /** * @see Alpaca.Fields.TextField#getTitle */ getTitle: function() { return "Date Field"; }, /** * @see Alpaca.Fields.TextField#getDescription */ getDescription: function() { return "Date Field"; }, /** * @private * @see Alpaca.Fields.TextField#getSchemaOfSchema */ getSchemaOfSchema: function() { return Alpaca.merge(this.base(), { "properties": { "format": { "title": "Format", "description": "Property data format", "type": "string", "default":"date", "enum" : ["date"], "readonly":true } } }); }, /** * @private * @see Alpaca.Fields.TextField#getOptionsForSchema */ getOptionsForSchema: function() { return Alpaca.merge(this.base(), { "fields": { "format": { "type": "text" } } }); }, /** * @private * @see Alpaca.Fields.TextField#getSchemaOfOptions */ getSchemaOfOptions: function() { return Alpaca.merge(this.base(), { "properties": { "dateFormat": { "title": "Date Format", "description": "Date format (using moment.js format)", "type": "string" }, "picker": { "title": "DatetimePicker options", "description": "Options that are supported by the <a href='http://eonasdan.github.io/bootstrap-datetimepicker/'>Bootstrap DateTime Picker</a>.", "type": "any" } } }); }, /** * @private * @see Alpaca.Fields.TextField#getOptionsForOptions */ getOptionsForOptions: function() { return Alpaca.merge(this.base(), { "fields": { "dateFormat": { "type": "text" }, "picker": { "type": "any" } } }); } /* end_builder_helpers */ }); Alpaca.registerMessages({ "invalidDate": "Invalid date for format {0}" }); Alpaca.registerFieldClass("date", Alpaca.Fields.DateField); Alpaca.registerDefaultFormatFieldMapping("date", "date"); })(jQuery);