/* * dateinput.js * * dependencies: prototype.js, lowpro.js * * -------------------------------------------------------------------------- * * Renders a date input. To use, add the following line to application.js: * * Event.addBehavior({'input.date': DateInputBehavior()}); * * This will effectively wire all inputs with a class of "date" to the * DateInputBehavior. * * This code was originally based on Dan Web's code for date_selector.js, but * has been modified from its original form. You can find Dan's original * code here: * * http://github.com/danwrong/low-pro/blob/master/behaviours/date_selector.js * * -------------------------------------------------------------------------- * * Copyright (c) 2007-2009, Five Points Solutions, Inc. * Portions Copyright (c) 2004, Dan Web * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ DateInputBehavior = Behavior.create({ initialize: function(options) { this.element.setAttribute("autocomplete", "off"); this.calendar = null; this.options = Object.extend(DateInputBehavior.DEFAULTS, options || {}); this.date = this.getDate(); this._createCalendar(); }, setDate: function(value, hideCalendar) { this.date = value; this.element.value = this.options.setter(this.date); var timeoutTime = 250; if (Prototype.Browser.IE) timeoutTime = 50; if (hideCalendar == null) hideCalendar = true; if (hideCalendar && this.calendar) { setTimeout(function() { this.calendar.element.hide(); this.element.select(); }.bind(this), timeoutTime); } this.element.fire('date:changed'); }, _createCalendar : function() { var calendar = $div({'class': 'calendar_popup'}); var body = $(document.getElementsByTagName('body')[0]); body.insert(calendar); calendar.setStyle('position: absolute'); this.calendar = new DateInputBehavior.Calendar(calendar, this); }, onclick : function(event) { if (this._isOverWidget(event)) { this.calendar.toggle(); event.stop(); } }, onmouseover: function(event) { if (this._isOverWidget(event)) this.element.setStyle("cursor: pointer"); else this.element.setStyle("cursor: text"); }, onmouseout: function(event) { if (this._isOverWidget(event)) this.element.setStyle("cursor: text"); else this.element.setStyle("cursor: pointer"); }, onmousemove: function(event) { this.onmouseover(event); }, onkeypress: function(event) { switch(event.keyCode) { case Event.KEY_UP: case 38: case Event.KEY_DOWN: case 63233: case 40: this.calendar.toggle(); event.stop(); break; case Event.KEY_ESC: this.calendar.hide(); break; case Event.KEY_TAB: this.calendar.hide(); event.stop(); var formElements = this.element.up('form').getElements(); var elementIndex = formElements.indexOf(this.element) + 1; if (formElements.length > elementIndex) formElements[elementIndex].focus(); break; } }, onkeydown: function(event) { if (Prototype.Browser.IE) this.onkeypress(event); if (Prototype.Browser.WebKit && (event.keyCode == 40 || event.keyCode == 38)){ this.onkeypress(event); } }, getDate : function() { return this.options.getter(this.element.value) || new Date(); }, _isOverWidget: function(event) { var positionedOverWidget = null; if (Prototype.Browser.IE) { var widgetLeft = this.element.cumulativeOffset().left; var widgetRight = this.element.cumulativeOffset().left + this.element.getDimensions().width; positionedOverWidget = (event.pointerX() >= widgetLeft && event.pointerX() <= widgetRight); } else { var calendarIconWidth = parseInt(this.element.getStyle('padding-right'), 10); var widgetLeft = this.element.cumulativeOffset().left + this.element.getDimensions().width - calendarIconWidth; positionedOverWidget = (event.pointerX() >= widgetLeft); } return positionedOverWidget; } }); DateInputBehavior.Calendar = Behavior.create({ initialize: function(selector) { this.selector = selector; this.element.hide(); Event.observe(document, 'click', this.element.hide.bind(this.element)); }, show: function() { DateInputBehavior.Calendar.instances.invoke('hide'); this.date = this.selector.getDate(); this.redraw(); this.element.setStyle({ 'top': this.getVerticalOffset(this.selector.element) + 'px', 'left': Math.max(this.selector.element.cumulativeOffset().left + this.selector.element.getWidth() - this.element.getWidth() - 4, this.selector.element.cumulativeOffset().left) + 'px', 'z-index': 10001 }); this.element.show(); this.active = true; }, getVerticalOffset: function(selector){ var defaultOffset = this.selector.element.cumulativeOffset().top + this.selector.element.getHeight() + 2; var height = this.element.getHeight(); var top = 0; if(document.viewport.getHeight() > defaultOffset + height) { top = defaultOffset; } else { top = (defaultOffset - height - selector.getHeight() - 6); } if (top < document.viewport.getScrollOffsets().top) top = document.viewport.getScrollOffsets().top; return top; }, hide: function() { this.element.hide(); this.active = false; }, toggle: function() { if (this.element.visible()) { this.hide(); } else { this.show(); } }, redraw: function() { var oldMonth = this.element.down('select.month'); if (oldMonth) Event.stopObserving(oldMonth, 'change', oldMonth._monthChanged); var oldYear = this.element.down('select.year'); if (oldYear) Event.stopObserving(oldYear, 'change', oldYear._yearChanged); var html = '
← | ' + '' + this._monthYear() + ' | ' + '→ | ' + '||||
---|---|---|---|---|---|---|