/** * * inspired by Simon Willison, this is a date object that accepts three types of * input * 1) Simon's magic date * 2) separate inputs for month, day, year * 3) a pop-up calendar, hopefully from egroupware * * @param swd "FORM INPUT" the free text magic date input * * @param puc string id of the html element that is the trigger for our popup clendar * * @param err "HTML SPAN" where to report errors * * @param separates ARRAY an array with three inputs, year, month day, in that order, keyed by the leters Y, m, d * **/ function willisonDate (swd, puc, separates, err){ this.freedate = document.getElementById(swd); this.popper = document.getElementById(puc); this.yearfinal = document.getElementById(separates["Y"]); this.monthfinal = document.getElementById(separates["m"]); this.dayfinal = document.getElementById(separates["d"]); this.errorreport = document.getElementById(err); // add an event listener to the freedate // to run parseDateString on change // {{{ our popup calendar this.pucal = Calendar.setup( { inputField : swd, // ID of the input field ifFormat : "%m/%d/%Y", // the date format button : puc, // ID of the button /* displayArea : err, */ yearInput : separates["Y"], monthInput : separates["m"], dayInput : separates["d"], separateInputs : true } ); // }}} // straight from SW this.monthNames = "January February March April May June July August September October November December".split(" "); this.weekdayNames = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "); this.numberWords = "zero one two three four five six seven eight nine ten eleven twelve".split(" "); // {{{ function parseMonth /** * **/ this.parseMonth = function (month) { var matches = this.monthNames.filter(function(item) { return new RegExp("^" + month, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid month string"); } if (matches.length > 1) { throw new Error("Ambiguous month"); } return this.monthNames.indexOf(matches[0]); } // }}} // {{{ function parseWeekday /* Same as parseMonth but for days of the week */ this.parseWeekday = function (weekday) { var matches = this.weekdayNames.filter(function(item) { return new RegExp("^" + weekday, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid day string"); } if (matches.length > 1) { throw new Error("Ambiguous weekday"); } return this.weekdayNames.indexOf(matches[0]); } // }}} // {{{ function parseNumberWord this.parseNumberWord = function (num) { var matches = this.numberWords.filter(function(item) { return new RegExp("^" + num, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid number word"); } if (matches.length > 1) { throw new Error("Ambiguous number"); } return this.numberWords.indexOf(matches[0]); } // }}} // {{{ dateParsePatterns this.dateParsePatterns = [ // Today { re: /^tod/i, handler: function() { return new Date(); } }, // Tomorrow { re: /^tom/i, handler: function() { var d = new Date(); d.setDate(d.getDate() + 1); return d; } }, // Yesterday { re: /^yes/i, handler: function() { var d = new Date(); d.setDate(d.getDate() - 1); return d; } }, // 4th { re: /^(\d{1,2})(st|nd|rd|th)?$/i, handler: function(bits) { var d = new Date(); d.setDate(parseInt(bits[1], 10)); return d; } }, // 4th Jan { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+)$/i, handler: function(bits, caller) { var d = new Date(); d.setDate(parseInt(bits[1], 10)); d.setMonth(caller.parseMonth(bits[2])); return d; } }, // 4th Jan 2003 { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+),? (\d{4})$/i, handler: function(bits, caller) { var d = new Date(); d.setDate(parseInt(bits[1], 10)); d.setMonth(caller.parseMonth(bits[2])); d.setYear(bits[3]); return d; } }, // Jan 4th { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i, handler: function(bits, caller) { var d = new Date(); d.setDate(parseInt(bits[2], 10)); d.setMonth(caller.parseMonth(bits[1])); return d; } }, // Jan 4th 2003 { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i, handler: function(bits, caller) { var d = new Date(); d.setDate(parseInt(bits[2], 10)); d.setMonth(caller.parseMonth(bits[1])); d.setYear(bits[3]); return d; } }, // xxx/## weeks ago { re: /^(\w+) weeks?\s*ago$/i, handler: function(bits, caller) { var d = new Date(); if(bits[1]==="a"){ bits[1] = "one"; } if(isNaN(parseInt(bits[1]))) { d.setDate(d.getDate()-(parseInt(caller.parseNumberWord(bits[1]), 10)*7)); } else { d.setDate(d.getDate()-(parseInt(bits[1], 10)*7)); } return d; } }, // xxx/## months ago { re: /^(\w+) months?\s*ago$/i, handler: function(bits, caller) { var d = new Date(); if(bits[1]==="a"){ bits[1] = "one"; } if(isNaN(parseInt(bits[1]))) { d.setMonth(d.getMonth()-parseInt(caller.parseNumberWord(bits[1]), 10)); } else { d.setMonth(d.getMonth()-parseInt(bits[1], 10)); } return d; } }, // in xxx/## weeks from tomorrow|today|yesterday { re: /^(in)?\s*(\w+) weeks?\s*from\s*(tomorrow|today|yesterday)$/i, handler: function(bits, caller) { var d = new Date(); var day = d.getDay(); var dayoffset = 0; if(bits[2]==="a"){ bits[2] = "one"; } switch(bits[bits.length-1]){ case "tomorrow" : dayoffset = 1; break; case "yesterday" : dayoffset = -1; break; default : dayoffset = 0; } if(isNaN(parseInt(bits[2]))) { d.setDate(d.getDate()+parseInt(caller.parseNumberWord(bits[2]), 10)*7 + dayoffset); } else { d.setDate(d.getDate()+parseInt(bits[2], 10)*7 + dayoffset); } return d; } }, // in xxx/## weeks { re: /^(in)?\s*(\w+) weeks?\s*(from (last)?\s*(\w+))?$/i, handler: function(bits, caller) { var d = new Date(); var day = d.getDay(); var dayoffset = 0; if(bits[2]==="a"){ bits[2] = "one"; } // we will also try to handle "from DAY" to guess // when they want to start from try{ if(bits.length && caller.parseWeekday(bits[bits.length-1])!==null){ // then maybe they named a date var startday = caller.parseWeekday(bits[bits.length-1]); if(startday -1) { message = 'Invalid date string'; } this.errorreport.firstChild.innerHTML = message; this.errorreport.className = 'error'; } } addObjectEventFunction(this.freedate, "change", this, "magicDate", true); this.freedate.addEventListener("focus", function(e) {e.target.select(); }, true); // }}} } // end of willisonDate declaration