GUI Components JavaScript DHTML


The Boring DHTML Date Picker Test
   
    


/*
 * The Boring Date Picker, a DTML widget to select a date.
 * This code is released under GNU GPL, see file LICENSE for details.
 *
 * $Id: calendario.js,v 1.9 2003/09/24 16:15:24 neves Exp $
 */
// Initialize arrays.
var months = new Array("Janeiro", "Fevereiro", "Marco", "Abril", 
                       "Maio", "Junho", "Julho", "Agosto", 
                       "Setembro", "Outubro", "Novembro", "Dezembro");
var days = new Array("D", "S", "T", "Q", "Q", "S", "S");
/**
 * id = id of calendar element in the page (unique in page)
 * form = associated form of calendar element
 */
Calendar = function(id) {
    this.el = document.getElementById(id);
    this.displayDate = new Date();
    this.cid = id; //calendarId
    this.form = Calendar.getParentForm(this.el);
    this.form[id] = this; //now I can access the calendar from the form
    
    this.specialWeekDays = "06"; //weekend: saturday and sunday
    this.validInterval = [null, null];
};
//Static methods and utility functions
Calendar.getParentForm = function(el) {
    var form = el.parentNode;
    while (form.tagName != "FORM") {
        //no error checking
  form = form.parentNode;
    }
    return form;
}
Calendar.monthsSize = new Array(31, 28, 31, 30, 31, 30, 
                                31, 31, 30, 31, 30, 31); 
