Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
27 jpm 1
/*
2
 * Ext JS Library 2.0 RC 1
3
 * Copyright(c) 2006-2007, Ext JS, LLC.
4
 * licensing@extjs.com
5
 *
6
 * http://extjs.com/license
7
 */
8
 
9
/**
10
 * @class Ext.MultiMonthCalendar
11
 * @extends Ext.Component
12
 * Multi-month Calendar
13
 * @constructor
14
  * @param {Object} config The config object
15
 */
16
Ext.ux.MultiMonthCalendar = Ext.extend(Ext.Component, {
17
    /**
18
     * @cfg {Date} minDate
19
     * Minimum allowable date (JavaScript date object, defaults to null)
20
     */
21
    minDate : null,
22
    /**
23
     * @cfg {Date} maxDate
24
     * Maximum allowable date (JavaScript date object, defaults to null)
25
     */
26
    maxDate : null,
27
    /**
28
     * @cfg {String} minText
29
     * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
30
     */
31
    minText : "This date is before the minimum date",
32
    /**
33
     * @cfg {String} maxText
34
     * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
35
     */
36
    maxText : "This date is after the maximum date",
37
    /**
38
     * @cfg {String} format
39
     * The default date format string which can be overriden for localization support.  The format must be
40
     * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41
     */
42
    format : "m/d/y",
43
    /**
44
     * @cfg {Array} disabledDays
45
     * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
46
     */
47
    disabledDays : null,
48
    /**
49
     * @cfg {String} disabledDaysText
50
     * The tooltip to display when the date falls on a disabled day (defaults to "")
51
     */
52
    disabledDaysText : "",
53
    /**
54
     * @cfg {RegExp} disabledDatesRE
55
     * JavaScript regular expression used to disable a pattern of dates (defaults to null)
56
     */
57
    disabledDatesRE : null,
58
    /**
59
     * @cfg {String} disabledDatesText
60
     * The tooltip text to display when the date falls on a disabled date (defaults to "")
61
     */
62
    disabledDatesText : "",
63
    /**
64
     * @cfg {Boolean} constrainToViewport
65
     * True to constrain the date picker to the viewport (defaults to true)
66
     */
67
    constrainToViewport : true,
68
    /**
69
     * @cfg {Array} monthNames
70
     * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
71
     */
72
    monthNames : Date.monthNames,
73
    /**
74
     * @cfg {Array} dayNames
75
     * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
76
     */
77
    dayNames : Date.dayNames,
78
    /**
79
     * @cfg {String} nextText
80
     * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
81
     */
82
    nextText: 'Next Month (Control+Right)',
83
    /**
84
     * @cfg {String} prevText
85
     * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
86
     */
87
    prevText: 'Previous Month (Control+Left)',
88
    /**
89
     * @cfg {Number} startDay
90
     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
91
     */
92
    startDay : 0,
93
    /**
94
    * @cfg {Number} noOfMonth
95
    * No of Month to be displayed
96
    */
97
    noOfMonth : 2,
98
/**
99
    * @cfg {Array} eventDates
100
    * List of Dates which have an event (show as selected in UI)
101
    */
102
    eventDates : null,
103
 
104
    /**
105
    * @cfg {Array} noOfMonthPerRow
106
    * No. Of Month to be displayed in a row
107
    */
108
    noOfMonthPerRow : 3,
109
 
110
    initComponent : function(){
111
        Ext.ux.MultiMonthCalendar.superclass.initComponent.call(this);
112
        this.value = this.value ?
113
                 this.value.clearTime() : new Date().clearTime();
114
        this.initDisabledDays();
115
        this.noOfMonthPerRow = this.noOfMonthPerRow > this.noOfMonth ?this.noOfMonth : this.noOfMonthPerRow
116
    },
117
 
118
    // private
119
    initDisabledDays : function(){
120
        if(!this.disabledDatesRE && this.disabledDates){
121
            var dd = this.disabledDates;
122
            var re = "(?:";
123
            for(var i = 0; i < dd.length; i++){
124
                re += dd[i];
125
                if(i != dd.length-1) re += "|";
126
            }
127
            this.disabledDatesRE = new RegExp(re + ")");
128
        }
129
    },
130
 
131
    /**
132
     * Sets the value of the date field
133
     * @param {Date} value The date to set
134
     */
135
 
136
    setValue : function(value){
137
        var old = this.value;
138
        this.value = value.clearTime(true);
139
        if(this.el){
140
            this.update(this.value);
141
        }
142
    },
143
 
144
    /**
145
     * Gets the current selected value of the date field
146
     * @return {Date} The selected date
147
     */
148
    getValue : function(){
149
        return this.value;
150
    },
151
 
152
 
153
    // private
154
    focus : function(){
155
        if(this.el){
156
            this.update(this.activeDate);
157
        }
158
    },
159
 
160
    // private
161
	onRender : function(container, position){
162
        var m = ["<table cellspacing='0'>"];
163
        if(this.noOfMonthPerRow > 1) {
164
            m.push("<tr><td class='x-date-left'><a href='#' title='", this.prevText ,"'> </a></td>");
165
               m.push("<td class='x-date-left' colspan='"+ eval(this.noOfMonthPerRow *2 -3) +"'></td>");
166
               m.push("<td class='x-date-right'><a href='#' title='", this.nextText ,"'> </a></td></tr><tr>");
167
       } else {
168
               //Special case of only one month
169
               m.push("<tr><td><table cellspacing='0' width='100%'><tr><td class='x-date-left'><a href='#' title='", this.prevText ,"'> </a></td>");
170
               m.push("<td class='x-date-right'><a href='#' title='", this.nextText ,"'> </a></td></tr></table></td></tr><tr>");
171
       }
172
        for(var x=0; x<this.noOfMonth; x++) {
173
            m.push("<td><table border='1' cellspacing='0'><tr>");
174
            m.push("<td class='x-date-middle' align='center'><span id='monthLabel" + x + "'></span></td>");
175
            m.push("</tr><tr><td><table class='x-date-inner' id='inner-date"+x+"' cellspacing='0'><thead><tr>");
176
            var dn = this.dayNames;
177
            for(var i = 0; i < 7; i++){
178
               var d = this.startDay+i;
179
               if(d > 6){
180
                   d = d-7;
181
               }
182
                m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
183
            }
184
            m[m.length] = "</tr></thead><tbody><tr>";
185
            for(var i = 0; i < 42; i++) {
186
                if(i % 7 == 0 && i != 0){
187
                    m[m.length] = "</tr><tr>";
188
                }
189
                m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
190
            }
191
            m[m.length] = '</tr></tbody></table></td></tr></table></td>';
192
            if(x != this.noOfMonth-1) {
193
                m[m.length] = "<td width='3'></td>";
194
            }
195
            if( (x+1) % this.noOfMonthPerRow == 0 && x!= 0) {
196
                m[m.length] = "</tr><tr>";
197
            }
198
        }
199
        m[m.length] = "</tr></table>";
200
        var el = document.createElement("div");
201
        el.className = "x-date-picker";
202
        el.innerHTML = m.join("");
203
 
204
        container.dom.insertBefore(el, position);
205
 
206
        this.el = Ext.get(el);
207
        this.eventEl = Ext.get(el.firstChild);
208
 
209
        new Ext.util.ClickRepeater(this.el.child("td.x-date-left a"), {
210
            handler: this.showPrevMonth,
211
            scope: this,
212
            preventDefault:true,
213
            stopDefault:true
214
        });
215
 
216
        new Ext.util.ClickRepeater(this.el.child("td.x-date-right a"), {
217
            handler: this.showNextMonth,
218
            scope: this,
219
            preventDefault:true,
220
            stopDefault:true
221
        });
222
 
223
        var kn = new Ext.KeyNav(this.eventEl, {
224
            "left" : function(e){
225
                e.ctrlKey ?
226
                    this.showPrevMonth() :
227
                    this.update(this.activeDate.add("d", -1));
228
            },
229
 
230
            "right" : function(e){
231
                e.ctrlKey ?
232
                    this.showNextMonth() :
233
                    this.update(this.activeDate.add("d", 1));
234
            },
235
 
236
            "pageUp" : function(e){
237
                this.showNextMonth();
238
            },
239
 
240
            "pageDown" : function(e){
241
                this.showPrevMonth();
242
            },
243
 
244
            "enter" : function(e){
245
                e.stopPropagation();
246
                return true;
247
            },
248
            scope : this
249
        });
250
 
251
        this.cellsArray = new Array();
252
        this.textNodesArray = new Array();
253
        for(var x=0; x< this.noOfMonth; x++) {
254
            var cells = Ext.get('inner-date'+x).select("tbody td");
255
            var textNodes = Ext.get('inner-date'+x).query("tbody span");
256
            this.cellsArray[x] = cells;
257
            this.textNodesArray[x] = textNodes;
258
        }
259
 
260
        if(Ext.isIE){
261
            this.el.repaint();
262
        }
263
        this.update(this.value);
264
    },
265
 
266
    // private
267
    showPrevMonth : function(e){
268
        this.update(this.activeDate.add("mo", -1));
269
    },
270
 
271
    // private
272
    showNextMonth : function(e){
273
        this.update(this.activeDate.add("mo", 1));
274
    },
275
 
276
    // private
277
    update : function(date){
278
        this.activeDate = date;
279
        for(var x=0;x<this.noOfMonth;x++) {
280
            var days = date.getDaysInMonth();
281
            var firstOfMonth = date.getFirstDateOfMonth();
282
            var startingPos = firstOfMonth.getDay()-this.startDay;
283
 
284
            if(startingPos <= this.startDay){
285
                startingPos += 7;
286
            }
287
 
288
            var pm = date.add("mo", -1);
289
            var prevStart = pm.getDaysInMonth()-startingPos;
290
 
291
            var cells = this.cellsArray[x].elements;
292
            var textEls = this.textNodesArray[x];
293
            days += startingPos;
294
 
295
            // convert everything to numbers so it's fast
296
            var day = 86400000;
297
            var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
298
            var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
299
            var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
300
            var ddMatch = this.disabledDatesRE;
301
            var ddText = this.disabledDatesText;
302
            var ddays = this.disabledDays ? this.disabledDays.join("") : false;
303
            var ddaysText = this.disabledDaysText;
304
            var format = this.format;
305
 
306
            var setCellClass = function(cal, cell){
307
                cell.title = "";
308
                var t = d.getTime();
309
                cell.firstChild.dateValue = t;
310
 
311
                // disabling
312
                if(t < min) {
313
                    cell.className = " x-date-disabled";
314
                    cell.title = cal.minText;
315
                    return;
316
                }
317
                if(t > max) {
318
                    cell.className = " x-date-disabled";
319
                    cell.title = cal.maxText;
320
                    return;
321
                }
322
                if(ddays){
323
                    if(ddays.indexOf(d.getDay()) != -1){
324
                        cell.title = ddaysText;
325
                        cell.className = " x-date-disabled";
326
                    }
327
                }
328
                if(ddMatch && format){
329
                    var fvalue = d.dateFormat(format);
330
                    if(ddMatch.test(fvalue)){
331
                        cell.title = ddText.replace("%0", fvalue);
332
                        cell.className = " x-date-disabled";
333
                    }
334
                }
335
                //Only active days need to be selected
336
                if(cal.eventDates && (cell.className.indexOf('x-date-active') != -1)) {
337
                    for(var y=0; y < cal.eventDates.length; y++) {
338
                        var evtDate = cal.eventDates[y].clearTime().getTime();
339
                        if(t == evtDate) {
340
                            cell.className += " x-date-selected";
341
                            break;
342
                        }
343
                    }
344
                }
345
            };
346
 
347
            var i = 0;
348
            for(; i < startingPos; i++) {
349
                textEls[i].innerHTML = (++prevStart);
350
                d.setDate(d.getDate()+1);
351
                cells[i].className = "x-date-prevday";
352
                setCellClass(this, cells[i]);
353
            }
354
            for(; i < days; i++){
355
                intDay = i - startingPos + 1;
356
                textEls[i].innerHTML = (intDay);
357
                d.setDate(d.getDate()+1);
358
                cells[i].className = "x-date-active";
359
                setCellClass(this, cells[i]);
360
            }
361
            var extraDays = 0;
362
            for(; i < 42; i++) {
363
                 textEls[i].innerHTML = (++extraDays);
364
                 d.setDate(d.getDate()+1);
365
                 cells[i].className = "x-date-nextday";
366
                 setCellClass(this, cells[i]);
367
            }
368
            var monthLabel = Ext.get('monthLabel' + x);
369
            monthLabel.update(this.monthNames[date.getMonth()] + " " + date.getFullYear());
370
 
371
            if(!this.internalRender){
372
                var main = this.el.dom.firstChild;
373
                var w = main.offsetWidth;
374
                this.el.setWidth(w + this.el.getBorderWidth("lr"));
375
                Ext.fly(main).setWidth(w);
376
                this.internalRender = true;
377
                // opera does not respect the auto grow header center column
378
                // then, after it gets a width opera refuses to recalculate
379
                // without a second pass
380
                if(Ext.isOpera && !this.secondPass){
381
                    main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
382
                    this.secondPass = true;
383
                    this.update.defer(10, this, [date]);
384
                }
385
            }
386
            date = date.add('mo',1);
387
        }
388
    }
389
});
390
Ext.reg('mmcalendar', Ext.ux.MultiMonthCalendar);
391