root/afridex/plugins/fresh-page/js/epoch_classes.js

Revision 21, 40.4 kB (checked in by admin, 18 years ago)
Line 
1/*!!
2Epoch DHTML JavaScript Calendar - Version 2.0.2
3English Edition
4Primary JavaScript File
5(c) 2006-2007 MeanFreePath
6Free for NON-COMMERCIAL use - see website for details and updates
7http://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*/
13function Epoch(name,mode,targetelement,multiselect) {
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,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        };
551        //-----------------------------------------------------------------------------
552        /**
553        * Toggles (shows/hides) the calendar depending on its current state
554        */
555        self.toggle = function () {
556                self.visible ? self.hide() : self.show();
557        };
558        //-----------------------------------------------------------------------------
559        /**
560        * Adds the array "dates" to the calendar's dates array, removing duplicate dates,
561        * and redraws the calendar if redraw is true
562        * @param array dates
563        * @param bool redraw
564        */
565        self.addDates = function (dates,redraw) {
566                var i;
567                for(i=0;i<dates.length;i++) {
568                        if(self.dateInArray(self.dates,dates[i]) == -1) { //if the date isn't already in the array, add it!
569                                self.dates[self.dates.length] = dates[i];
570                        }
571                }
572                //now rebuild the selectedDates pointer array
573                updateSelectedDates();
574                if(redraw != false) { //redraw  the calendar if "redraw" is false or undefined
575                        self.reDraw();
576                }
577        };
578        //-----------------------------------------------------------------------------
579        /**
580        * Removes the dates from the calendar's dates array and redraws the calendar
581        * if redraw is true
582        * @param array dates
583        * @param bool redraw
584        */
585        self.removeDates = function (dates,redraw) {
586                var idx;
587                for(var i=0;i<dates.length;i++) {
588                        idx = self.dateInArray(self.dates,dates[i]);
589                        if(idx != -1) { //search for the dates in the dates array, removing them if the dates match
590                                self.dates.splice(idx,1);
591                        }
592                }
593                updateSelectedDates();
594                if(redraw != false) { //redraw  the calendar if "redraw" is true or undefined
595                        self.reDraw();
596                }
597        };
598        //-----------------------------------------------------------------------------
599        /**
600        * Selects or Deselects an array of dates
601        * @param Array inpdates
602        * @param bool selectVal
603        * @param bool redraw
604        * @param bool removeothers
605        */
606        self.selectDates = function (inpdates,selectVal,redraw,removeothers) {
607                var i, idx;
608                if(removeothers == true) {
609                        for(i=0;i<self.dates.length;i++) {
610                                self.dates[i].selected = false;
611                        }
612                }
613                for(i=0;i<inpdates.length;i++) {
614                        idx = self.dateInArray(self.dates,inpdates[i]);
615                        if(selectVal == true) {
616                                inpdates[i].selected = true;
617                                if(idx == -1) { //if the date does not exist in the calendar's dates array, add it
618                                        self.dates[self.dates.length] = inpdates[i];
619                                }
620                                else { //if not, just select it
621                                        self.dates[idx].selected = true;
622                                }
623                        }
624                        else { //if deselecting...
625                                if(idx > -1) { //if the date is found, deselect and/or remove it from the calendar's dates array
626                                        self.dates[idx].selected = inpdates[i].selected = false;
627                                        if(self.dates[idx].type == 'normal') { //remove 'normal' dates from the dates array, since they're useless unless selected
628                                                self.dates.splice(idx,1);
629                                        }
630                                }
631                        }
632                }
633                //now rebuild the selectedDates pointer array
634                updateSelectedDates();
635                if(redraw != false) { //redraw the calendar if "redraw" is false or undefined
636                        self.reDraw();
637                }
638        };
639        //-----------------------------------------------------------------------------
640        /**
641        * Adds the dates in dates as hidden inputs to the form "form".  inputname
642        * is the name of each hidden element. "form" can either be a pointer to the form's
643        * DOM element or its id string.
644        * @param mixed form
645        * @param string inputname
646        */
647        self.sendForm = function(form,inputname) {
648                var inpname = inputname || 'epochdates', f, inp;
649                f = (typeof(form) == 'string' ? document.getElementById(form) : form);
650                if(!f) {
651                        alert('ERROR: Invalid form input');
652                        return false;
653                }
654                for(var i=0;i<self.dates.length;i++) {
655                        inp = document.createElement('input');
656                        inp.setAttribute('type','hidden');
657                        inp.setAttribute('name',inpname + '['+i+']');
658                        inp.setAttribute('value',encodeURIComponent(self.dates[i].dateFormat('Y-m-d')));  //default to the ISO date format
659                        f.appendChild(inp);
660                }
661                return true;
662        };
663        //-----------------------------------------------------------------------------
664        /**
665        * Erases the dates array and resets the calendar's selection variables to defaults.
666        * If retMonth is true, the calendar will return to the initial default month/year
667        * @param bool retMonth
668        */
669        self.resetSelections = function (retMonth) {
670                var dateArray = new Array();
671                var dt = self.dates;
672                for(var i=0;i<dt.length;i++) {
673                        if(dt[i].selected) {
674                                dateArray[dateArray.length] = dt[i];
675                        }
676                }
677                self.selectDates(dateArray,false,false);
678                self.rows = new Array(false,false,false,false,false,false,false);
679                self.cols = new Array(false,false,false,false,false,false,false);
680                if(self.mode == 'popup') { //hide the calendar and clear the input element if in popup mode
681                        self.tgt.value = '';
682                        self.hide();
683                }
684                retMonth == true ? self.goToMonth(self.displayYearInitial,self.displayMonthInitial) : self.reDraw();
685        };
686        //-----------------------------------------------------------------------------
687        /**
688        * Reapplies all the CSS classes for the calendar cells - usually called after changing their state
689        * If index is specified, it will redraw that cell only.
690        * @param int index
691        */
692        self.reDraw = function (index) {
693                self.state = 1;
694                var len = index ? index + 1 : self.cells.length;
695                for(var i = index || 0;i<len;i++) {
696                        setCellProperties(i);
697                }
698                self.state = 2;
699        };
700        //-----------------------------------------------------------------------------
701        /**
702        * Returns the index of the cell whose date value matches "date", or -1 if not found
703        * @param Date date
704        * @return int
705        */
706        self.getCellIndex = function(date) {
707                for(var i=0;i<self.cells.length;i++) {
708                        if(self.cells[i].date.getUeDay() == date.getUeDay()) {
709                                return i;
710                        }
711                }
712                return -1;
713        };
714        //-----------------------------------------------------------------------------
715        //begin constructor code:
716
717        //PUBLIC VARIABLES
718        self.state = 0;
719        self.name = name;
720        self.curDate = new Date();
721        self.mode = mode;
722        self.selectMultiple = (multiselect == true); //'false' if not true or not set at all
723        //the various calendar variables
724        self.dates = new Array();
725        self.selectedDates = new Array();
726
727        self.calendar;
728        self.calHeading;
729        self.calCells;
730        self.rows;
731        self.cols;
732        self.cells = new Array();
733        //The controls
734        self.monthSelect;
735        self.yearSelect;
736        self.mousein = false;
737
738        //Initialize the calendar and its variables{
739        calConfig();
740        setLang();
741        setDays();
742        createCalendar(); //create the calendar DOM element and its children, and their related objects
743        targetelement = typeof(targetelement) == 'string' ? document.getElementById(targetelement) : targetelement;
744        setMode(targetelement);
745        self.state = 2; //0: initializing, 1: redrawing, 2: finished!
746        self.visible ? self.show() : self.hide();
747}
748//-----------------------------------------------------------------------------
749/*****************************************************************************/
750/**
751* Object that contains the methods and properties for the calendar day headings
752*/
753function CalHeading(owner,tableCell,dayOfWeek) {
754        //-----------------------------------------------------------------------------
755        function DayHeadingonclick() {//selects/deselects the days for this object's day of week
756                //reduce indirection:
757                var sdates = owner.dates;
758                var cells = owner.cells;
759                var dateArray = new Array();
760                owner.cols[dayOfWeek] = !owner.cols[dayOfWeek];
761                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
762                        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
763                                dateArray[dateArray.length] = cells[i].date;
764                        }
765                }
766                owner.selectDates(dateArray,owner.cols[dayOfWeek],true);
767        }
768        //-----------------------------------------------------------------------------
769        var self = this;
770        self.dayOfWeek = dayOfWeek;
771        addEventHandler(tableCell,'mouseup',DayHeadingonclick);
772}
773/*****************************************************************************/
774/**
775* Object that contains the methods and properties for the calendar week headings
776*/
777function WeekHeading(owner,tableCell,week,tableRow) {
778        //-----------------------------------------------------------------------------
779        function weekHeadingonclick() {
780                //reduce indirection:
781                var cells = owner.cells;
782                var sdates = owner.dates;
783                var dateArray = new Array();
784                owner.rows[tableRow] = !owner.rows[tableRow];
785                for(var i=0;i<cells.length;i++) {
786                        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)
787                                dateArray[dateArray.length] = cells[i].date;
788                        }
789                }
790                owner.selectDates(dateArray,owner.rows[tableRow],true);
791        }
792        //-----------------------------------------------------------------------------
793        var self = this;
794        self.week = week;
795        tableCell.setAttribute('class','wkhead');
796        tableCell.setAttribute('className','wkhead'); //<iehack>
797        addEventHandler(tableCell,'mouseup',weekHeadingonclick);
798}
799/*****************************************************************************/
800/**
801* Object that holds all data & code related to a calendar cell
802*/
803/**
804 * The CalCell constructor function
805 * @param Epoch owner
806 * @param HTMLTableCellElement tableCell
807 * @param Date dateObj
808 * @param int row
809 * @param int week
810 */
811function CalCell(owner,tableCell,dateObj,row,week) {
812        var self = this;
813        //-----------------------------------------------------------------------------
814        function calCellonclick() {
815                if(self.date.canSelect) {
816                        if(owner.selectMultiple == true) { //if we can select multiple cells simultaneously, add the currently selected self's date to the dates array
817                                owner.selectDates(new Array(self.date),!self.date.selected,false);
818                                self.setClass(); //update the current cell's style to reflect the changes - a full redraw isn't necessary
819                        }
820                        else { //if we can only select one date at a time
821                                owner.selectDates(new Array(self.date),true,false,true);
822                                if(owner.mode == 'popup') { //update the target element's value and hide the calendar if in popup mode
823                                        owner.tgt.value = self.date.dateFormat(); //use the default date format defined in dateFormat
824                                        owner.tgt.dateObj = new Date(self.date); //add a Date object to the target element for later reference
825                                        owner.hide();
826                                }
827                                owner.reDraw(); //redraw all the calendar cells
828                        }
829                }
830        }
831        //-----------------------------------------------------------------------------
832        /**
833        * Replicate the CSS :hover effect for non-supporting browsers <iehack>
834        */
835        function calCellonmouseover() {
836                if(self.date.canSelect) {
837                        tableCell.setAttribute('class',self.cellClass + ' hover');
838                        tableCell.setAttribute('className',self.cellClass + ' hover');
839                }
840        }
841        //-----------------------------------------------------------------------------
842        /**
843        * Replicate the CSS :hover effect for non-supporting browsers <iehack>
844        */
845        function calCellonmouseout() {
846                self.setClass();
847        }
848        //-----------------------------------------------------------------------------
849        /**
850        * Sets the CSS class of the cell based on the specified criteria
851        */
852        self.setClass = function ()
853        {
854                if(self.date.canSelect !== false) {
855                        if(self.date.selected) {
856                                self.cellClass = 'cell_selected';
857                        }
858                        else if(owner.displayMonth != self.date.getMonth() ) {
859                                self.cellClass = 'notmnth';
860                        }
861                        else if(self.date.type == 'holiday') {
862                                self.cellClass = 'hlday';
863                        }
864                        else if(self.dayOfWeek > 0 && self.dayOfWeek < 6) {
865                                self.cellClass = 'wkday';
866                        }
867                        else {
868                                self.cellClass = 'wkend';
869                        }
870                }
871                else {
872                        self.cellClass = 'noselect';
873                }
874                //highlight the current date
875                if(self.date.getUeDay() == owner.curDate.getUeDay()) {
876                        self.cellClass = self.cellClass + ' curdate';
877                }
878                tableCell.setAttribute('class',self.cellClass);
879                tableCell.setAttribute('className',self.cellClass); //<iehack>
880        };
881        //-----------------------------------------------------------------------------
882        /**
883        * Sets the cell's hyperlink, if declared
884        * @param string href
885        * @param string type ('anchor' or 'js' - default 'anchor')
886        */
887        self.setURL = function(href,type) {
888                if(href) {
889                        if(type == 'js') { //Make the WHOLE cell be a clickable link
890                                addEventHandler(self.tableCell,'mousedown',function(){window.location.href = href;});
891                        }
892                        else { //make only the date number of the cell a clickable link:
893                                var url = document.createElement('a');
894                                url.setAttribute('href',href);
895                                url.appendChild(document.createTextNode(self.date.getDate()));
896                                self.tableCell.replaceChild(url,self.tableCell.firstChild); //assumes the first child of the cell DOM node is the date text
897                        }
898                }
899        };
900        //-----------------------------------------------------------------------------
901        /**
902        * Sets the title (i.e. tooltip) that appears when a user holds their mouse cursor over a cell
903        * @param string titleStr
904        */
905        self.setTitle = function(titleStr) {
906                if(titleStr && titleStr.length > 0) {
907                        self.title = titleStr;
908                        self.tableCell.setAttribute('title',titleStr);
909                }
910        };
911        //-----------------------------------------------------------------------------
912        /**
913        * Sets the internal html of the cell, using a string containing html markup
914        * @param string html
915        */
916        self.setHTML = function(html) {
917                if(html && html.length > 0) {
918                        if(self.tableCell.childNodes[1]) {
919                                self.tableCell.childNodes[1].innerHTML = html;
920                        }
921                        else {
922                                var htmlCont = document.createElement('div');
923                                htmlCont.innerHTML = html;
924                                self.tableCell.appendChild(htmlCont);
925                        }
926                }
927        };
928        //-----------------------------------------------------------------------------
929        self.cellClass;                 //the CSS class of the cell
930        self.tableRow = row;
931        self.tableCell = tableCell;
932        self.date = new Date(dateObj);
933        self.date.canSelect = true; //whether this cell can be selected or not - always true unless set otherwise externally
934        self.date.type = 'normal';  //i.e. normal date, holiday, etc - always true unless set otherwise externally
935        self.date.selected = false;     //whether the cell is selected (and is therefore stored in the owner's dates array)
936        self.date.cellHTML = '';
937        self.dayOfWeek = self.date.getDay();
938        self.week = week;
939        //assign the event handlers for the table cell element
940        addEventHandler(tableCell,'click', calCellonclick);
941        addEventHandler(tableCell,'mouseover', calCellonmouseover);
942        addEventHandler(tableCell,'mouseout', calCellonmouseout);
943        self.setClass();
944}
945/*****************************************************************************/
946Date.prototype.getDayOfYear = function () //returns the day of the year for this date
947{
948        return parseInt((this.getTime() - new Date(this.getFullYear(),0,1).getTime())/86400000 + 1);
949};
950//-----------------------------------------------------------------------------
951/**
952 * Returns the week number for this date.  dowOffset is the day of week the week
953 * "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
954 * the week returned is the ISO 8601 week number.
955 * @param int dowOffset
956 * @return int
957 */
958Date.prototype.getWeek = function (dowOffset) {
959        dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; //default dowOffset to zero
960        var newYear = new Date(this.getFullYear(),0,1);
961        var day = newYear.getDay() - dowOffset; //the day of week the year begins on
962        day = (day >= 0 ? day : day + 7);
963        var weeknum, daynum = Math.floor((this.getTime() - newYear.getTime() - (this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
964        //if the year starts before the middle of a week
965        if(day < 4) {
966                weeknum = Math.floor((daynum+day-1)/7) + 1;
967                if(weeknum > 52) {
968                        nYear = new Date(this.getFullYear() + 1,0,1);
969                        nday = nYear.getDay() - dowOffset;
970                        nday = nday >= 0 ? nday : nday + 7;
971                        weeknum = nday < 4 ? 1 : 53; //if the next year starts before the middle of the week, it is week #1 of that year
972                }
973        }
974        else {
975                weeknum = Math.floor((daynum+day-1)/7);
976        }
977        return weeknum;
978};
979//-----------------------------------------------------------------------------
980Date.prototype.getUeDay = function () //returns the number of DAYS since the UNIX Epoch - good for comparing the date portion
981{
982        return parseInt(Math.floor((this.getTime() - this.getTimezoneOffset() * 60000)/86400000)); //must take into account the local timezone
983};
984//-----------------------------------------------------------------------------
985var __DATE_FORMAT = 'm/d/Y';
986Date.prototype.dateFormat = function(format)
987{
988        if(!format) { // the default date format to use - can be customized to the current locale
989                format = __DATE_FORMAT;
990        }
991        LZ = function(x) {return(x < 0 || x > 9 ? '' : '0') + x};
992        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');
993        var DAY_NAMES = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
994        var result="";
995        var i_format=0;
996        var c="";
997        var token="";
998        var y=this.getFullYear().toString();
999        var M=this.getMonth()+1;
1000        var d=this.getDate();
1001        var E=this.getDay();
1002        var H=this.getHours();
1003        var m=this.getMinutes();
1004        var s=this.getSeconds();
1005        value = {
1006                Y: y.toString(),
1007                y: y.substring(2),
1008                n: M,
1009                m: LZ(M),
1010                F: MONTH_NAMES[M-1],
1011                M: MONTH_NAMES[M+11],
1012                j: d,
1013                d: LZ(d),
1014                D: DAY_NAMES[E+7],
1015                l: DAY_NAMES[E],
1016                G: H,
1017                H: LZ(H)
1018        };
1019        if (H==0) {value['g']=12;}
1020        else if (H>12){value['g']=H-12;}
1021        else {value['g']=H;}
1022        value['h']=LZ(value['g']);
1023        if (H > 11) {value['a']='pm'; value['A'] = 'PM';}
1024        else { value['a']='am'; value['A'] = 'AM';}
1025        value['i']=LZ(m);
1026        value['s']=LZ(s);
1027        //construct the result string
1028        while (i_format < format.length) {
1029                c=format.charAt(i_format);
1030                token="";
1031                while ((format.charAt(i_format)==c) && (i_format < format.length)) {
1032                        token += format.charAt(i_format++);
1033                }
1034                if (value[token] != null) { result=result + value[token]; }
1035                else { result=result + token; }
1036        }
1037        return result;
1038};
1039/*****************************************************************************/
1040//-----------------------------------------------------------------------------
1041function addEventHandler(element, type, func) { //unfortunate hack to deal with Internet Explorer's horrible DOM event model <iehack>
1042        if(element.addEventListener) {
1043                element.addEventListener(type,func,false);
1044        }
1045        else if (element.attachEvent) {
1046                element.attachEvent('on'+type,func);
1047        }
1048}
1049//-----------------------------------------------------------------------------
1050function removeEventHandler(element, type, func) { //unfortunate hack to deal with Internet Explorer's horrible DOM event model <iehack>
1051        if(element.removeEventListener) {
1052                element.removeEventListener(type,func,false);
1053        }
1054        else if (element.attachEvent) {
1055                element.detachEvent('on'+type,func);
1056        }
1057}
1058//-----------------------------------------------------------------------------
1059function getTop(element) {//returns the absolute Top value of element, in pixels
1060        var oNode = element;
1061        var iTop = 0;
1062
1063        while(oNode.tagName != 'HTML') {
1064                iTop += oNode.offsetTop || 0;
1065                if(oNode.offsetParent) { //i.e. the parent element is not hidden
1066                        oNode = oNode.offsetParent;
1067                }
1068                else {
1069                        break;
1070                }
1071        }
1072        return iTop;
1073}
1074//-----------------------------------------------------------------------------
1075function getLeft(element) { //returns the absolute Left value of element, in pixels
1076        var oNode = element;
1077        var iLeft = 0;
1078        while(oNode.tagName != 'HTML') {
1079                iLeft += oNode.offsetLeft || 0;
1080                if(oNode.offsetParent) { //i.e. the parent element is not hidden
1081                        oNode = oNode.offsetParent;
1082                }
1083                else {
1084                        break;
1085                }
1086        }
1087        return iLeft;
1088}
1089//-----------------------------------------------------------------------------
Note: See TracBrowser for help on using the browser.