Calendar.daysInMonth = function(dt) {
    if (dt.getMonth() == 1) {
        var year = dt.getFullYear();
  return (((0 == year % 4) && (0 != (year % 100))) ||
                (0 == year % 400)) ? 29 : 28;
    }
    return Calendar.monthsSize[dt.getMonth()];
}
Calendar.addEvent = function(el, evname, func) {
    //Using this to add static Calendar functions as events
    if (!func) var func = Calendar["on" + evname];
    evname = evname.toLowerCase();
    if (el.attachEvent) { // IE
        el.attachEvent("on" + evname, func);
    } else if (el.addEventListener) { // Gecko / W3C
        el.addEventListener(evname, func, true);
    } else { // Opera (or old browsers)
        el["on" + evname] = func;
    }
};
Calendar.removeEvent = function(el, evname, func) {
    if (el.detachEvent) { // IE
        el.detachEvent("on" + evname, func);
    } else if (el.removeEventListener) { // Gecko / W3C
        el.removeEventListener(evname, func, true);
    } else { // Opera (or old browsers)
        el["on" + evname] = null;
    }
};
//Change element classes to be sensible to mouse over and click
//so it have a feeling of pressed button
Calendar.addMouseSensivity = function(el) {
    Calendar.addEvent(el, "MouseOver");
    Calendar.addEvent(el, "MouseOut");
    Calendar.addEvent(el, "MouseDown");
    Calendar.addEvent(el, "MouseUp");
}
Calendar.removeClass = function(el, className) {
    if (!(el && el.className)) {
        return;
    }
    var cls = el.className.split(" ");
    var ar = new Array();
    for (var i = cls.length; i > 0;) {
        if (cls[--i] != className) {
            ar[ar.length] = cls[i];
        }
    }
    el.className = ar.join(" ");
};
Calendar.addClass = function(el, className) {
    Calendar.removeClass(el, className);
    el.className += " " + className;
};
Calendar.hasClass = function(el, className) {
    var classes = el.className.split(" ");
    for (var i=0; i        if (classes[i] == className) {
            return true;
        }
    }
    return false;
};
//##end of static methods
Calendar.prototype.addHidden = function(name) {
    var el = document.createElement("input");
    el.type = "hidden";
    el.name = name;
    this.form.appendChild(el);
};
Calendar.prototype.setValidInterval = function(datesArray) {
    if (datesArray.length == 2) {
        this.validInterval = datesArray;
        if (this.validInterval[0] &&
            this.validInterval[0].valueOf() > this.displayDate.valueOf()) {
            this.displayDate = this.validInterval[0];
        } else if (this.validInterval[1] &&
            this.validInterval[1].valueOf() < this.displayDate.valueOf()) {
            this.displayDate = this.validInterval[1];
        }
    }
}
Calendar.prototype.isDisabled = function(dt) {
    if (this.validInterval) {
        if (this.validInterval[0] &&
            this.validInterval[0].getTime() > dt.getTime()) {
            return true;
        } else if (this.validInterval[1] &&
                   this.validInterval[1].getTime() < dt.getTime()) {
            return true;
        }
    }
    return false;            
};
Calendar.prototype.setDisplayDate = function(dt) {
    if (!this.isDisabled(dt)) {
        this.displayDate = dt;
    } else {
        if (this.validInterval[0] &&
            this.displayDate.valueOf() < this.validInterval[0]) {
            this.displayDate = this.validInterval[0];
        } else {
            //so we must have na upper valid date
            this.displayDate = this.validInterval[1];
        }
    }
    this.draw();
};
Calendar.prototype.setDate = function(dt) {
    this.displayDate = dt;
    this.selectedDate = dt;
    var formDay = this.el.id + "Day";
    var formMonth = this.el.id + "Month";
    var formYear = this.el.id + "Year";
    var formDate = this.el.id + "Date";
    if (this.form[formDate] == null) {
  this.addHidden(formDay);
  this.addHidden(formYear);
  this.addHidden(formMonth);
  this.addHidden(formDate);
    }
    var y = dt.getFullYear();
    var m = dt.getMonth(); 
    var d = dt.getDate();
    this.form[formDay].value = d;
    this.form[formMonth].value = m;
    this.form[formYear].value = y;
    var a = this.form[formDate];
    a.value = y + "-" 
    if (m<9) a.value += "0";
    a.value += (m+1) + "-" //month to [1,12]
    if (d<10) a.value += "0";
    a.value += d; //2003-09-07
    this.draw();

//returns last day from previous month
Calendar.previousMonth = function(dt) {
    var newMonth = dt.getMonth() - 1;
    var year = dt.getFullYear();
    if (newMonth < 0) {
       newMonth = 11;
       year--;
    }
    var previous = new Date(year, newMonth, 1);
    previous.setDate(Calendar.daysInMonth(previous));
    return previous;
}
Calendar.prototype.decreaseMonth = function() {
    this.setDisplayDate(Calendar.previousMonth(this.displayDate));
    this.draw();
}
//returns next day of next month
Calendar.nextMonth = function(dt) {
    var newMonth = dt.getMonth() + 1;
    var year = dt.getFullYear();
    if (newMonth % 12 != newMonth) {
       newMonth = newMonth % 12;
       year++;
    }
    return new Date(year, newMonth, 1);
}
        
Calendar.prototype.increaseMonth = function() {
    this.setDisplayDate(Calendar.nextMonth(this.displayDate));
    this.draw();
}
Calendar.prototype.selectDay = function(dayCell) {
    var day = parseInt(dayCell.innerHTML);
    if (!isNaN(day)) {
        this.setDate(new Date(this.displayDate.getFullYear(),
                              this.displayDate.getMonth(),
                              day));
    }
}
  
//Let's decorate the widget table with the classes we want
Calendar.prototype.decorate = function() {
    var tds = this.form.getElementsByTagName('TD');
    for (var i=0; i        //to allow access of calendar objects from events
        tds[i].datePicker = this;
        if (Calendar.hasClass(tds[i], 'day')  &&
            !Calendar.hasClass(tds[i], 'disabled')) {
            Calendar.addMouseSensivity(tds[i]);
            Calendar.addEvent(tds[i], 'Click');
            
        } else if (Calendar.hasClass(tds[i], 'button')) {
            Calendar.addMouseSensivity(tds[i]);
        }
    }
    
}
/** 
 * Selected weekdays columns will have a different color.
 * The default is to select the weekend (saturday and sunday).
 */
Calendar.prototype.setSpecialWeekDays = function(weekDaysArray) {
    if (weekDaysArray.length) {
        this.specialWeekDays = weekDaysArray.join(''); //strings have indexOf
    } else {
        this.specialWeekDays = '';
    }
}
Calendar.onMouseOver = function(ev) {
    if (!ev) var ev = window.event;
    var el = ev.target ? ev.target : ev.srcElement;
    Calendar.addClass(el, 'hilite');
}
Calendar.onMouseOut = function(ev) {
    if (!ev) var ev = window.event;
    var el = ev.target ? ev.target : ev.srcElement;
    
    Calendar.removeClass(el, 'hilite');
    Calendar.removeClass(el, 'active');
}
Calendar.onMouseDown = function(ev) {
    if (!ev) var ev = window.event;
    var el = ev.target ? ev.target : ev.srcElement;
    Calendar.removeClass(el, 'hilite');
    Calendar.addClass(el, 'active');
}
Calendar.onMouseUp = function(ev) {
    if (!ev) var ev = window.event;
    var el = ev.target ? ev.target : ev.srcElement;
    Calendar.removeClass(el, 'active');
    Calendar.addClass(el, 'hilite');
}
Calendar.onClick = function(ev) {
    if (!ev) var ev = window.event;
    var el = ev.target ? ev.target : ev.srcElement;
    Calendar.addClass(el, 'selected');
    el.datePicker.selectDay(el);
}
Calendar.prototype.getHeader = function () {
    var header = '    var lastDayMonthBefore = Calendar.previousMonth(this.displayDate);
    if (this.isDisabled(lastDayMonthBefore)) {
        header += '> ';
    } else { 
        header += ' onclick="this.datePicker.decreaseMonth();" class="button" title="Mes anterior">«';
    }
    header += '' +
      ' ' + 
      months[this.displayDate.getMonth()] + ' ' + 
      this.displayDate.getFullYear() + '     var firstDayNextMonth = Calendar.nextMonth(this.displayDate);
    if (this.isDisabled(firstDayNextMonth)) {
        header += '> ';
    } else {
        header += ' onclick="this.datePicker.increaseMonth();"  \
                  class="button" title="Proximo mes">»';
    }
    header += '';
    return header;        
}
/**
 * return weekdays header row
 */
Calendar.prototype.getWeekdays = function () {
    var weekDaysHeader = '';
    for (var i = 0; i < days.length; i++) {
        //Nonbreaking spaces to make it look better with coolest dhtml 
        //calendar css
  weekDaysHeader += '        if (this.specialWeekDays.indexOf(i) != -1) {
            weekDaysHeader += ' weekend'
        }
        weekDaysHeader += '">' + days[i] + '';
    }
    weekDaysHeader += '';
    return weekDaysHeader;
}
Calendar.prototype.getDaysGrid = function () {
    var firstWeekday = (new Date(this.displayDate.getFullYear(),
                                 this.displayDate.getMonth(),
                                 1)).getDay();
    
    var gridSize = 7 * 6; //7 days in week, always with 6 rows
    var grid = new Array(gridSize);
    for (var i=0; i        var day = i - firstWeekday + 1;
        if (day < 1 || 
            day > Calendar.daysInMonth(this.displayDate)) {
            grid[i] = null;
        } else {
            grid [i] = day;
        }
    }
    return grid;
}
Calendar.prototype.getDays = function () {
    var daysTable = '';
    var grid = this.getDaysGrid();
    var weekDay;
    
    for (var i=0; i        weekDay = i % 7;
        if (weekDay == 0) {
            daysTable += i!=0 ? '\n' : '';
            daysTable += '\n';
        }
        if (grid[i]) {
            daysTable += '            if (this.selectedDate &&
                this.selectedDate.getFullYear() == this.displayDate.getFullYear() &&
                this.selectedDate.getMonth() == this.displayDate.getMonth() &&
                this.selectedDate.getDate() == grid[i]) {
                daysTable += ' selected';
            }
            if (this.specialWeekDays.indexOf(weekDay) != -1) {
                daysTable += ' weekend';                
            }
            if (this.isDisabled(new Date(this.displayDate.getFullYear(),
                                         this.displayDate.getMonth(),
                                         grid[i]))) {
                    daysTable += ' disabled';                
                }
            daysTable += '">'+ grid[i] + '';
        } else {
            daysTable += ' ';
        }
    }
    //   alert(daysTable)
    return daysTable + ''
}
Calendar.prototype.draw = function() {
    this.el.innerHTML = '\n' +
                        this.getHeader() +
                        this.getWeekdays() +
                        "\n\n" +
                        this.getDays(); +
                        "\n";
    this.decorate();
}



