var EffiCalendar = Class.create(JSControl, { initialize: function($super, element){ $super(element); this.controls_ = { "month": Element.down(this.element, "span.Month"), "year": Element.down(this.element, "span.Year"), "day": Element.down(this.element, "table.Day tbody") }; Element.setStyle(this.controls_.month, {"width": 1.2 * Math.max.apply(null, DateInput.monthnames.pluck("length")) + "ex"}); var firstdayattr = this.element.getAttribute("first-day") || ""; this.firstday_ = firstdayattr ? parseInt(firstdayattr, 10) || 0 : 1; var weekendsattr = this.element.getAttribute("weekends"); this.weekends_ = weekendsattr ? weekendsattr.split(" ").collect(function(str){ return parseInt(str, 10); }) : [0, 6]; this.SetValue(ADate.Current()); new AEvent("WM_INIT", {}, this); Event.observe(this.controls_.day, "click", function(event){ var td = Event.findElement(event, "td"); if (!td || !Element.descendantOf(td, this.controls_.day) || !Element.hasClassName(td, "day")) return; new AEvent("CLICK", {}, this); if (td != this.selected_cell_){ this.selectCell(td); // this.onchange(); } this.finalize(); }.bindAsEventListener(this)); var keyboard = this.keyboard.bindAsEventListener(this); Event.observe(this.controls_.day, "keydown", keyboard); var setcurrent = Element.down(this.element, "button.SetCurrent"); if (setcurrent) { Event.observe(setcurrent, "click", this.OnSetCurrent.bind(this)); Event.observe(setcurrent, "keydown", this.OnSetCurrent.bind(this)); } var buttons = {}; ["month", "year"].each(function(nam){ var elem = this.controls_[nam]; buttons[nam] = [Element.previous(elem, "button"), Element.next(elem, "button")]; }, this); [[buttons.month[0], this.dec_month], [buttons.month[1], this.inc_month], [buttons.year[0], this.dec_year], [buttons.year[1], this.inc_year]].each(function(arr){ if (arr[0]) Event.observe(arr[0], "click", arr[1].bind(this)); }, this); var showbox_months_timer = function(button){ var timer = window.setTimeout(this.showbox_months.bind(this).curry(button), 300); document.observe("mouseup", function(event){ window.clearTimeout(timer); this.hidebox_month(); }.bind(this)); }.bind(this); buttons.month.each(function(button){ if (button) Event.observe(button, "mousedown", showbox_months_timer.curry(button)); }, this); [[buttons.year[0], this.dec_year], [buttons.year[1], this.inc_year]].each(function(args){ this.bind_timer(args[0], args[1].bind(this)); }, this); }, OnSetCurrent: function(event) { if (event.ctrlKey || event.altKey) return; if(event.type=="keydown") { var key = event.which || event.keyCode; switch(key) { case Event.KEY_RETURN: break; default: return; } } var today = ADate.Current(); if (today.toString() != this.Value().toString()){ this.SetValue(today); // this.onchange(); } this.finalize(); Event.stop(event); return false; }, SetValue: function(date){ var today = new Date(); if (typeof date.day != "number" || isNaN(date.day)) date.day = today.getDate(); if (typeof date.month != "number" || isNaN(date.month)) date.month = today.getMonth() + 1; if (typeof date.year != "number" || isNaN(date.year)) date.year = today.getFullYear(); this.displayMonth(date.month, date.year); this.selectDay(date.day); }, clear: function(elem){ if (!elem) return null; while (elem.firstChild) elem.removeChild(elem.firstChild); return elem; }, addCell: function(tr, day){ var td = tr.insertCell(-1); if (typeof day != "undefined"){ td.value = day; td.appendChild(document.createTextNode(String(day))); Element.addClassName(td, "day"); } Element.addClassName(td, (td.cellIndex + 1) % 2 == 0 ? "even" : "odd"); return td; }, days_in_month: function(month, year){ return month == 2 && !DateInput.isLeapYear(year) ? 28 : DateInput.maxDays[month]; }, displayMonth: function(month, year){ if (typeof this.month_ != "undefined" && typeof this.year_ != "undefined" && // this.month_ == month && this.year_ == year) return; this.month_ = month; this.year_ = year; this.controls_.month.value = month; this.controls_.year.value = year; this.clear(this.controls_.month).appendChild(document.createTextNode(DateInput.monthnames[month])); this.clear(this.controls_.year).appendChild(document.createTextNode(String(year))); var firstday = new Date(year, month - 1, 1, 0, 0, 0, 0); this.clear(this.controls_.day); var tr = this.controls_.day.insertRow(-1); var counter = (firstday.getDay() + 7 - this.firstday_) % 7; for (var iii = 0; iii < counter; ++iii) this.addCell(tr); for (var day = 1; day <= this.days_in_month(month, year); ++day){ if (counter >= 7){ tr = this.controls_.day.insertRow(-1); counter = 0; } var td = this.addCell(tr, day); if (this.weekends_.include((this.firstday_ + counter) % 7)) Element.addClassName(td, "weekend"); ++counter; } for (var iii = counter; iii < 7; ++iii) this.addCell(tr); }, selectDay: function(day){ this.selectCell(Element.select(this.controls_.day, "td.day").find(function(cell){ return cell.value == day; })); }, selectCell: function(td){ if (this.selected_cell_ == td) return; if (this.selected_cell_){ Element.removeClassName(this.selected_cell_, "Selected"); this.selected_cell_ = null; } if (td){ Element.addClassName(td, "Selected"); this.selected_cell_ = td; } }, SetTabOrder: function(tabbase){ this.controls_.day.tabIndex = tabbase++; var setcurrent = Element.down(this.element, "button.SetCurrent") if (setcurrent) setcurrent.tabIndex = tabbase++; return tabbase; }, Value: function(){ if (this.selected_cell_ && Element.descendantOf(this.selected_cell_, this.controls_.day) && // typeof this.month_ != "undefined" && typeof this.year_ != "undefined") return new ADate(this.year_, this.month_, this.selected_cell_.value); else return new ADate(); }, finalize: function(){ new AEvent("FINALIZE", {}, this); }, updateMonth: function(month, year){ var day = -1; if (this.selected_cell_) day = this.selected_cell_.value; this.displayMonth(month, year); if (day != -1) this.selectDay(Math.min(day, this.days_in_month(month, year))); // this.onchange(); }, correctMonth: function(val){ if (val.month < 1){ --val.year; val.month += 12 }else if (val.month > 12){ ++val.year; val.month -= 12; } }, inc_month: function(){ if (typeof this.month_ == "undefined" || typeof this.year_ == "undefined") return; var val = {"month": this.month_ + 1, "year": this.year_}; this.correctMonth(val); this.updateMonth(val.month, val.year); }, dec_month: function(){ if (typeof this.month_ == "undefined" || typeof this.year_ == "undefined") return; var val = {"month": this.month_ - 1, "year": this.year_}; this.correctMonth(val); this.updateMonth(val.month, val.year); }, inc_year: function(){ if (typeof this.month_ == "undefined" || typeof this.year_ == "undefined") return; this.updateMonth(this.month_, this.year_ + 1); }, dec_year: function(){ if (typeof this.month_ == "undefined" || typeof this.year_ == "undefined") return; this.updateMonth(this.month_, this.year_ - 1); }, correctDay: function(val){ if (val.day < 1){ --val.month; this.correctMonth(val); val.day += this.days_in_month(val.month, val.year); }else if (val.day > this.days_in_month(val.month, val.year)){ val.day -= this.days_in_month(val.month, val.year); ++val.month; this.correctMonth(val); } }, inc_day: function(){ var val = this.Value(); if (val.IsIncorrect && val.IsIncorrect()) return; ++val.day; this.correctDay(val); this.SetValue(val); // this.onchange(); }, dec_day: function(){ var val = this.Value(); if (val.IsIncorrect && val.IsIncorrect()) return; --val.day; this.correctDay(val); this.SetValue(val); // this.onchange(); }, inc_week: function(){ var val = this.Value(); if (val.IsIncorrect && val.IsIncorrect()) return; val.day += 7; this.correctDay(val); this.SetValue(val); // this.onchange(); }, dec_week: function(){ var val = this.Value(); if (val.IsIncorrect && val.IsIncorrect()) return; val.day -= 7; this.correctDay(val); this.SetValue(val); // this.onchange(); }, keyboard: function(event){ if (!event) return; var keyCode = event.which || event.keyCode; switch (keyCode){ case Event.KEY_RIGHT: if (event.ctrlKey) this.inc_month(); else this.inc_day(); break; case Event.KEY_LEFT: if (event.ctrlKey) this.dec_month(); else this.dec_day(); break; case Event.KEY_UP: if (event.ctrlKey) this.dec_year(); else this.dec_week(); break; case Event.KEY_DOWN: if (event.ctrlKey) this.inc_year(); else this.inc_week(); break; case Event.KEY_RETURN: this.finalize(); break; default: return; } Event.stop(event); }, get_default_box_handlers: function(box){ if (!box) return []; else return [ [box, "mouseover", function(event){ var li = Event.findElement(event, "li"); if (li && li.parentNode == box) Element.addClassName(li, "hover"); }], [box, "mouseout", function(event){ var li = Event.findElement(event, "li"); if (li && li.parentNode == box) Element.removeClassName(li, "hover"); }] ]; }, align_and_show_box: function(box, button, rightside){ Element.setStyle(box, {"visibility": "hidden", "display": ""}); var params = {"setWidth": false, "setHeight": false, "offsetTop": button.offsetHeight}; if (rightside) params["offsetLeft"] = button.offsetWidth - box.offsetWidth; Element.clonePosition(box, button, params); Element.setStyle(box, {"visibility": ""}); if (!box.visible_ && box.handlers_) box.handlers_.each(function(args){ Event.observe.apply(null, args); }); box.visible_ = true; }, hide_box: function(box){ if (!box || !box.visible_) return; Element.setStyle(box, {"display": "none"}); if (box.handlers_) box.handlers_.each(function(args){ Event.stopObserving.apply(null, args); }); for (var li = box.firstChild; li; li = li.nextSibling) if (li.nodeType == Node.ELEMENT_NODE) Element.removeClassName(li, "hover"); box.visible_ = false; }, showbox_months: function(button){ if (!button) return; var box = this.controls_.month.next("ul"); if (!box) return; if (!box.handlers_){ box.handlers_ = this.get_default_box_handlers(box); box.handlers_.push([box, "mouseup", function(event){ if (typeof this.year_ == "undefined") return; var li = Event.findElement(event, "li"); if (!li || li.parentNode != box) return; this.updateMonth(parseInt(li.getAttribute("value"), 10), this.year_); }.bindAsEventListener(this)]); } this.align_and_show_box(box, button, Element.previous(button, "button")); var val = String(this.month_); for (var li = box.firstChild; li; li = li.nextSibling){ if (li.nodeType == Node.ELEMENT_NODE) Element[li.getAttribute("value") == val ? "addClassName" : "removeClassName"](li, "Selected"); } }, hidebox_month: function(){ this.hide_box(this.controls_.month.next("ul")); }, clear_timers: function(button){ if (!button) return; if (button.delayer_){ window.clearTimeout(button.delayer_); delete button.delayer_; } if (button.repeater_){ window.clearInterval(button.repeater_); delete button.repeater_; } }, bind_timer: function(button, func){ var mouseup = function(){ if (button.handlers_) button.handlers_.each(function(args){ Event.stopObserving.apply(null, args); }); this.clear_timers(button); }.bind(this); Event.observe(button, "mousedown", function(){ this.clear_timers(button); button.delayer_ = window.setTimeout(function(){ func(); button.repeater_ = window.setInterval(func, 60); }, 300); if (typeof button.handlers_ == "undefined") button.handlers_ = [ [document, "mouseup", mouseup], [button, "mouseup", mouseup], [button, "mouseout", mouseup] ]; button.handlers_.each(function(args){ Event.observe.apply(null, args); }); }.bind(this)); } }); Date.prototype.isLeapYear = function(){ var year = this.getFullYear(); return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; }