source: trunk/spip/esqueleto-redcta/plugins/spip-listes_1_9_2/javascript/datepicker.js @ 90

Last change on this file since 90 was 90, checked in by guille, 15 years ago

importacion de spip-listes-1_9_2

File size: 12.9 KB
Line 
1/*
2 * Date picker plugin for jQuery
3 * http://kelvinluck.com/assets/jquery/datePicker
4 *
5 * Copyright (c) 2006 Kelvin Luck (kelvnluck.com)
6 * Licensed under the MIT License:
7 *   http://www.opensource.org/licenses/mit-license.php
8 *
9 * $LastChangedDate: 2006-10-08 19:08:47 +0100 (Sun, 08 Oct 2006) $
10 * $Rev: 23 $
11 */
12 
13$.datePicker = function()
14{
15        // so that firebug console.log statements don't break IE
16        if (window.console == undefined) { window.console = {log:function(){}}; }
17       
18        var months = ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
19        var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
20        var navLinks = {p:'Prev', n:'Next', c:'Close'};
21        var dateFormat = 'dd/mm/yyyy';
22        var _firstDate;
23        var _lastDate;
24       
25        var _selectedDate;
26        var _openCal;
27       
28        var _zeroPad = function(num) { 
29                var s = '0'+num;
30                return s.substring(s.length-2) 
31                //return ('0'+num).substring(-2); // doesn't work on IE :(
32        };
33        var _strToDate = function(dIn)
34        {
35                switch (dateFormat.toLowerCase()) {
36                        case 'yyyy-mm-dd':
37                                dParts = dIn.split('-');
38                                return new Date(dParts[0], Number(dParts[1])-1, dParts[2]);
39                        case 'dd/mm/yyyy':
40                                dParts = dIn.split('/');
41                                return new Date(dParts[2], Number(dParts[1])-1, Number(dParts[0]));
42                        case 'mm/dd/yyyy':
43                        default:
44                                var parts = parts ? parts : [2, 1, 0];
45                                dParts = dIn.split('/');
46                                return new Date(dParts[2], Number(dParts[0])-1, Number(dParts[1]));
47                }
48        };
49        var _dateToStr = function(d)
50        {
51                var dY = d.getFullYear();
52                var dM = _zeroPad(d.getMonth()+1);
53                var dD = _zeroPad(d.getDate());
54                switch (dateFormat.toLowerCase()) {
55                        case 'yyyy/mm/dd':
56                                return dY + '/' + dM + '/' + dD;
57                        case 'yyyy-mm-dd':
58                                return dY + '-' + dM + '-' + dD;
59                        case 'dd/mm/yyyy':
60                                return dD + '/' + dM + '/' + dY;
61                        case 'mm/dd/yyyy':
62                        default:
63                                return dM + '/' + dD + '/' + dY;
64                }
65        };
66       
67        var _getCalendarDiv = function(dIn)
68        {
69                var today = new Date();
70                if (dIn == undefined) {
71                        // start from this month.
72                        d = new Date(today.getFullYear(), today.getMonth(), 1);
73                } else {
74                        // start from the passed in date
75                        d = dIn;
76                        d.setDate(1);
77                }
78                // check that date is within allowed limits:           
79                if ((d.getMonth() < _firstDate.getMonth() && d.getFullYear() == _firstDate.getFullYear()) || d.getFullYear() < _firstDate.getFullYear()) {
80                        d = new Date(_firstDate.getFullYear(), _firstDate.getMonth(), 1);;
81                } else if ((d.getMonth() > _lastDate.getMonth() && d.getFullYear() == _lastDate.getFullYear()) || d.getFullYear() > _lastDate.getFullYear()) {
82                        d = new Date(_lastDate.getFullYear(), _lastDate.getMonth(), 1);;
83                }
84               
85                var calDiv = $.DIV({className:'popup-calendar'}, '');
86                var jCalDiv = $(calDiv);
87                var firstMonth = true;
88                var firstDate = _firstDate.getDate();
89               
90                // create prev and next links
91                var prevLinkDiv = '';
92                if (!(d.getMonth() == _firstDate.getMonth() && d.getFullYear() == _firstDate.getFullYear())) { 
93                        // not in first display month so show a previous link
94                        firstMonth = false;
95                        var lastMonth = new Date(d.getFullYear(), d.getMonth()-1, 1);
96                        var prevLink = $.A({href:'javascript:;'}, navLinks.p);
97                        $(prevLink).click(function()
98                        {
99                                $.datePicker.changeMonth(lastMonth, this);
100                                return false;
101                        });
102                        prevLinkDiv = $.DIV({className:'link-prev'}, '<', prevLink);
103                }
104               
105                var finalMonth = true;
106                var lastDate = _lastDate.getDate();
107                nextLinkDiv = '';
108                if (!(d.getMonth() == _lastDate.getMonth() && d.getFullYear() == _lastDate.getFullYear())) { 
109                        // in the last month - no next link
110                        finalMonth = false;
111                        var nextMonth = new Date(d.getFullYear(), d.getMonth()+1, 1);
112                        var nextLink = $.A({href:'javascript:;'}, navLinks.n);
113                        $(nextLink).click(function() 
114                        {
115                                $.datePicker.changeMonth(nextMonth, this);
116                                return false;
117                        });
118                        nextLinkDiv = $.DIV({className:'link-next'}, nextLink, '>');
119                }
120               
121                var closeLink = $.A({href:'javascript:;'}, navLinks.c);
122                $(closeLink).click(function()
123                {
124                        $.datePicker.closeCalendar();
125                });
126               
127                jCalDiv.append(
128                        $.DIV({className:'link-close'}, closeLink),
129                        $.H3({}, months[d.getMonth()], ' ', d.getFullYear())
130                );
131               
132                var headRow = $.TR({});
133                for (var i=0; i<7; i++) {
134                        var day = days[i];
135                        headRow.appendChild(
136                                $.TH({scope:'col', abbr:day, title:day}, day.substr(0, 1))
137                        );
138                }
139               
140                var tBody = $.TBODY();
141               
142                var lastDay = (new Date(d.getFullYear(), d.getMonth()+1, 0)).getDate();
143                var curDay = -d.getDay();
144               
145                var todayDate = (new Date()).getDate();
146                var thisMonth = d.getMonth() == today.getMonth() && d.getFullYear() == today.getFullYear();
147               
148                var w = 0;
149                while (w++<6) {
150                        var thisRow = $.TR({});
151                        for (var i=0; i<7; i++) {
152                                var atts = {};
153                               
154                                if (curDay < 0 || curDay >= lastDay) {
155                                        dayStr = ' ';
156                                } else if (firstMonth && curDay < firstDate-1) {
157                                        dayStr = curDay+1;
158                                        atts.className = 'inactive';
159                                } else if (finalMonth && curDay > lastDate-1) {
160                                        dayStr = curDay+1;
161                                        atts.className = 'inactive';
162                                } else {
163                                        d.setDate(curDay+1);
164                                        var dStr = _dateToStr(d);
165                                        dayStr = $.A({href:'#', rel:dStr}, curDay+1);
166                                        $(dayStr).click(function(e)
167                                        {
168                                                $.datePicker.selectDate($.attr(this, 'rel'), this);
169                                                return false;
170                                        });
171                                        if (_selectedDate && _selectedDate==dStr) {
172                                                $(dayStr).addClass('selected');
173                                        }
174                                }
175                               
176                                if (thisMonth && curDay+1 == todayDate) {
177                                        atts.className = 'today';
178                                }
179                                thisRow.appendChild($.TD(atts, dayStr));
180                                curDay++;
181                        }
182                        tBody.appendChild(thisRow);
183                }
184               
185                jCalDiv.append(
186                        $.TABLE({cellspacing:2}, $.THEAD({}, headRow), tBody),
187                        prevLinkDiv,
188                        nextLinkDiv
189                );
190
191                if ($.browser.msie) { 
192                       
193                        // we put a styled iframe behind the calendar so HTML SELECT elements don't show through
194                        jCalDiv.append(document.createElement('iframe'));
195
196                }
197                jCalDiv.css({'display':'block'});
198                return calDiv;
199        };
200        var _draw = function(c)
201        {
202                // explicitly empty the calendar before removing it to reduce the (MASSIVE!) memory leak in IE
203                // still not perfect but a lot better!
204                // Strangely if you chain the methods it reacts differently - when chained opening the calendar on
205                // IE uses a bunch of memory and pressing next/prev doubles this memory. When you close the calendar
206                // the memory is freed. If they aren't chained then pressing next or previous doesn't double the used
207                // memory so only one chunk of memory is used when you open the calendar (which is also freed when you
208                // close the calendar).
209                $('div.popup-calendar a', _openCal).unbind();
210                $('div.popup-calendar', _openCal).empty();
211                $('div.popup-calendar', _openCal).remove();
212                _openCal.append(c);
213        };
214        var _closeDatePicker = function()
215        {
216                $('div.popup-calendar a', _openCal).unbind();
217                $('div.popup-calendar', _openCal).empty();
218                $('div.popup-calendar', _openCal).css({'display':'none'});
219               
220                /*
221                if ($.browser.msie) {
222                        _openCal.unbind('keypress', _handleKeys);
223                } else {
224                        $(window).unbind('keypress', _handleKeys);
225                }
226                */
227                $(document).unbind('mousedown', _checkMouse);
228                delete _openCal;
229                _openCal = null;
230        };
231        var _handleKeys = function(e)
232        {
233                var key = e.keyCode ? e.keyCode : (e.which ? e.which: 0);
234                //console.log('KEY!! ' + key);
235                if (key == 27) {
236                        _closeDatePicker();
237                }
238                return false;
239        };
240        var _checkMouse = function(e)
241        {
242                var target = $.browser.msie ? window.event.srcElement : e.target;
243                var cp = $(target).findClosestParent('div.popup-calendar');
244                if (cp.get(0).className != 'date-picker-holder') {
245                        _closeDatePicker();
246                }
247        };
248       
249        return {
250                show: function()
251                {
252                        if (_openCal) {
253                                _closeDatePicker();
254                        }
255                        this.blur();
256                        var input = $('input', $(this).findClosestParent('input'))[0];
257                        _firstDate = input._startDate;
258                        _lastDate = input._endDate;
259                        _openCal = $(this).findClosestParent('div.popup-calendar');
260                        var d = $(input).val();
261                        if (d != '') {
262                                if (_dateToStr(_strToDate(d)) == d) {
263                                        _selectedDate = d;
264                                        _draw(_getCalendarDiv(_strToDate(d)));
265                                } else {
266                                        // invalid date in the input field - just default to this month
267                                        _selectedDate = false;
268                                        _draw(_getCalendarDiv());
269                                }
270                        } else {
271                                _selectedDate = false;
272                                _draw(_getCalendarDiv());
273                        }
274                        /*
275                        if ($.browser == "msie") {
276                                _openCal.bind('keypress', _handleKeys);
277                        } else {
278                                $(window).bind('keypress', _handleKeys);
279                        }
280                        */
281                        $(document).bind('mousedown', _checkMouse);
282                },
283                changeMonth: function(d, e)
284                {
285                       
286                        _draw(_getCalendarDiv(d));
287                },
288                selectDate: function(d, ele)
289                {
290                        selectedDate = d;
291                        $('input', $(ele).findClosestParent('input')).val(d);
292                        _closeDatePicker(ele);
293                },
294                closeCalendar: function()
295                {
296                        _closeDatePicker(this);
297                },
298                setInited: function(i)
299                {
300                        i._inited = true;
301                },
302                isInited: function(i)
303                {
304                        return i._inited != undefined;
305                },
306                setDateFormat: function(format)
307                {
308                        // set's the format that selected dates are returned in.
309                        // options are 'dd/mm/yyyy' (european), 'mm/dd/yyyy' (americian) and 'yyyy-mm-dd' (unicode)
310                        dateFormat = format;
311                },
312                /**
313                * Function: setLanguageStrings
314                *
315                * Allows you to localise the calendar by passing in relevant text for the english strings in the plugin.
316                *
317                * Arguments:
318                * days          -       Array, e.g. ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
319                * months        -       Array, e.g. ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
320                * navLinks      -       Object, e.g. {p:'Prev', n:'Next', c:'Close'}
321                **/
322                setLanguageStrings: function(aDays, aMonths, aNavLinks)
323                {
324                        days = aDays;
325                        months = aMonths;
326                        navLinks = aNavLinks;
327                },
328                /**
329                * Function: setDateWindow
330                *
331                * Used internally to set the start and end dates for a given date select
332                *
333                * Arguments:
334                * i                     -       The id of the INPUT element this date window is for
335                * w                     -       The date window - an object containing startDate and endDate properties
336                *                               each in the current format as set in a call to setDateFormat (or in the
337                *                               default format dd/mm/yyyy if setDateFormat hasn't been called).
338                *                               e.g. {startDate:'01/03/2006', endDate:'11/04/2006}
339                **/
340                setDateWindow: function(i, w)
341                {
342                        if (w == undefined) w = {};
343                        if (w.startDate == undefined) {
344                                i._startDate = new Date();
345                        } else {
346                                i._startDate = _strToDate(w.startDate);
347                        }
348                        if (w.endDate == undefined) {
349                                i._endDate = new Date();
350                                i._endDate.setFullYear(i._endDate.getFullYear()+5);
351                        } else {
352                                i._endDate = _strToDate(w.endDate);
353                        };
354                }
355        };
356}();
357$.fn.findClosestParent = function(s)
358{
359        var ele = this;
360        while (true) {
361                if ($(s, ele).length > 0) {
362                        return (ele);
363                }
364                ele = ele.parent();
365                if(ele[0].length == 0) {
366                        return false;
367                }
368        }
369};
370$.fn.datePicker = function(a)
371{
372        this.each(function() {
373                if(this.nodeName.toLowerCase() != 'input') return;
374                $.datePicker.setDateWindow(this, a);
375                if (!$.datePicker.isInited(this)) {
376                        var calBut = $.A({href:'javascript:;', className:'date-picker', title:'Choose date'}, $.SPAN({}, 'Choose date'));
377                        $(calBut).click($.datePicker.show);
378                        $(this).wrap(
379                                '<div class="date-picker-holder"></div>'
380                        ).before(
381                                $.DIV({className:'popup-calendar'})
382                        ).after(
383                                calBut
384                        );
385                        $.datePicker.setInited(this);
386                }
387        });
388       
389};
390/*
391<!-- Generated calendar HTML looks like this - style with CSS -->
392<div class="popup-calendar">
393        <div class="link-close"><a href="#">Close</a></div>
394        <h3>July 2006</h3>
395        <table cellspacing="2">
396                <thead>
397                        <tr>
398                                <th scope="col" abbr="Monday" title="Monday">M</th>
399                                <th scope="col" abbr="Tuesday" title="Tuesday">T</th>
400                                <th scope="col" abbr="Wednesday" title="Wednesday">W</th>
401                                <th scope="col" abbr="Thursday" title="Thursday">T</th>
402                                <th scope="col" abbr="Friday" title="Friday">F</th>
403                                <th scope="col" abbr="Saturday" title="Saturday">S</th>
404                                <th scope="col" abbr="Sunday" title="Sunday">S</th>
405                        </tr>
406                </thead>
407                <tbody>
408                        <tr>
409                                <td>&nbsp;</td>
410                                <td>&nbsp;</td>
411                                <td>&nbsp;</td>
412                                <td class="inactive">1</td>
413                                <td class="inactive">2</td>
414                                <td class="inactive">3</td>
415                                <td class="inactive">4</td>
416                        </tr>
417                        <tr>
418                                <td class="inactive">5</td>
419                                <td class="inactive">6</td>
420                                <td class="inactive">7</td>
421                                <td class="today"><a href="#">8</a></td>
422                                <td><a href="#">9</a></td>
423                                <td><a href="#">10</a></td>
424                                <td><a href="#">11</a></td>
425                        </tr>
426                        <tr>
427                                <td><a href="#">12</a></td>
428                                <td><a href="#">13</a></td>
429                                <td><a href="#">14</a></td>
430                                <td><a href="#">15</a></td>
431                                <td><a href="#">16</a></td>
432                                <td><a href="#">17</a></td>
433                                <td><a href="#" class="selected">18</a></td>
434                        </tr>
435                        <tr>
436                                <td><a href="#">19</a></td>
437                                <td><a href="#">20</a></td>
438                                <td><a href="#">21</a></td>
439                                <td><a href="#">22</a></td>
440                                <td><a href="#">23</a></td>
441                                <td><a href="#">24</a></td>
442                                <td><a href="#">25</a></td>
443                        </tr>
444                        <tr>
445                                <td><a href="#">26</a></td>
446                                <td><a href="#">27</a></td>
447                                <td><a href="#">28</a></td>
448                                <td><a href="#">29</a></td>
449                                <td><a href="#">30</a></td>
450                                <td>&nbsp;</td>
451                                <td>&nbsp;</td>
452                        </tr>
453                </tbody>
454        </table>
455        <div class="link-prev"><a href="#">Prev</a></div>
456        <div class="link-next"><a href="#">Next</a></div>
457</div>
458*/
Note: See TracBrowser for help on using the repository browser.