/*
 * This must run with jsunit from cvs from after 15/9
 *
 *$Id: calendario_test.js,v 1.7 2003/09/24 16:15:24 neves Exp $
 */
function setUp() {
    c = new Calendar("datePicker");
    form = document.forms[0]
}
function testGetParentForm() {
    assertEquals(document.formulario, c.form);  
}
function testSetDate() {
    var y = 1977;
    var m = 11;
    var d = 10;
    c.setDate(new Date(y, m, d,12));
    assertEquals(y+"", form.datePickerYear.value);
    assertEquals(d+"", form.datePickerDay.value);
    assertEquals(m+"", form.datePickerMonth.value);
    assertEquals(y+"-"+(m+1)+"-"+d, form.datePickerDate.value);
}
function testGetHeader() {
    var month = 2;
    var year = 2001;
    c.setDate(new Date(year, month, 1));
    var h = c.getHeader();
    assertNotEquals("Header must have the year",
                    -1, 
                    h.toLowerCase().indexOf(year));
    assertNotEquals("Header must have the month",
                    -1, 
                    h.toLowerCase().indexOf(month));
}
function equalArrays(array1, array2) {
    if (array1.length != array2.length) {
        return false;
    }
    for (var i=0; i        if (array1[i] != array2[i]) {
            return false;
        }
    }
    return true;
}
function testGetDaysGrid() {
    var grid;
    c.setDate(new Date(2003, 8, 1));
    var sep2003 = new Array(null, 1, 2, 3, 4, 5, 6,
                            7, 8, 9, 10, 11, 12, 13,
                            14, 15, 16, 17, 18, 19, 20,
                            21, 22, 23, 24, 25, 26, 27,
                            28, 29, 30, null, null, null, null,
                            null, null, null, null, null, null, null);
    grid = c.getDaysGrid();
    assert("Equal values for grid of september 2003",
           equalArrays(sep2003, grid));
    //starts saturday
    c.setDate(new Date(2003, 10, 1));
    var nov2003 = new Array(null, null, null, null, null, null, 1,
                            2, 3, 4, 5, 6, 7, 8,
                            9, 10, 11, 12, 13, 14, 15,
                            16, 17, 18, 19, 20, 21, 22,
                            23, 24, 25, 26, 27, 28, 29,
                            30, null, null, null, null, null, null);
    grid = c.getDaysGrid();
    assert("Equal values for grid of november 2003",
           equalArrays(nov2003, grid));
    //just 4 rows
    c.setDate(new Date(2009, 1, 1));
    var feb2009 = new Array(1, 2, 3, 4, 5, 6, 7,
                            8, 9, 10, 11, 12, 13, 14,
                            15, 16, 17, 18, 19, 20, 21,
                            22, 23, 24, 25, 26, 27, 28,
                            null, null, null, null, null, null, null,
                            null, null, null, null, null, null, null);
    grid = c.getDaysGrid();
    assert("Equal values for grid offebruary 2003",
           equalArrays(feb2009, grid));
    //bissext
    c.setDate(new Date(2004, 1, 1));
    var feb2004 = new Array(1, 2, 3, 4, 5, 6, 7,
                            8, 9, 10, 11, 12, 13, 14,
                            15, 16, 17, 18, 19, 20, 21,
                            22, 23, 24, 25, 26, 27, 28,
                            29, null, null, null, null, null, null,
                            null, null, null, null, null, null, null);
    grid = c.getDaysGrid();
    assert("Equal values for grid of february 2004",
           equalArrays(feb2004, grid));
}
//aux func to test increase and decrease
function getTitleElement() {
    var el = form.getElementsByTagName('thead')[0];
    var childs =  el.getElementsByTagName('td');
    for (var i=0; i        if (childs[i].className == "title") {
            el = childs[i];
        }
    }
    return el;
}
function testIncreaseMonth() {
    var el;
    for (var i=0; i<11; i++) {
        c.setDate(new Date(2003, i ,1));
  c.increaseMonth();
        el = getTitleElement();
  assert("Increased Month name " + months[i+1] + 
               " isn't in header cell",
               el.innerHTML.indexOf(months[i+1])!=-1);
    }
    c.increaseMonth();
    el = getTitleElement();
    assert("Increased Month name " + months[0] + " isn't in header cell",
           el.innerHTML.indexOf(months[0])!=-1);
}
function testDecreaseMonth() {
    var el;
    for (var i=11; i>0; i--) {
        c.setDate(new Date(2003, i ,1));
  c.decreaseMonth();
        el = getTitleElement();
  assert("Decreased Month name " + months[i-1] + 
               " isn't in header cell",
               el.innerHTML.indexOf(months[i-1])!=-1);
    }
    c.decreaseMonth();
    el = getTitleElement();
    assert("Decreased Month name " + months[11] + " isn't in header cell",
           el.innerHTML.indexOf(months[11])!=-1);
}
function testHasClass() {
    var el = document.createElement('p');
    el.className = "abc";
    assert(Calendar.hasClass(el, "abc"));
    el.className = "abcde";
    assert(!Calendar.hasClass(el, "abc"));
    el.className = "abc cde";
    assert(Calendar.hasClass(el, "abc"));
    el.className = "cde abc";
    assert(Calendar.hasClass(el, "abc"));
    el.className = "aaa abc cde";
    assert(Calendar.hasClass(el, "abc"));
}
function testAddClass() {
  var el = document.createElement('p');
  Calendar.addClass(el, "abc");
  assert(Calendar.hasClass(el, "abc"));
  Calendar.addClass(el, "abc");
  assert(Calendar.hasClass(el, "abc"));
  Calendar.addClass(el, "cde");
  assert(Calendar.hasClass(el, "abc"));
  assert(Calendar.hasClass(el, "cde"));
}
function testRemoveClass() {
    var el = document.createElement('p');
    el.className = "abc";
    Calendar.removeClass(el, "abc");
    assert(!Calendar.hasClass(el, "abc"));
    Calendar.removeClass(el, "abc");
    assert(!Calendar.hasClass(el, "abc"));
    el.className = "abc cde eft";
    Calendar.removeClass(el, "cde");
    assert(Calendar.hasClass(el, "abc"));
    assert(Calendar.hasClass(el, "eft"));
    assert(!Calendar.hasClass(el, "cde"));
}
function testSelectDay() {
    var y = 2003;
    var m = 9;
    var d = 15;
    c.setDate(new Date(y, m, d));
    var days = form.getElementsByTagName("TBODY");
    days = form.getElementsByTagName("TD");
    for (var i=0; i        if (parseInt(days[i].innerHTML) == d) {
            assert(Calendar.hasClass(days[i],'selected'));
        } else {
            assert(!Calendar.hasClass(days[i],'selected'));
        }
    }
}
function testInvalidDates() {
    c.setDisplayDate(new Date(2003, 5, 22));
    var dateMin = new Date(2003, 5, 02);
    var dateMax = new Date(2003, 5, 29);
    var dateMiddle = new Date(2003, 5, 15);
    c.setValidInterval([dateMin, 
                        dateMax]);
    assert("Less than min must be disabled",
           c.isDisabled(new Date(2003, 5, 1)));
    assert("Greater than max must be disabled",
           c.isDisabled(new Date(2003, 5, 30)));
    assert("Date in middle must be valid",
           !c.isDisabled(dateMiddle));
    assert("Min interval date must be enabled",
           !c.isDisabled(dateMin));
    assert("Max interval date must be enabled",
           !c.isDisabled(dateMax));
    c.setDisplayDate(new Date(2003, 5, 1));
    assert("Display date can't be set out of valid interval",
           c.displayDate.valueOf() >= dateMin.valueOf());
    c.setValidInterval([dateMiddle, 
                        dateMax]);
    assert("Display date can't be set out of valid interval",
           c.displayDate.valueOf() >= dateMiddle.valueOf());
    
    //Days before limit are disabled
    c.setValidInterval([dateMin, 
                        dateMax]);
    var days = form.getElementsByTagName("TBODY")[1].getElementsByTagName("TD");
    
    for (var i=0; i        var cellDay = parseInt(days[i].innerHTML);
        if (!isNaN(cellDay) &&
            cellDay >= dateMin.getDate() &&
            cellDay <= dateMax.getDate()) {
            assert("Day " + cellDay + " can't be disabled",
                   !Calendar.hasClass(days[i], 'disabled'));
        } else {
            assert("Day " + cellDay + " in pos " + i + " must be disabled",
                   Calendar.hasClass(days[i], 'disabled'));
        }
    }
}
function testDisabledArrows() {
    var dateMin = new Date(2003, 5, 02);
    var dateMax = new Date(2003, 6, 29);
    c.setValidInterval([dateMin, dateMax]);
    c.setDisplayDate(dateMin);
    c.draw();
    var header = form.getElementsByTagName("THEAD")[0].getElementsByTagName("TD");
    var leftArrow = header[0];
    var rightArrow = header[2];
    assert("Left arrow can't be active if month before just has invalid dates",
           !Calendar.hasClass(leftArrow, 'button'));
    assert("Right arrow must be active if month after has any valid date",
           Calendar.hasClass(rightArrow, 'button'));
    c.setDisplayDate(dateMax);
    c.draw();
    header = form.getElementsByTagName("THEAD")[0].getElementsByTagName("TD");
    leftArrow = header[0];
    rightArrow = header[2];
    assert("Left arrow must be active if month before has any valid date",
           Calendar.hasClass(leftArrow, 'button'));
    assert("Right arrow can't be active if month after just has invalid dates",
           !Calendar.hasClass(rightArrow, 'button'));
}



