| [21] | 1 | /*!! |
|---|
| 2 | Epoch DHTML JavaScript Calendar - Version 2.0.2 |
|---|
| 3 | English Edition |
|---|
| 4 | Primary JavaScript File |
|---|
| 5 | (c) 2006-2007 MeanFreePath |
|---|
| 6 | Free for NON-COMMERCIAL use - see website for details and updates |
|---|
| 7 | http://www.meanfreepath.com/javascript_calendar/index.html |
|---|
| 8 | !!*/ |
|---|
| 9 | |
|---|
| 10 | /** |
|---|
| 11 | * The main Epoch class. All publicly-accessible methods and properties are called from this class |
|---|
| 12 | */ |
|---|
| 13 | function Epoch(name,mode,targetelement,multiselect, m_afterHide, m_afterHideParam, m_dateformat) { |
|---|
| 14 | var self = this; //workaround due to varying definitions of "this" in variable scopes. see http://www.meanfreepath.com/support/epoch/epoch.html#self for details |
|---|
| 15 | //DEFINE PRIVATE METHODS |
|---|
| 16 | //----------------------------------------------------------------------------- |
|---|
| 17 | /** |
|---|
| 18 | * Declares and initializes the calendar variables. All the variables here can be safely changed |
|---|
| 19 | * (within reason ;) by the developer |
|---|
| 20 | */ |
|---|
| 21 | function calConfig() { |
|---|
| 22 | self.versionNumber = '2.0.2'; |
|---|
| 23 | self.displayYearInitial = self.curDate.getFullYear(); //the initial year to display on load |
|---|
| 24 | self.displayMonthInitial = self.curDate.getMonth(); //the initial month to display on load (0-11) |
|---|
| 25 | self.displayYear = self.displayYearInitial; |
|---|
| 26 | self.displayMonth = self.displayMonthInitial; |
|---|
| 27 | |
|---|
| 28 | var d = new Date(); |
|---|
| 29 | var curr_year = d.getFullYear(); |
|---|
| 30 | self.minDate = new Date(curr_year-5,0,1); |
|---|
| 31 | // self.maxDate = new Date(2012,11,31); |
|---|
| 32 | self.maxDate = new Date(parseInt(curr_year)+parseInt(10),11,31); |
|---|
| 33 | |
|---|
| 34 | self.startDay = 0; // the day the week will 'start' on: 0(Sun) to 6(Sat) |
|---|
| 35 | self.showWeeks = true; //whether the week numbers will be shown |
|---|
| 36 | self.selCurMonthOnly = true; //allow user to only select dates in the currently displayed month |
|---|
| 37 | } |
|---|
| 38 | //----------------------------------------------------------------------------- |
|---|
| 39 | /** |
|---|
| 40 | * All language settings for Epoch are made here. |
|---|
| 41 | * Check Date.dateFormat() for the Date object's language settings |
|---|
| 42 | */ |
|---|
| 43 | function setLang() { |
|---|
| 44 | self.daylist = new Array('S','M','T','W','T','F','S','S','M','T','W','T','F','S'); |
|---|
| 45 | self.months_sh = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); |
|---|
| 46 | self.monthup_title = 'Go to the next month'; |
|---|
| 47 | self.monthdn_title = 'Go to the previous month'; |
|---|
| 48 | self.clearbtn_caption = 'Clear'; |
|---|
| 49 | self.clearbtn_title = 'Clears any dates selected on the calendar'; |
|---|
| 50 | self.maxrange_caption = 'This is the maximum range'; |
|---|
| 51 | self.closebtn_caption = 'Close'; |
|---|
| 52 | self.closebtn_title = 'Close the calendar'; |
|---|
| 53 | } |
|---|
| 54 | //----------------------------------------------------------------------------- |
|---|
| 55 | /** |
|---|
| 56 | * Initializes the standard Gregorian Calendar parameters |
|---|
| 57 | */ |
|---|
| 58 | function setDays() { |
|---|
| 59 | self.daynames = new Array(); |
|---|
| 60 | var j=0; |
|---|
| 61 | for(var i=self.startDay;i<self.startDay + 7;i++) { |
|---|
| 62 | self.daynames[j++] = self.daylist[i]; |
|---|
| 63 | } |
|---|
| 64 | self.monthDayCount = new Array(31,((self.curDate.getFullYear() - 2000) % 4 ? 28 : 29),31,30,31,30,31,31,30,31,30,31); |
|---|
| 65 | } |
|---|
| 66 | //----------------------------------------------------------------------------- |
|---|
| 67 | /** |
|---|
| 68 | * Creates the full DOM implementation of the calendar |
|---|
| 69 | */ |
|---|
| 70 | function createCalendar() { |
|---|
| 71 | var tbody, tr, td; |
|---|
| 72 | self.calendar = document.createElement('table'); |
|---|
| 73 | self.calendar.setAttribute('id',self.name+'_calendar'); |
|---|
| 74 | setClass(self.calendar,'calendar'); |
|---|
| 75 | self.calendar.style.display = 'none'; //default to invisible |
|---|
| 76 | //to prevent IE from selecting text when clicking on the calendar |
|---|
| 77 | addEventHandler(self.calendar,'selectstart', function() {return false;}); |
|---|
| 78 | addEventHandler(self.calendar,'drag', function() {return false;}); |
|---|
| 79 | tbody = document.createElement('tbody'); |
|---|
| 80 | |
|---|
| 81 | //create the Main Calendar Heading |
|---|
| 82 | tr = document.createElement('tr'); |
|---|
| 83 | td = document.createElement('td'); |
|---|
| 84 | td.appendChild(createMainHeading()); |
|---|
| 85 | tr.appendChild(td); |
|---|
| 86 | tbody.appendChild(tr); |
|---|
| 87 | |
|---|
| 88 | //create the calendar Day Heading & the calendar Day Cells |
|---|
| 89 | tr = document.createElement('tr'); |
|---|
| 90 | td = document.createElement('td'); |
|---|
| 91 | self.calendar.celltable = document.createElement('table'); |
|---|
| 92 | setClass(self.calendar.celltable,'cells'); |
|---|
| 93 | self.calendar.celltable.appendChild(createDayHeading()); |
|---|
| 94 | self.calendar.celltable.appendChild(createCalCells()); |
|---|
| 95 | td.appendChild(self.calendar.celltable); |
|---|
| 96 | tr.appendChild(td); |
|---|
| 97 | tbody.appendChild(tr); |
|---|
| 98 | |
|---|
| 99 | //create the calendar footer |
|---|
| 100 | tr = document.createElement('tr'); |
|---|
| 101 | td = document.createElement('td'); |
|---|
| 102 | td.appendChild(createFooter()); |
|---|
| 103 | tr.appendChild(td); |
|---|
| 104 | tbody.appendChild(tr); |
|---|
| 105 | |
|---|
| 106 | //add the tbody element to the main calendar table |
|---|
| 107 | self.calendar.appendChild(tbody); |
|---|
| 108 | |
|---|
| 109 | //and add the onmouseover events to the calendar table |
|---|
| 110 | addEventHandler(self.calendar,'mouseover',cal_onmouseover); |
|---|
| 111 | addEventHandler(self.calendar,'mouseout',cal_onmouseout); |
|---|
| 112 | } |
|---|
| 113 | //----------------------------------------------------------------------------- |
|---|
| 114 | /** |
|---|
| 115 | * Creates the primary calendar heading, with months & years |
|---|
| 116 | */ |
|---|
| 117 | function createMainHeading() { |
|---|
| 118 | //create the containing <div> element |
|---|
| 119 | var container = document.createElement('div'); |
|---|
| 120 | setClass(container,'mainheading'); |
|---|
| 121 | //create the child elements and other variables |
|---|
| 122 | self.monthSelect = document.createElement('select'); |
|---|
| 123 | self.yearSelect = document.createElement('select'); |
|---|
| 124 | var monthDn = document.createElement('input'), monthUp = document.createElement('input'); |
|---|
| 125 | var opt, i; |
|---|
| 126 | //fill the month select box |
|---|
| 127 | for(i=0;i<12;i++) { |
|---|
| 128 | opt = document.createElement('option'); |
|---|
| 129 | opt.setAttribute('value',i); |
|---|
| 130 | if(self.displayMonth == i) { |
|---|
| 131 | opt.setAttribute('selected','selected'); |
|---|
| 132 | } |
|---|
| 133 | opt.appendChild(document.createTextNode(self.months_sh[i])); |
|---|
| 134 | self.monthSelect.appendChild(opt); |
|---|
| 135 | } |
|---|
| 136 | //and fill the year select box |
|---|
| 137 | var yrMax = self.maxDate.getFullYear(), yrMin = self.minDate.getFullYear(); |
|---|
| 138 | for(i=yrMin;i<=yrMax;i++) { |
|---|
| 139 | opt = document.createElement('option'); |
|---|
| 140 | opt.setAttribute('value',i); |
|---|
| 141 | if(self.displayYear == i) { |
|---|
| 142 | opt.setAttribute('selected','selected'); |
|---|
| 143 | } |
|---|
| 144 | opt.appendChild(document.createTextNode(i)); |
|---|
| 145 | self.yearSelect.appendChild(opt); |
|---|
| 146 | } |
|---|
| 147 | //add the appropriate children for the month buttons |
|---|
| 148 | monthUp.setAttribute('type','button'); |
|---|
| 149 | monthUp.setAttribute('value','>'); |
|---|
| 150 | monthUp.setAttribute('title',self.monthup_title); |
|---|
| 151 | monthDn.setAttribute('type','button'); |
|---|
| 152 | monthDn.setAttribute('value','<'); |
|---|
| 153 | monthDn.setAttribute('title',self.monthdn_title); |
|---|
| 154 | self.monthSelect.owner = self.yearSelect.owner = monthUp.owner = monthDn.owner = self; //hack to allow us to access self calendar in the events (<fix>??) |
|---|
| 155 | |
|---|
| 156 | //assign the event handlers for the controls |
|---|
| 157 | function selectonchange() { |
|---|
| 158 | if(self.goToMonth(self.yearSelect.value,self.monthSelect.value)) { |
|---|
| 159 | self.displayMonth = self.monthSelect.value; |
|---|
| 160 | self.displayYear = self.yearSelect.value; |
|---|
| 161 | } |
|---|
| 162 | else { |
|---|
| 163 | self.monthSelect.value = self.displayMonth; |
|---|
| 164 | self.yearSelect.value = self.displayYear; |
|---|
| 165 | } |
|---|
| 166 | } |
|---|
| 167 | addEventHandler(monthUp,'click',function(){self.nextMonth();}); |
|---|
| 168 | addEventHandler(monthDn,'click',function(){self.prevMonth();}); |
|---|
| 169 | addEventHandler(self.monthSelect,'change',selectonchange); |
|---|
| 170 | addEventHandler(self.yearSelect,'change',selectonchange); |
|---|
| 171 | |
|---|
| 172 | //and finally add the elements to the containing div |
|---|
| 173 | container.appendChild(monthDn); |
|---|
| 174 | container.appendChild(self.monthSelect); |
|---|
| 175 | container.appendChild(self.yearSelect); |
|---|
| 176 | container.appendChild(monthUp); |
|---|
| 177 | return container; |
|---|
| 178 | } |
|---|
| 179 | //----------------------------------------------------------------------------- |
|---|
| 180 | /** |
|---|
| 181 | * Creates the footer of the calendar - goes under the calendar cells |
|---|
| 182 | */ |
|---|
| 183 | function createFooter() { |
|---|
| 184 | var container = document.createElement('div'); |
|---|
| 185 | var clearSelected = document.createElement('input'); |
|---|
| 186 | clearSelected.setAttribute('type','button'); |
|---|
| 187 | clearSelected.setAttribute('value',self.clearbtn_caption); |
|---|
| 188 | clearSelected.setAttribute('title',self.clearbtn_title); |
|---|
| 189 | clearSelected.owner = self; |
|---|
| 190 | addEventHandler(clearSelected,'click',function() {self.resetSelections(false);}); |
|---|
| 191 | container.appendChild(clearSelected); |
|---|
| 192 | if(self.mode == 'popup') { |
|---|
| 193 | var closeBtn = document.createElement('input'); |
|---|
| 194 | closeBtn.setAttribute('type','button'); |
|---|
| 195 | closeBtn.setAttribute('value',self.closebtn_caption); |
|---|
| 196 | closeBtn.setAttribute('title',self.closebtn_title); |
|---|
| 197 | addEventHandler(closeBtn,'click',function(){self.hide();}); |
|---|
| 198 | setClass(closeBtn,'closeBtn'); |
|---|
| 199 | container.appendChild(closeBtn); |
|---|
| 200 | } |
|---|
| 201 | return container; |
|---|
| 202 | } |
|---|
| 203 | //----------------------------------------------------------------------------- |
|---|
| 204 | /** |
|---|
| 205 | * Creates the heading containing the day names |
|---|
| 206 | */ |
|---|
| 207 | function createDayHeading() { |
|---|
| 208 | //create the table element |
|---|
| 209 | self.calHeading = document.createElement('thead'); |
|---|
| 210 | setClass(self.calHeading,'caldayheading'); |
|---|
| 211 | var tr = document.createElement('tr'), th; |
|---|
| 212 | self.cols = new Array(false,false,false,false,false,false,false); |
|---|
| 213 | |
|---|
| 214 | //if we're showing the week headings, create an empty <td> for filler |
|---|
| 215 | if(self.showWeeks) { |
|---|
| 216 | th = document.createElement('th'); |
|---|
| 217 | setClass(th,'wkhead'); |
|---|
| 218 | tr.appendChild(th); |
|---|
| 219 | } |
|---|
| 220 | //populate the day titles |
|---|
| 221 | for(var dow=0;dow<7;dow++) { |
|---|
| 222 | th = document.createElement('th'); |
|---|
| 223 | th.appendChild(document.createTextNode(self.daynames[dow])); |
|---|
| 224 | if(self.selectMultiple) { //if selectMultiple is true, assign the cell a CalHeading Object to handle all events |
|---|
| 225 | th.headObj = new CalHeading(self,th,(dow + self.startDay < 7 ? dow + self.startDay : dow + self.startDay - 7)); |
|---|
| 226 | } |
|---|
| 227 | tr.appendChild(th); |
|---|
| 228 | } |
|---|
| 229 | self.calHeading.appendChild(tr); |
|---|
| 230 | return self.calHeading; |
|---|
| 231 | } |
|---|
| 232 | //----------------------------------------------------------------------------- |
|---|
| 233 | /** |
|---|
| 234 | * Creates the table containing the calendar day cells |
|---|
| 235 | */ |
|---|
| 236 | function createCalCells() { |
|---|
| 237 | self.rows = new Array(false,false,false,false,false,false); |
|---|
| 238 | self.cells = new Array(); |
|---|
| 239 | var row = -1, totalCells = (self.showWeeks ? 48 : 42); |
|---|
| 240 | var beginDate = new Date(self.displayYear,self.displayMonth,1); |
|---|
| 241 | var endDate = new Date(self.displayYear,self.displayMonth,self.monthDayCount[self.displayMonth]); |
|---|
| 242 | var sdt = new Date(beginDate); |
|---|
| 243 | sdt.setDate(sdt.getDate() + (self.startDay - beginDate.getDay()) - (self.startDay - beginDate.getDay() > 0 ? 7 : 0) ); |
|---|
| 244 | //create the table element to hold the cells |
|---|
| 245 | self.calCells = document.createElement('tbody'); |
|---|
| 246 | var tr,td; |
|---|
| 247 | var cellIdx = 0, cell, week, dayval; |
|---|
| 248 | |
|---|
| 249 | for(var i=0;i<totalCells;i++) { |
|---|
| 250 | if(self.showWeeks) { //if we are showing the week headings |
|---|
| 251 | if(i % 8 == 0) { |
|---|
| 252 | row++; |
|---|
| 253 | week = sdt.getWeek(self.startDay); |
|---|
| 254 | tr = document.createElement('tr'); |
|---|
| 255 | td = document.createElement('td'); |
|---|
| 256 | if(self.selectMultiple) { //if selectMultiple is enabled, create the associated weekObj objects |
|---|
| 257 | td.weekObj = new WeekHeading(self,td,week,row) |
|---|
| 258 | } |
|---|
| 259 | else {//otherwise just set the class of the td for consistent look |
|---|
| 260 | setClass(td,'wkhead'); |
|---|
| 261 | } |
|---|
| 262 | td.appendChild(document.createTextNode(week)); |
|---|
| 263 | tr.appendChild(td); |
|---|
| 264 | i++; |
|---|
| 265 | } |
|---|
| 266 | } |
|---|
| 267 | else if(i % 7 == 0) { //otherwise, new row every 7 cells |
|---|
| 268 | row++; |
|---|
| 269 | week = sdt.getWeek(self.startDay); |
|---|
| 270 | tr = document.createElement('tr'); |
|---|
| 271 | } |
|---|
| 272 | //create the day cells |
|---|
| 273 | dayval = sdt.getDate(); |
|---|
| 274 | td = document.createElement('td'); |
|---|
| 275 | td.appendChild(document.createTextNode(dayval)); |
|---|
| 276 | cell = new CalCell(self,td,sdt,row,week);//,'normal',sdt.getTime() >= self.minDate.getTime() && sdt.getTime() <= self.maxDate.getTime()); |
|---|
| 277 | self.cells[cellIdx] = cell; |
|---|
| 278 | td.cellObj = cell; |
|---|
| 279 | tr.appendChild(td); |
|---|
| 280 | self.calCells.appendChild(tr); |
|---|
| 281 | self.reDraw(cellIdx++); //and paint the cell according to its properties |
|---|
| 282 | sdt.setDate(dayval + 1); //increment the date |
|---|
| 283 | } |
|---|
| 284 | return self.calCells; |
|---|
| 285 | } |
|---|
| 286 | //----------------------------------------------------------------------------- |
|---|
| 287 | /** |
|---|
| 288 | * Runs all the operations necessary to change the mode of the calendar |
|---|
| 289 | * @param HTMLInputElement targetelement |
|---|
| 290 | */ |
|---|
| 291 | function setMode(targetelement) { |
|---|
| 292 | if(self.mode == 'popup') { //set positioning to absolute for popup |
|---|
| 293 | self.calendar.style.position = 'absolute'; |
|---|
| 294 | } |
|---|
| 295 | //if a target element has been set, append the calendar to it |
|---|
| 296 | if(targetelement) { |
|---|
| 297 | switch(self.mode) { |
|---|
| 298 | case 'flat': |
|---|
| 299 | self.tgt = targetelement; |
|---|
| 300 | self.tgt.appendChild(self.calendar); |
|---|
| 301 | self.visible = true; |
|---|
| 302 | break; |
|---|
| 303 | case 'popup': |
|---|
| 304 | self.calendar.style.position = 'absolute'; |
|---|
| 305 | document.body.appendChild(self.calendar); |
|---|
| 306 | self.setTarget(targetelement,false); |
|---|
| 307 | break; |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | else { //otherwise, add the calendar to the document.body (useful if targetelement will not be defined until after the calendar is initialized) |
|---|
| 311 | document.body.appendChild(self.calendar); |
|---|
| 312 | self.visible = false; |
|---|
| 313 | } |
|---|
| 314 | } |
|---|
| 315 | //----------------------------------------------------------------------------- |
|---|
| 316 | /** |
|---|
| 317 | * Removes the calendar table cells from the DOM (does not delete the cell objects associated with them) |
|---|
| 318 | */ |
|---|
| 319 | function deleteCells() { |
|---|
| 320 | self.calendar.celltable.removeChild(self.calendar.celltable.childNodes[1]); //remove the tbody element from the cell table |
|---|
| 321 | } |
|---|
| 322 | //----------------------------------------------------------------------------- |
|---|
| 323 | /** |
|---|
| 324 | * Sets the CSS class of the element, W3C & IE |
|---|
| 325 | * @param HTMLElement element |
|---|
| 326 | * @param string className |
|---|
| 327 | */ |
|---|
| 328 | function setClass(element,className) { |
|---|
| 329 | element.setAttribute('class',className); |
|---|
| 330 | element.setAttribute('className',className); //<iehack> |
|---|
| 331 | } |
|---|
| 332 | /** |
|---|
| 333 | * Updates a cell's data, including css class and selection properties |
|---|
| 334 | * @param int cellindex |
|---|
| 335 | */ |
|---|
| 336 | function setCellProperties(cellindex) { |
|---|
| 337 | var cell = self.cells[cellindex]; |
|---|
| 338 | var date; |
|---|
| 339 | idx = self.dateInArray(self.dates,cell.date); |
|---|
| 340 | if(idx > -1) { |
|---|
| 341 | date = self.dates[idx]; //reduce indirection |
|---|
| 342 | cell.date.selected = date.selected || false; |
|---|
| 343 | cell.date.type = date.type; |
|---|
| 344 | cell.date.canSelect = date.canSelect; |
|---|
| 345 | cell.setTitle(date.title); |
|---|
| 346 | cell.setURL(date.href); |
|---|
| 347 | cell.setHTML(date.cellHTML); |
|---|
| 348 | } |
|---|
| 349 | else { |
|---|
| 350 | cell.date.selected = false; //if the cell's date isn't in the dates array, set it's selected value to false |
|---|
| 351 | } |
|---|
| 352 | //make all cells lying outside the min and max dates un-selectable |
|---|
| 353 | if(cell.date.getTime() < self.minDate.getTime() || cell.date.getTime() > self.maxDate.getTime()) { |
|---|
| 354 | cell.date.canSelect = false; |
|---|
| 355 | } |
|---|
| 356 | cell.setClass(); |
|---|
| 357 | } |
|---|
| 358 | //----------------------------------------------------------------------------- |
|---|
| 359 | function cal_onmouseover() { |
|---|
| 360 | self.mousein = true; |
|---|
| 361 | } |
|---|
| 362 | //----------------------------------------------------------------------------- |
|---|
| 363 | function cal_onmouseout() { |
|---|
| 364 | self.mousein = false; |
|---|
| 365 | } |
|---|
| 366 | //----------------------------------------------------------------------------- |
|---|
| 367 | /** |
|---|
| 368 | * Updates the calendar's selectedDates pointer array |
|---|
| 369 | */ |
|---|
| 370 | function updateSelectedDates() { |
|---|
| 371 | var idx = 0; |
|---|
| 372 | self.selectedDates = new Array(); |
|---|
| 373 | for(i=0;i<self.dates.length;i++) { |
|---|
| 374 | if(self.dates[i].selected) { |
|---|
| 375 | self.selectedDates[idx++] = self.dates[i]; |
|---|
| 376 | } |
|---|
| 377 | } |
|---|
| 378 | } |
|---|
| 379 | //PUBLIC METHODS |
|---|
| 380 | //----------------------------------------------------------------------------- |
|---|
| 381 | /** |
|---|
| 382 | * Find a date in the given array, returning its index if found, -1 if not |
|---|
| 383 | * @param array arr |
|---|
| 384 | * @param Date searchVal |
|---|
| 385 | * @param int startIndex |
|---|
| 386 | * @return int |
|---|
| 387 | */ |
|---|
| 388 | self.dateInArray = function(arr,searchVal,startIndex) { |
|---|
| 389 | startIndex = (startIndex != null ? startIndex : 0); //default startIndex to 0, if not set |
|---|
| 390 | for(var i=startIndex;i<arr.length;i++) { |
|---|
| 391 | if(searchVal.getUeDay() == arr[i].getUeDay()) { |
|---|
| 392 | return i; |
|---|
| 393 | } |
|---|
| 394 | } |
|---|
| 395 | return -1; |
|---|
| 396 | }; |
|---|
| 397 | //----------------------------------------------------------------------------- |
|---|
| 398 | /** |
|---|
| 399 | * Changes the target element of this calendar to another input. |
|---|
| 400 | * Many thanks to Jake Olefsky - jake@olefsky.com |
|---|
| 401 | * @param HTMLInputElement targetelement |
|---|
| 402 | * @param bool focus |
|---|
| 403 | */ |
|---|
| 404 | self.setTarget = function (targetelement, focus) |
|---|
| 405 | { |
|---|
| 406 | //if this is a popup calendar |
|---|
| 407 | if(self.mode == 'popup') { |
|---|
| 408 | //declare the event handlers for the target element |
|---|
| 409 | function popupFocus() { |
|---|
| 410 | self.show(); |
|---|
| 411 | } |
|---|
| 412 | function popupBlur() { |
|---|
| 413 | if(!self.mousein){ |
|---|
| 414 | self.hide(); |
|---|
| 415 | } |
|---|
| 416 | } |
|---|
| 417 | function popupKeyDown() { |
|---|
| 418 | self.hide(); |
|---|
| 419 | } |
|---|
| 420 | //unset old target element event handlers (if there is one yet) |
|---|
| 421 | if(self.tgt) { |
|---|
| 422 | removeEventHandler(self.tgt,'focus',popupFocus); |
|---|
| 423 | removeEventHandler(self.tgt,'blur',popupBlur); |
|---|
| 424 | removeEventHandler(self.tgt,'keydown',popupKeyDown); |
|---|
| 425 | } |
|---|
| 426 | //and set the new target element |
|---|
| 427 | self.tgt = targetelement; |
|---|
| 428 | //create a pointer to the INPUT's date object and init the new data array |
|---|
| 429 | var dto = self.tgt.dateObj,pdateArr = new Array; |
|---|
| 430 | //if a date is set for the target element |
|---|
| 431 | if(dto) { |
|---|
| 432 | if(self.tgt.value.length) { //load it into the calendar... |
|---|
| 433 | pdateArr[0] = dto; |
|---|
| 434 | } |
|---|
| 435 | self.goToMonth(dto.getFullYear(),dto.getMonth()); //...and go to the target's month/year |
|---|
| 436 | } |
|---|
| 437 | self.selectDates(pdateArr,true,true,true); |
|---|
| 438 | |
|---|
| 439 | self.topOffset = self.tgt.offsetHeight; // the vertical distance (in pixels) to display the calendar from the Top of its input element |
|---|
| 440 | self.leftOffset = 0; // the horizontal distance (in pixels) to display the calendar from the Left of its input element |
|---|
| 441 | self.updatePos(self.tgt); |
|---|
| 442 | //and add the event handlers to the new element |
|---|
| 443 | addEventHandler(self.tgt,'focus',popupFocus); |
|---|
| 444 | addEventHandler(self.tgt,'blur',popupBlur); |
|---|
| 445 | addEventHandler(self.tgt,'keydown',popupKeyDown); |
|---|
| 446 | if(focus !== false) { //focus the target element immediately, unless otherwise specified |
|---|
| 447 | popupFocus(); |
|---|
| 448 | } |
|---|
| 449 | } |
|---|
| 450 | else { //if this is a flat or inline calendar |
|---|
| 451 | //if the target is already set, remove the calendar's DOM representation from it |
|---|
| 452 | if(self.tgt) { |
|---|
| 453 | self.tgt.removeChild(self.calendar); |
|---|
| 454 | } |
|---|
| 455 | //now, set the calendar's target to the new target element, and show the calendar |
|---|
| 456 | self.tgt = targetelement; |
|---|
| 457 | self.tgt.appendChild(self.calendar); |
|---|
| 458 | self.show(); |
|---|
| 459 | } |
|---|
| 460 | }; |
|---|
| 461 | //----------------------------------------------------------------------------- |
|---|
| 462 | /** |
|---|
| 463 | * Go to the next month. if the month is December, go to January of the next year |
|---|
| 464 | * Returns true if the month will be incremented |
|---|
| 465 | * @return bool |
|---|
| 466 | */ |
|---|
| 467 | self.nextMonth = function () { |
|---|
| 468 | var month = self.displayMonth; |
|---|
| 469 | var year = self.displayYear; |
|---|
| 470 | //increment the month/year values, provided they're within the min/max ranges |
|---|
| 471 | if(self.displayMonth < 11) { //i.e. if currently in the year |
|---|
| 472 | month++; |
|---|
| 473 | } |
|---|
| 474 | else if(self.yearSelect.value < self.maxDate.getFullYear()) { //if not, increment the year as well |
|---|
| 475 | month = 0; |
|---|
| 476 | year++; |
|---|
| 477 | } |
|---|
| 478 | return self.goToMonth(year,month); |
|---|
| 479 | }; |
|---|
| 480 | //----------------------------------------------------------------------------- |
|---|
| 481 | /** |
|---|
| 482 | * Go to the previous month - if the month is January, go to December of the previous year. |
|---|
| 483 | * Returns true if the month will be decremented |
|---|
| 484 | * @return bool |
|---|
| 485 | */ |
|---|
| 486 | self.prevMonth = function () { |
|---|
| 487 | var month = self.displayMonth; |
|---|
| 488 | var year = self.displayYear; |
|---|
| 489 | //increment the month/year values, provided they're within the min/max ranges |
|---|
| 490 | if(self.displayMonth > 0) { //i.e. if currently in the year |
|---|
| 491 | month--; |
|---|
| 492 | } |
|---|
| 493 | else { //if not, decrement the year as well |
|---|
| 494 | month = 11; |
|---|
| 495 | year--; |
|---|
| 496 | } |
|---|
| 497 | return self.goToMonth(year,month); |
|---|
| 498 | }; |
|---|
| 499 | //----------------------------------------------------------------------------- |
|---|
| 500 | /** |
|---|
| 501 | * Sets the calendar to display the requested month/year, returning true if the |
|---|
| 502 | * date is within the minimum and maximum allowed dates |
|---|
| 503 | * @param int year |
|---|
| 504 | * @param int month |
|---|
| 505 | * @return bool |
|---|
| 506 | */ |
|---|
| 507 | self.goToMonth = function (year,month) { |
|---|
| 508 | var testdatemin = new Date(year, month, 31); |
|---|
| 509 | var testdatemax = new Date(year, month, 1); |
|---|
| 510 | if(testdatemin >= self.minDate && testdatemax <= self.maxDate) { |
|---|
| 511 | self.monthSelect.value = self.displayMonth = month; |
|---|
| 512 | self.yearSelect.value = self.displayYear = year; |
|---|
| 513 | //recreate the calendar for the new month |
|---|
| 514 | createCalCells(); |
|---|
| 515 | deleteCells(); |
|---|
| 516 | self.calendar.celltable.appendChild(self.calCells); |
|---|
| 517 | return true; |
|---|
| 518 | } |
|---|
| 519 | else { |
|---|
| 520 | alert(self.maxrange_caption); |
|---|
| 521 | return false; |
|---|
| 522 | } |
|---|
| 523 | }; |
|---|
| 524 | //----------------------------------------------------------------------------- |
|---|
| 525 | /** |
|---|
| 526 | * Moves the calendar's position to the target element's location (popup mode only) |
|---|
| 527 | */ |
|---|
| 528 | self.updatePos = function (target) { |
|---|
| 529 | if(self.mode == 'popup') { |
|---|
| 530 | self.calendar.style.top = getTop(target) + self.topOffset + 'px'; |
|---|
| 531 | self.calendar.style.left = getLeft(target) + self.leftOffset + 'px'; |
|---|
| 532 | } |
|---|
| 533 | }; |
|---|
| 534 | //----------------------------------------------------------------------------- |
|---|
| 535 | /** |
|---|
| 536 | * Displays the calendar |
|---|
| 537 | */ |
|---|
| 538 | self.show = function () { |
|---|
| 539 | self.updatePos(self.tgt); //update the calendar position, in case the page layout has changed since loading |
|---|
| 540 | self.calendar.style.display = 'block'; //'table'; //<iehack> 'table' is the W3C-recommended spec, but IE isn't a fan of those |
|---|
| 541 | self.visible = true; |
|---|
| 542 | }; |
|---|
| 543 | //----------------------------------------------------------------------------- |
|---|
| 544 | /** |
|---|
| 545 | * Hides the calendar |
|---|
| 546 | */ |
|---|
| 547 | self.hide = function () { |
|---|
| 548 | self.calendar.style.display = 'none'; |
|---|
| 549 | self.visible = false; |
|---|
| 550 | eval(m_afterHide +"('" + m_afterHideParam + "');"); |
|---|
| 551 | }; |
|---|
| 552 | //----------------------------------------------------------------------------- |
|---|
| 553 | /** |
|---|
| 554 | * Toggles (shows/hides) the calendar depending on its current state |
|---|
| 555 | */ |
|---|
| 556 | self.toggle = function () { |
|---|
| 557 | self.visible ? self.hide() : self.show(); |
|---|
| 558 | }; |
|---|
| 559 | //----------------------------------------------------------------------------- |
|---|
| 560 | /** |
|---|
| 561 | * Adds the array "dates" to the calendar's dates array, removing duplicate dates, |
|---|
| 562 | * and redraws the calendar if redraw is true |
|---|
| 563 | * @param array dates |
|---|
| 564 | * @param bool redraw |
|---|
| 565 | */ |
|---|
| 566 | self.addDates = function (dates,redraw) { |
|---|
| 567 | var i; |
|---|
| 568 | for(i=0;i<dates.length;i++) { |
|---|
| 569 | if(self.dateInArray(self.dates,dates[i]) == -1) { //if the date isn't already in the array, add it! |
|---|
| 570 | self.dates[self.dates.length] = dates[i]; |
|---|
| 571 | } |
|---|
| 572 | } |
|---|
| 573 | //now rebuild the selectedDates pointer array |
|---|
| 574 | updateSelectedDates(); |
|---|
| 575 | if(redraw != false) { //redraw the calendar if "redraw" is false or undefined |
|---|
| 576 | self.reDraw(); |
|---|
| 577 | } |
|---|
| 578 | }; |
|---|
| 579 | //----------------------------------------------------------------------------- |
|---|
| 580 | /** |
|---|
| 581 | * Removes the dates from the calendar's dates array and redraws the calendar |
|---|
| 582 | * if redraw is true |
|---|
| 583 | * @param array dates |
|---|
| 584 | * @param bool redraw |
|---|
| 585 | */ |
|---|
| 586 | self.removeDates = function (dates,redraw) { |
|---|
| 587 | var idx; |
|---|
| 588 | for(var i=0;i<dates.length;i++) { |
|---|
| 589 | idx = self.dateInArray(self.dates,dates[i]); |
|---|
| 590 | if(idx != -1) { //search for the dates in the dates array, removing them if the dates match |
|---|
| 591 | self.dates.splice(idx,1); |
|---|
| 592 | } |
|---|
| 593 | } |
|---|
| 594 | updateSelectedDates(); |
|---|
| 595 | if(redraw != false) { //redraw the calendar if "redraw" is true or undefined |
|---|
| 596 | self.reDraw(); |
|---|
| 597 | } |
|---|
| 598 | }; |
|---|
| 599 | //----------------------------------------------------------------------------- |
|---|
| 600 | /** |
|---|
| 601 | * Selects or Deselects an array of dates |
|---|
| 602 | * @param Array inpdates |
|---|
| 603 | * @param bool selectVal |
|---|
| 604 | * @param bool redraw |
|---|
| 605 | * @param bool removeothers |
|---|
| 606 | */ |
|---|
| 607 | self.selectDates = function (inpdates,selectVal,redraw,removeothers) { |
|---|
| 608 | var i, idx; |
|---|
| 609 | if(removeothers == true) { |
|---|
| 610 | for(i=0;i<self.dates.length;i++) { |
|---|
| 611 | self.dates[i].selected = false; |
|---|
| 612 | } |
|---|
| 613 | } |
|---|
| 614 | for(i=0;i<inpdates.length;i++) { |
|---|
| 615 | idx = self.dateInArray(self.dates,inpdates[i]); |
|---|
| 616 | if(selectVal == true) { |
|---|
| 617 | inpdates[i].selected = true; |
|---|
| 618 | if(idx == -1) { //if the date does not exist in the calendar's dates array, add it |
|---|
| 619 | self.dates[self.dates.length] = inpdates[i]; |
|---|
| 620 | } |
|---|
| 621 | else { //if not, just select it |
|---|
| 622 | self.dates[idx].selected = true; |
|---|
| 623 | } |
|---|
| 624 | } |
|---|
| 625 | else { //if deselecting... |
|---|
| 626 | if(idx > -1) { //if the date is found, deselect and/or remove it from the calendar's dates array |
|---|
| 627 | self.dates[idx].selected = inpdates[i].selected = false; |
|---|
| 628 | if(self.dates[idx].type == 'normal') { //remove 'normal' dates from the dates array, since they're useless unless selected |
|---|
| 629 | self.dates.splice(idx,1); |
|---|
| 630 | } |
|---|
| 631 | } |
|---|
| 632 | } |
|---|
| 633 | } |
|---|
| 634 | //now rebuild the selectedDates pointer array |
|---|
| 635 | updateSelectedDates(); |
|---|
| 636 | if(redraw != false) { //redraw the calendar if "redraw" is false or undefined |
|---|
| 637 | self.reDraw(); |
|---|
| 638 | } |
|---|
| 639 | }; |
|---|
| 640 | //----------------------------------------------------------------------------- |
|---|
| 641 | /** |
|---|
| 642 | * Adds the dates in dates as hidden inputs to the form "form". inputname |
|---|
| 643 | * is the name of each hidden element. "form" can either be a pointer to the form's |
|---|
| 644 | * DOM element or its id string. |
|---|
| 645 | * @param mixed form |
|---|
| 646 | * @param string inputname |
|---|
| 647 | */ |
|---|
| 648 | self.sendForm = function(form,inputname) { |
|---|
| 649 | var inpname = inputname || 'epochdates', f, inp; |
|---|
| 650 | f = (typeof(form) == 'string' ? document.getElementById(form) : form); |
|---|
| 651 | if(!f) { |
|---|
| 652 | alert('ERROR: Invalid form input'); |
|---|
| 653 | return false; |
|---|
| 654 | } |
|---|
| 655 | for(var i=0;i<self.dates.length;i++) { |
|---|
| 656 | inp = document.createElement('input'); |
|---|
| 657 | inp.setAttribute('type','hidden'); |
|---|
| 658 | inp.setAttribute('name',inpname + '['+i+']'); |
|---|
| 659 | inp.setAttribute('value',encodeURIComponent(self.dates[i].dateFormat('Y-m-d'))); //default to the ISO date format |
|---|
| 660 | f.appendChild(inp); |
|---|
| 661 | } |
|---|
| 662 | return true; |
|---|
| 663 | }; |
|---|
| 664 | //----------------------------------------------------------------------------- |
|---|
| 665 | /** |
|---|
| 666 | * Erases the dates array and resets the calendar's selection variables to defaults. |
|---|
| 667 | * If retMonth is true, the calendar will return to the initial default month/year |
|---|
| 668 | * @param bool retMonth |
|---|
| 669 | */ |
|---|
| 670 | self.resetSelections = function (retMonth) { |
|---|
| 671 | var dateArray = new Array(); |
|---|
| 672 | var dt = self.dates; |
|---|
| 673 | for(var i=0;i<dt.length;i++) { |
|---|
| 674 | if(dt[i].selected) { |
|---|
| 675 | dateArray[dateArray.length] = dt[i]; |
|---|
| 676 | } |
|---|
| 677 | } |
|---|
| 678 | self.selectDates(dateArray,false,false); |
|---|
| 679 | self.rows = new Array(false,false,false,false,false,false,false); |
|---|
| 680 | self.cols = new Array(false,false,false,false,false,false,false); |
|---|
| 681 | if(self.mode == 'popup') { //hide the calendar and clear the input element if in popup mode |
|---|
| 682 | self.tgt.value = ''; |
|---|
| 683 | self.hide(); |
|---|
| 684 | } |
|---|
| 685 | retMonth == true ? self.goToMonth(self.displayYearInitial,self.displayMonthInitial) : self.reDraw(); |
|---|
| 686 | }; |
|---|
| 687 | //----------------------------------------------------------------------------- |
|---|
| 688 | /** |
|---|
| 689 | * Reapplies all the CSS classes for the calendar cells - usually called after changing their state |
|---|
| 690 | * If index is specified, it will redraw that cell only. |
|---|
| 691 | * @param int index |
|---|
| 692 | */ |
|---|
| 693 | self.reDraw = function (index) { |
|---|
| 694 | self.state = 1; |
|---|
| 695 | var len = index ? index + 1 : self.cells.length; |
|---|
| 696 | for(var i = index || 0;i<len;i++) { |
|---|
| 697 | setCellProperties(i); |
|---|
| 698 | } |
|---|
| 699 | self.state = 2; |
|---|
| 700 | }; |
|---|
| 701 | //----------------------------------------------------------------------------- |
|---|
| 702 | /** |
|---|
| 703 | * Returns the index of the cell whose date value matches "date", or -1 if not found |
|---|
| 704 | * @param Date date |
|---|
| 705 | * @return int |
|---|
| 706 | */ |
|---|
| 707 | self.getCellIndex = function(date) { |
|---|
| 708 | for(var i=0;i<self.cells.length;i++) { |
|---|
| 709 | if(self.cells[i].date.getUeDay() == date.getUeDay()) { |
|---|
| 710 | return i; |
|---|
| 711 | } |
|---|
| 712 | } |
|---|
| 713 | return -1; |
|---|
| 714 | }; |
|---|
| 715 | //----------------------------------------------------------------------------- |
|---|
| 716 | //begin constructor code: |
|---|
| 717 | |
|---|
| 718 | //PUBLIC VARIABLES |
|---|
| 719 | self.state = 0; |
|---|
| 720 | self.name = name; |
|---|
| 721 | self.curDate = new Date(); |
|---|
| 722 | self.mode = mode; |
|---|
| 723 | self.selectMultiple = (multiselect == true); //'false' if not true or not set at all |
|---|
| 724 | //the various calendar variables |
|---|
| 725 | self.dates = new Array(); |
|---|
| 726 | self.selectedDates = new Array(); |
|---|
| 727 | |
|---|
| 728 | self.calendar; |
|---|
| 729 | self.calHeading; |
|---|
| 730 | self.calCells; |
|---|
| 731 | self.rows; |
|---|
| 732 | self.cols; |
|---|
| 733 | self.cells = new Array(); |
|---|
| 734 | //The controls |
|---|
| 735 | self.monthSelect; |
|---|
| 736 | self.yearSelect; |
|---|
| 737 | self.mousein = false; |
|---|
| 738 | |
|---|
| 739 | //Initialize the calendar and its variables{ |
|---|
| 740 | calConfig(); |
|---|
| 741 | setLang(); |
|---|
| 742 | setDays(); |
|---|
| 743 | createCalendar(); //create the calendar DOM element and its children, and their related objects |
|---|
| 744 | targetelement = typeof(targetelement) == 'string' ? document.getElementById(targetelement) : targetelement; |
|---|
| 745 | setMode(targetelement); |
|---|
| 746 | self.state = 2; //0: initializing, 1: redrawing, 2: finished! |
|---|
| 747 | self.visible ? self.show() : self.hide(); |
|---|
| 748 | |
|---|
| 749 | self.afterHide = m_afterHide; |
|---|
| 750 | self.afterHideParam = m_afterHideParam; |
|---|
| 751 | self.dateformat = m_dateformat; |
|---|
| 752 | } |
|---|
| 753 | //----------------------------------------------------------------------------- |
|---|
| 754 | /*****************************************************************************/ |
|---|
| 755 | /** |
|---|
| 756 | * Object that contains the methods and properties for the calendar day headings |
|---|
| 757 | */ |
|---|
| 758 | function CalHeading(owner,tableCell,dayOfWeek) { |
|---|
| 759 | //----------------------------------------------------------------------------- |
|---|
| 760 | function DayHeadingonclick() {//selects/deselects the days for this object's day of week |
|---|
| 761 | //reduce indirection: |
|---|
| 762 | var sdates = owner.dates; |
|---|
| 763 | var cells = owner.cells; |
|---|
| 764 | var dateArray = new Array(); |
|---|
| 765 | owner.cols[dayOfWeek] = !owner.cols[dayOfWeek]; |
|---|
| 766 | for(var i=0;i<cells.length;i++) { //cycle through all the cells in the calendar, selecting all cells with the same dayOfWeek as this heading |
|---|
| 767 | if(cells[i].dayOfWeek == dayOfWeek && cells[i].date.canSelect && (!owner.selCurMonthOnly || cells[i].date.getMonth() == owner.displayMonth && cells[i].date.getFullYear() == owner.displayYear)) { //if the cell's DoW matches, with other conditions |
|---|
| 768 | dateArray[dateArray.length] = cells[i].date; |
|---|
| 769 | } |
|---|
| 770 | } |
|---|
| 771 | owner.selectDates(dateArray,owner.cols[dayOfWeek],true); |
|---|
| 772 | } |
|---|
| 773 | //----------------------------------------------------------------------------- |
|---|
| 774 | var self = this; |
|---|
| 775 | self.dayOfWeek = dayOfWeek; |
|---|
| 776 | addEventHandler(tableCell,'mouseup',DayHeadingonclick); |
|---|
| 777 | } |
|---|
| 778 | /*****************************************************************************/ |
|---|
| 779 | /** |
|---|
| 780 | * Object that contains the methods and properties for the calendar week headings |
|---|
| 781 | */ |
|---|
| 782 | function WeekHeading(owner,tableCell,week,tableRow) { |
|---|
| 783 | //----------------------------------------------------------------------------- |
|---|
| 784 | function weekHeadingonclick() { |
|---|
| 785 | //reduce indirection: |
|---|
| 786 | var cells = owner.cells; |
|---|
| 787 | var sdates = owner.dates; |
|---|
| 788 | var dateArray = new Array(); |
|---|
| 789 | owner.rows[tableRow] = !owner.rows[tableRow]; |
|---|
| 790 | for(var i=0;i<cells.length;i++) { |
|---|
| 791 | if(cells[i].tableRow == tableRow && cells[i].date.canSelect && (!owner.selCurMonthOnly || cells[i].date.getMonth() == owner.displayMonth && cells[i].date.getFullYear() == owner.displayYear)) { //if the cell's DoW matches, with other conditions) |
|---|
| 792 | dateArray[dateArray.length] = cells[i].date; |
|---|
| 793 | } |
|---|
| 794 | } |
|---|
| 795 | owner.selectDates(dateArray,owner.rows[tableRow],true); |
|---|
| 796 | } |
|---|
| 797 | //----------------------------------------------------------------------------- |
|---|
| 798 | var self = this; |
|---|
| 799 | self.week = week; |
|---|
| 800 | tableCell.setAttribute('class','wkhead'); |
|---|
| 801 | tableCell.setAttribute('className','wkhead'); //<iehack> |
|---|
| 802 | addEventHandler(tableCell,'mouseup',weekHeadingonclick); |
|---|
| 803 | } |
|---|
| 804 | /*****************************************************************************/ |
|---|
| 805 | /** |
|---|
| 806 | * Object that holds all data & code related to a calendar cell |
|---|
| 807 | */ |
|---|
| 808 | /** |
|---|
| 809 | * The CalCell constructor function |
|---|
| 810 | * @param Epoch owner |
|---|
| 811 | * @param HTMLTableCellElement tableCell |
|---|
| 812 | * @param Date dateObj |
|---|
| 813 | * @param int row |
|---|
| 814 | * @param int week |
|---|
| 815 | */ |
|---|
| 816 | function CalCell(owner,tableCell,dateObj,row,week) { |
|---|
| 817 | var self = this; |
|---|
| 818 | //----------------------------------------------------------------------------- |
|---|
| 819 | function calCellonclick() { |
|---|
| 820 | if(self.date.canSelect) { |
|---|
| 821 | if(owner.selectMultiple == true) { //if we can select multiple cells simultaneously, add the currently selected self's date to the dates array |
|---|
| 822 | owner.selectDates(new Array(self.date),!self.date.selected,false); |
|---|
| 823 | self.setClass(); //update the current cell's style to reflect the changes - a full redraw isn't necessary |
|---|
| 824 | } |
|---|
| 825 | else { //if we can only select one date at a time |
|---|
| 826 | owner.selectDates(new Array(self.date),true,false,true); |
|---|
| 827 | if(owner.mode == 'popup') { //update the target element's value and hide the calendar if in popup mode |
|---|
| 828 | //owner.tgt.value = self.date.dateFormat(); //use the default date format defined in dateFormat |
|---|
| 829 | owner.tgt.value = self.date.dateFormat(owner.dateformat); |
|---|
| 830 | owner.tgt.dateObj = new Date(self.date); //add a Date object to the target element for later reference |
|---|
| 831 | owner.hide(); |
|---|
| 832 | } |
|---|
| 833 | owner.reDraw(); //redraw all the calendar cells |
|---|
| 834 | } |
|---|
| 835 | } |
|---|
| 836 | } |
|---|
| 837 | //----------------------------------------------------------------------------- |
|---|
| 838 | /** |
|---|
| 839 | * Replicate the CSS :hover effect for non-supporting browsers <iehack> |
|---|
| 840 | */ |
|---|
| 841 | function calCellonmouseover() { |
|---|
| 842 | if(self.date.canSelect) { |
|---|
| 843 | tableCell.setAttribute('class',self.cellClass + ' hover'); |
|---|
| 844 | tableCell.setAttribute('className',self.cellClass + ' hover'); |
|---|
| 845 | } |
|---|
| 846 | } |
|---|
| 847 | //----------------------------------------------------------------------------- |
|---|
| 848 | /** |
|---|
| 849 | * Replicate the CSS :hover effect for non-supporting browsers <iehack> |
|---|
| 850 | */ |
|---|
| 851 | function calCellonmouseout() { |
|---|
| 852 | self.setClass(); |
|---|
| 853 | } |
|---|
| 854 | //----------------------------------------------------------------------------- |
|---|
| 855 | /** |
|---|
| 856 | * Sets the CSS class of the cell based on the specified criteria |
|---|
| 857 | */ |
|---|
| 858 | self.setClass = function () |
|---|
| 859 | { |
|---|
| 860 | if(self.date.canSelect !== false) { |
|---|
| 861 | if(self.date.selected) { |
|---|
| 862 | self.cellClass = 'cell_selected'; |
|---|
| 863 | } |
|---|
| 864 | else if(owner.displayMonth != self.date.getMonth() ) { |
|---|
| 865 | self.cellClass = 'notmnth'; |
|---|
| 866 | } |
|---|
| 867 | else if(self.date.type == 'holiday') { |
|---|
| 868 | self.cellClass = 'hlday'; |
|---|
| 869 | } |
|---|
| 870 | else if(self.dayOfWeek > 0 && self.dayOfWeek < 6) { |
|---|
| 871 | self.cellClass = 'wkday'; |
|---|
| 872 | } |
|---|
| 873 | else { |
|---|
| 874 | self.cellClass = 'wkend'; |
|---|
| 875 | } |
|---|
| 876 | } |
|---|
| 877 | else { |
|---|
| 878 | self.cellClass = 'noselect'; |
|---|
| 879 | } |
|---|
| 880 | //highlight the current date |
|---|
| 881 | if(self.date.getUeDay() == owner.curDate.getUeDay()) { |
|---|
| 882 | self.cellClass = self.cellClass + ' curdate'; |
|---|
| 883 | } |
|---|
| 884 | tableCell.setAttribute('class',self.cellClass); |
|---|
| 885 | tableCell.setAttribute('className',self.cellClass); //<iehack> |
|---|
| 886 | }; |
|---|
| 887 | //----------------------------------------------------------------------------- |
|---|
| 888 | /** |
|---|
| 889 | * Sets the cell's hyperlink, if declared |
|---|
| 890 | * @param string href |
|---|
| 891 | * @param string type ('anchor' or 'js' - default 'anchor') |
|---|
| 892 | */ |
|---|
| 893 | self.setURL = function(href,type) { |
|---|
| 894 | if(href) { |
|---|
| 895 | if(type == 'js') { //Make the WHOLE cell be a clickable link |
|---|
| 896 | addEventHandler(self.tableCell,'mousedown',function(){window.location.href = href;}); |
|---|
| 897 | } |
|---|
| 898 | else { //make only the date number of the cell a clickable link: |
|---|
| 899 | var url = document.createElement('a'); |
|---|
| 900 | url.setAttribute('href',href); |
|---|
| 901 | url.appendChild(document.createTextNode(self.date.getDate())); |
|---|
| 902 | self.tableCell.replaceChild(url,self.tableCell.firstChild); //assumes the first child of the cell DOM node is the date text |
|---|
| 903 | } |
|---|
| 904 | } |
|---|
| 905 | }; |
|---|
| 906 | //----------------------------------------------------------------------------- |
|---|
| 907 | /** |
|---|
| 908 | * Sets the title (i.e. tooltip) that appears when a user holds their mouse cursor over a cell |
|---|
| 909 | * @param string titleStr |
|---|
| 910 | */ |
|---|
| 911 | self.setTitle = function(titleStr) { |
|---|
| 912 | if(titleStr && titleStr.length > 0) { |
|---|
| 913 | self.title = titleStr; |
|---|
| 914 | self.tableCell.setAttribute('title',titleStr); |
|---|
| 915 | } |
|---|
| 916 | }; |
|---|
| 917 | //----------------------------------------------------------------------------- |
|---|
| 918 | /** |
|---|
| 919 | * Sets the internal html of the cell, using a string containing html markup |
|---|
| 920 | * @param string html |
|---|
| 921 | */ |
|---|
| 922 | self.setHTML = function(html) { |
|---|
| 923 | if(html && html.length > 0) { |
|---|
| 924 | if(self.tableCell.childNodes[1]) { |
|---|
| 925 | self.tableCell.childNodes[1].innerHTML = html; |
|---|
| 926 | } |
|---|
| 927 | else { |
|---|
| 928 | var htmlCont = document.createElement('div'); |
|---|
| 929 | htmlCont.innerHTML = html; |
|---|
| 930 | self.tableCell.appendChild(htmlCont); |
|---|
| 931 | } |
|---|
| 932 | } |
|---|
| 933 | }; |
|---|
| 934 | //----------------------------------------------------------------------------- |
|---|
| 935 | self.cellClass; //the CSS class of the cell |
|---|
| 936 | self.tableRow = row; |
|---|
| 937 | self.tableCell = tableCell; |
|---|
| 938 | self.date = new Date(dateObj); |
|---|
| 939 | self.date.canSelect = true; //whether this cell can be selected or not - always true unless set otherwise externally |
|---|
| 940 | self.date.type = 'normal'; //i.e. normal date, holiday, etc - always true unless set otherwise externally |
|---|
| 941 | self.date.selected = false; //whether the cell is selected (and is therefore stored in the owner's dates array) |
|---|
| 942 | self.date.cellHTML = ''; |
|---|
| 943 | self.dayOfWeek = self.date.getDay(); |
|---|
| 944 | self.week = week; |
|---|
| 945 | //assign the event handlers for the table cell element |
|---|
| 946 | addEventHandler(tableCell,'click', calCellonclick); |
|---|
| 947 | addEventHandler(tableCell,'mouseover', calCellonmouseover); |
|---|
| 948 | addEventHandler(tableCell,'mouseout', calCellonmouseout); |
|---|
| 949 | self.setClass(); |
|---|
| 950 | } |
|---|
| 951 | /*****************************************************************************/ |
|---|
| 952 | Date.prototype.getDayOfYear = function () //returns the day of the year for this date |
|---|
| 953 | { |
|---|
| 954 | return parseInt((this.getTime() - new Date(this.getFullYear(),0,1).getTime())/86400000 + 1); |
|---|
| 955 | }; |
|---|
| 956 | //----------------------------------------------------------------------------- |
|---|
| 957 | /** |
|---|
| 958 | * Returns the week number for this date. dowOffset is the day of week the week |
|---|
| 959 | * "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday), |
|---|
| 960 | * the week returned is the ISO 8601 week number. |
|---|
| 961 | * @param int dowOffset |
|---|
| 962 | * @return int |
|---|
| 963 | */ |
|---|
| 964 | Date.prototype.getWeek = function (dowOffset) { |
|---|
| 965 | dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; //default dowOffset to zero |
|---|
| 966 | var newYear = new Date(this.getFullYear(),0,1); |
|---|
| 967 | var day = newYear.getDay() - dowOffset; //the day of week the year begins on |
|---|
| 968 | day = (day >= 0 ? day : day + 7); |
|---|
| 969 | var weeknum, daynum = Math.floor((this.getTime() - newYear.getTime() - (this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1; |
|---|
| 970 | //if the year starts before the middle of a week |
|---|
| 971 | if(day < 4) { |
|---|
| 972 | weeknum = Math.floor((daynum+day-1)/7) + 1; |
|---|
| 973 | if(weeknum > 52) { |
|---|
| 974 | nYear = new Date(this.getFullYear() + 1,0,1); |
|---|
| 975 | nday = nYear.getDay() - dowOffset; |
|---|
| 976 | nday = nday >= 0 ? nday : nday + 7; |
|---|
| 977 | weeknum = nday < 4 ? 1 : 53; //if the next year starts before the middle of the week, it is week #1 of that year |
|---|
| 978 | } |
|---|
| 979 | } |
|---|
| 980 | else { |
|---|
| 981 | weeknum = Math.floor((daynum+day-1)/7); |
|---|
| 982 | } |
|---|
| 983 | return weeknum; |
|---|
| 984 | }; |
|---|
| 985 | //----------------------------------------------------------------------------- |
|---|
| 986 | Date.prototype.getUeDay = function () //returns the number of DAYS since the UNIX Epoch - good for comparing the date portion |
|---|
| 987 | { |
|---|
| 988 | return parseInt(Math.floor((this.getTime() - this.getTimezoneOffset() * 60000)/86400000)); //must take into account the local timezone |
|---|
| 989 | }; |
|---|
| 990 | //----------------------------------------------------------------------------- |
|---|
| 991 | var __DATE_FORMAT = 'm/d/Y'; |
|---|
| 992 | Date.prototype.dateFormat = function(format) |
|---|
| 993 | { |
|---|
| 994 | if(!format) { // the default date format to use - can be customized to the current locale |
|---|
| 995 | format = __DATE_FORMAT; |
|---|
| 996 | } |
|---|
| 997 | LZ = function(x) {return(x < 0 || x > 9 ? '' : '0') + x}; |
|---|
| 998 | var MONTH_NAMES = new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); |
|---|
| 999 | var DAY_NAMES = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat'); |
|---|
| 1000 | var result=""; |
|---|
| 1001 | var i_format=0; |
|---|
| 1002 | var c=""; |
|---|
| 1003 | var token=""; |
|---|
| 1004 | var y=this.getFullYear().toString(); |
|---|
| 1005 | var M=this.getMonth()+1; |
|---|
| 1006 | var d=this.getDate(); |
|---|
| 1007 | var E=this.getDay(); |
|---|
| 1008 | var H=this.getHours(); |
|---|
| 1009 | var m=this.getMinutes(); |
|---|
| 1010 | var s=this.getSeconds(); |
|---|
| 1011 | value = { |
|---|
| 1012 | Y: y.toString(), |
|---|
| 1013 | y: y.substring(2), |
|---|
| 1014 | n: M, |
|---|
| 1015 | m: LZ(M), |
|---|
| 1016 | F: MONTH_NAMES[M-1], |
|---|
| 1017 | M: MONTH_NAMES[M+11], |
|---|
| 1018 | j: d, |
|---|
| 1019 | d: LZ(d), |
|---|
| 1020 | D: DAY_NAMES[E+7], |
|---|
| 1021 | l: DAY_NAMES[E], |
|---|
| 1022 | G: H, |
|---|
| 1023 | H: LZ(H) |
|---|
| 1024 | }; |
|---|
| 1025 | if (H==0) {value['g']=12;} |
|---|
| 1026 | else if (H>12){value['g']=H-12;} |
|---|
| 1027 | else {value['g']=H;} |
|---|
| 1028 | value['h']=LZ(value['g']); |
|---|
| 1029 | if (H > 11) {value['a']='pm'; value['A'] = 'PM';} |
|---|
| 1030 | else { value['a']='am'; value['A'] = 'AM';} |
|---|
| 1031 | value['i']=LZ(m); |
|---|
| 1032 | value['s']=LZ(s); |
|---|
| 1033 | //construct the result string |
|---|
| 1034 | while (i_format < format.length) { |
|---|
| 1035 | c=format.charAt(i_format); |
|---|
| 1036 | token=""; |
|---|
| 1037 | while ((format.charAt(i_format)==c) && (i_format < format.length)) { |
|---|
| 1038 | token += format.charAt(i_format++); |
|---|
| 1039 | } |
|---|
| 1040 | if (value[token] != null) { result=result + value[token]; } |
|---|
| 1041 | else { result=result + token; } |
|---|
| 1042 | } |
|---|
| 1043 | return result; |
|---|
| 1044 | }; |
|---|
| 1045 | /*****************************************************************************/ |
|---|
| 1046 | //----------------------------------------------------------------------------- |
|---|
| 1047 | function addEventHandler(element, type, func) { //unfortunate hack to deal with Internet Explorer's horrible DOM event model <iehack> |
|---|
| 1048 | if(element.addEventListener) { |
|---|
| 1049 | element.addEventListener(type,func,false); |
|---|
| 1050 | } |
|---|
| 1051 | else if (element.attachEvent) { |
|---|
| 1052 | element.attachEvent('on'+type,func); |
|---|
| 1053 | } |
|---|
| 1054 | } |
|---|
| 1055 | //----------------------------------------------------------------------------- |
|---|
| 1056 | function removeEventHandler(element, type, func) { //unfortunate hack to deal with Internet Explorer's horrible DOM event model <iehack> |
|---|
| 1057 | if(element.removeEventListener) { |
|---|
| 1058 | element.removeEventListener(type,func,false); |
|---|
| 1059 | } |
|---|
| 1060 | else if (element.attachEvent) { |
|---|
| 1061 | element.detachEvent('on'+type,func); |
|---|
| 1062 | } |
|---|
| 1063 | } |
|---|
| 1064 | //----------------------------------------------------------------------------- |
|---|
| 1065 | function getTop(element) {//returns the absolute Top value of element, in pixels |
|---|
| 1066 | var oNode = element; |
|---|
| 1067 | var iTop = 0; |
|---|
| 1068 | |
|---|
| 1069 | while(oNode.tagName != 'HTML') { |
|---|
| 1070 | iTop += oNode.offsetTop || 0; |
|---|
| 1071 | if(oNode.offsetParent) { //i.e. the parent element is not hidden |
|---|
| 1072 | oNode = oNode.offsetParent; |
|---|
| 1073 | } |
|---|
| 1074 | else { |
|---|
| 1075 | break; |
|---|
| 1076 | } |
|---|
| 1077 | } |
|---|
| 1078 | return iTop; |
|---|
| 1079 | } |
|---|
| 1080 | //----------------------------------------------------------------------------- |
|---|
| 1081 | function getLeft(element) { //returns the absolute Left value of element, in pixels |
|---|
| 1082 | var oNode = element; |
|---|
| 1083 | var iLeft = 0; |
|---|
| 1084 | while(oNode.tagName != 'HTML') { |
|---|
| 1085 | iLeft += oNode.offsetLeft || 0; |
|---|
| 1086 | if(oNode.offsetParent) { //i.e. the parent element is not hidden |
|---|
| 1087 | oNode = oNode.offsetParent; |
|---|
| 1088 | } |
|---|
| 1089 | else { |
|---|
| 1090 | break; |
|---|
| 1091 | } |
|---|
| 1092 | } |
|---|
| 1093 | return iLeft; |
|---|
| 1094 | } |
|---|
| 1095 | //----------------------------------------------------------------------------- |
|---|