/* The main calendar widget.  DIV containing a table. */
.calendar {
  position: relative;
  display: none;
  border-top: 2px solid #fff;
  border-right: 2px solid #000;
  border-bottom: 2px solid #000;
  border-left: 2px solid #fff;
  font-size: 11px;
  color: #000;
  cursor: default;
  background: #d4d0c8;
  font-family: tahoma,verdana,sans-serif;
}
.calendar table {
  border-top: 1px solid #000;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  border-left: 1px solid #000;
  font-size: 11px;
  color: #000;
  cursor: default;
  background: #d4d0c8;
  font-family: tahoma,verdana,sans-serif;
}
/* Header part -- contains navigation buttons and day names. */
.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */
  text-align: center;
  padding: 1px;
  border-top: 1px solid #fff;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  border-left: 1px solid #fff;
}
.calendar thead .title { /* This holds the current "month, year" */
  font-weight: bold;
  padding: 1px;
  border: 1px solid #000;
  background: #848078;
  color: #fff;
  text-align: center;
}
.calendar thead .headrow { /* Row  containing navigation buttons */
}
.calendar thead .daynames { /* Row  containing the day names */
}
.calendar thead .name { /* Cells  containing the day names */
  border-bottom: 1px solid #000;
  padding: 2px;
  text-align: center;
  background: #f4f0e8;
}
.calendar thead .weekend { /* How a weekend day name shows in header */
  color: #f00;
}
.calendar thead .hilite { /* How do the buttons in header appear when hover */
  border-top: 2px solid #fff;
  border-right: 2px solid #000;
  border-bottom: 2px solid #000;
  border-left: 2px solid #fff;
  padding: 0px;
  background: #e4e0d8;
}
.calendar thead .active { /* Active (pressed) buttons in header */
  padding: 2px 0px 0px 2px;
  border-top: 1px solid #000;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  border-left: 1px solid #000;
  background: #c4c0b8;
}
/* The body part -- contains all the days in month. */
.calendar tbody .day { /* Cells  containing month days dates */
  text-align: right;
  padding: 2px 4px 2px 2px;
}
.calendar table .wn {
  padding: 2px 3px 2px 2px;
  border-right: 1px solid #000;
  background: #f4f0e8;
}
.calendar tbody .rowhilite td {
  background: #e4e0d8;
}
.calendar tbody .rowhilite td.wn {
  background: #d4d0c8;
}
.calendar tbody td.hilite { /* Hovered cells  */
  padding: 1px 3px 1px 1px;
  border-top: 1px solid #fff;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  border-left: 1px solid #fff;
}
.calendar tbody td.active { /* Active (pressed) cells  */
  padding: 2px 2px 0px 2px;
  border-top: 1px solid #000;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  border-left: 1px solid #000;
}
.calendar tbody td.selected { /* Cell showing selected date */
  font-weight: bold;
  border-top: 1px solid #000;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  border-left: 1px solid #000;
  padding: 2px 2px 0px 2px;
  background: #e4e0d8;
}
.calendar tbody td.weekend { /* Cells showing weekend days */
  color: #f00;
}
.calendar tbody td.today { /* Cell showing today date */
  font-weight: bold;
  color: #00f;
}
.calendar tbody .disabled { color: #999; }
.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */
  visibility: hidden;
}
.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */
  display: none;
}
/* The footer part -- status bar and "Close" button */
.calendar tfoot .footrow { /* The  in footer (only one right now) */
}
.calendar tfoot .ttip { /* Tooltip (status bar) cell  */
  background: #f4f0e8;
  padding: 1px;
  border: 1px solid #000;
  background: #848078;
  color: #fff;
  text-align: center;
}
.calendar tfoot .hilite { /* Hover style for buttons in footer */
  border-top: 1px solid #fff;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  border-left: 1px solid #fff;
  padding: 1px;
  background: #e4e0d8;
}
.calendar tfoot .active { /* Active (pressed) style for buttons in footer */
  padding: 2px 0px 0px 2px;
  border-top: 1px solid #000;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  border-left: 1px solid #000;
}
/* Combo boxes (menus that display months/years for direct selection) */
.combo {
  position: absolute;
  display: none;
  width: 4em;
  top: 0px;
  left: 0px;
  cursor: default;
  border-top: 1px solid #fff;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  border-left: 1px solid #fff;
  background: #e4e0d8;
  font-size: smaller;
  padding: 1px;
}
.combo .label {
  text-align: center;
  padding: 1px;
}
.combo .active {
  background: #c4c0b8;
  padding: 0px;
  border-top: 1px solid #000;
  border-right: 1px solid #fff;
  border-bottom: 1px solid #fff;
  border-left: 1px solid #000;
}
.combo .hilite {
  background: #048;
  color: #fea;
}


  
    

The Boring DHTML Date Picker Widget


    

Try it


    

Below is the sample of the Boring Date Picker Widget with valid dates
      from "2003-08-15" to "2005-11-25". Select a date.
        


          

            title="Mes anterior">--
     Agosto 2005 
            title="Proximo mes">--


    D
    S
    T
    Q
    Q
    S
    S


 123456

78910111213

14151617181920

21222324252627

28293031