PluginProbe
Timed Content / 1.1
Timed Content v1.1
2.99 trunk 1.0 1.1 1.2 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.10 2.11 2.12 2.15 2.2 2.3 2.3.1 2.4 2.5 2.5.1 2.50 2.51 2.52 All 67 releases
timed-content / tinymce_plugin / js / anytime.js

anytime.js in Timed Content 1.1, at tinymce_plugin/js/anytime.js

3,657 lines 135.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*****************************************************************************
2 * FILE: anytime.js - The Any+Time(TM) JavaScript Library (source)
3 *
4 * VERSION: 4.1112G
5 *
6 * Copyright 2008-2010 Andrew M. Andrews III (www.AMA3.com). Some Rights
7 * Reserved. This work licensed under the Creative Commons Attribution-
8 * Noncommercial-Share Alike 3.0 Unported License except in jurisdicitons
9 * for which the license has been ported by Creative Commons International,
10 * where the work is licensed under the applicable ported license instead.
11 * For a copy of the unported license, visit
12 * http://creativecommons.org/licenses/by-nc-sa/3.0/
13 * or send a letter to Creative Commons, 171 Second Street, Suite 300,
14 * San Francisco, California, 94105, USA. For ported versions of the
15 * license, visit http://creativecommons.org/international/
16 *
17 * Alternative licensing arrangements may be made by contacting the
18 * author at http://www.AMA3.com/contact/
19 *
20 * The Any+Time(TM) JavaScript Library provides the following ECMAScript
21 * functionality:
22 *
23 * AnyTime.Converter
24 * Converts Dates to/from Strings, allowing a wide range of formats
25 * closely matching those provided by the MySQL DATE_FORMAT() function,
26 * with some noteworthy enhancements.
27 *
28 * AnyTime.pad()
29 * Pads a value with a specific number of leading zeroes.
30 *
31 * AnyTime.noPicker()
32 * Destroys a calendar widget previously added by AnyTime.picker().
33 * Can also be invoked via jQuery using $(selector).AnyTime_noPicker()
34 *
35 * AnyTime.picker()
36 * Attaches a calendar widget to a text field for selecting date/time
37 * values with fewer mouse movements than most similar pickers. Any
38 * format supported by AnyTime.Converter can be used for the text field.
39 * If JavaScript is disabled, the text field remains editable without
40 * any of the picker features.
41 * Can also be invoked via jQuery using $(selector).AnyTime_picker()
42 *
43 * IMPORTANT NOTICE: This code depends upon the jQuery JavaScript Library
44 * (www.jquery.com), currently version 1.4.
45 *
46 * The Any+Time(TM) code and styles in anytime.css have been tested (but not
47 * extensively) on Windows Vista in Internet Explorer 8.0, Firefox 3.0, Opera
48 * 10.10 and Safari 4.0. Minor variations in IE6+7 are to be expected, due
49 * to their broken box model. Please report any other problems to the author
50 * (URL above).
51 *
52 * Any+Time is a trademark of Andrew M. Andrews III.
53 * Thanks to Chu for help with a setMonth() issue!
54 ****************************************************************************/
55
56 var AnyTime =
57 {
58 //=============================================================================
59 // AnyTime.pad() pads a value with a specified number of zeroes and returns
60 // a string containing the padded value.
61 //=============================================================================
62
63 pad: function( val, len )
64 {
65 var str = String(Math.abs(val));
66 while ( str.length < len )
67 str = '0'+str;
68 if ( val < 0 )
69 str = '-'+str;
70 return str;
71 }
72 };
73
74 (function($)
75 {
76 // private members
77
78 var __oneDay = (24*60*60*1000);
79 var __daysIn = [ 31,28,31,30,31,30,31,31,30,31,30,31 ];
80 var __iframe = null;
81 var __initialized = false;
82 var __msie6 = ( navigator.userAgent.indexOf('MSIE 6') > 0 );
83 var __msie7 = ( navigator.userAgent.indexOf('MSIE 7') > 0 );
84 var __pickers = [];
85
86 // Add methods to jQuery to create and destroy pickers using
87 // the typical jQuery approach.
88
89 jQuery.prototype.AnyTime_picker = function( options )
90 {
91 return this.each( function(i) { AnyTime.picker( this.id, options ); } );
92 }
93
94 jQuery.prototype.AnyTime_noPicker = function()
95 {
96 return this.each( function(i) { AnyTime.noPicker( this.id ); } );
97 }
98
99 // Add special methods to jQuery to compute the height and width
100 // of picker components differently for Internet Explorer 6.x
101 // This prevents the pickers from being too tall and wide.
102
103 jQuery.prototype.AnyTime_height = function(inclusive)
104 {
105 return ( __msie6 ?
106 Number(this.css('height').replace(/[^0-9]/g,'')) :
107 this.outerHeight(inclusive) );
108 };
109
110 jQuery.prototype.AnyTime_width = function(inclusive)
111 {
112 return ( __msie6 ?
113 (1+Number(this.css('width').replace(/[^0-9]/g,''))) :
114 this.outerWidth(inclusive) );
115 };
116
117
118 // Add a method to jQuery to change the classes of an element to
119 // indicate whether it's value is current (used by AnyTime.picker),
120 // and another to trigger the click handler for the currently-
121 // selected button under an element.
122
123 jQuery.prototype.AnyTime_current = function(isCurrent,isLegal)
124 {
125 if ( isCurrent )
126 {
127 this.removeClass('AnyTime-out-btn ui-state-default ui-state-disabled ui-state-highlight');
128 this.addClass('AnyTime-cur-btn ui-state-default ui-state-highlight');
129 }
130 else
131 {
132 this.removeClass('AnyTime-cur-btn ui-state-highlight');
133 if ( ! isLegal )
134 this.addClass('AnyTime-out-btn ui-state-disabled');
135 else
136 this.removeClass('AnyTime-out-btn ui-state-disabled');
137 }
138 };
139
140 jQuery.prototype.AnyTime_clickCurrent = function()
141 {
142 this.find('.AnyTime-cur-btn').triggerHandler('click');
143 }
144
145 $(document).ready(
146 function()
147 {
148 // IE6 doesn't float popups over <select> elements unless an
149 // <iframe> is inserted between them! The <iframe> is added to
150 // the page *before* the popups are moved, so they will appear
151 // after the <iframe>.
152
153 if ( __msie6 )
154 {
155 __iframe = $('<iframe frameborder="0" scrolling="no"></iframe>');
156 __iframe.src = "javascript:'<html></html>';";
157 $(__iframe).css( {
158 display: 'block',
159 height: '1px',
160 left: '0',
161 top: '0',
162 width: '1px',
163 zIndex: 0
164 } );
165 $(document.body).append(__iframe);
166 }
167
168 // Move popup windows to the end of the page. This allows them to
169 // overcome XHTML restrictions on <table> placement enforced by MSIE.
170
171 for ( var id in __pickers )
172 if ( ! Array.prototype[id] ) // prototype.js compatibility issue
173 __pickers[id].onReady();
174
175 __initialized = true;
176
177 } ); // document.ready
178
179 //=============================================================================
180 // AnyTime.Converter
181 //
182 // This object converts between Date objects and Strings.
183 //
184 // To use AnyTime.Converter, simply create an instance for a format string,
185 // and then (repeatedly) invoke the format() and/or parse() methods to
186 // perform the conversions. For example:
187 //
188 // var converter = new AnyTime.Converter({format:'%Y-%m-%d'})
189 // var datetime = converter.parse('1967-07-30') // July 30, 1967 @ 00:00
190 // alert( converter.format(datetime) ); // outputs: 1967-07-30
191 //
192 // Constructor parameter:
193 //
194 // options - an object of optional parameters that override default behaviors.
195 // The supported options are:
196 //
197 // baseYear - the number to add to two-digit years if the %y format
198 // specifier is used. By default, AnyTime.Converter follows the
199 // MySQL assumption that two-digit years are in the range 1970 to 2069
200 // (see http://dev.mysql.com/doc/refman/5.1/en/y2k-issues.html).
201 // The most common alternatives for baseYear are 1900 and 2000.
202 //
203 // dayAbbreviations - an array of seven strings, indexed 0-6, to be used
204 // as ABBREVIATED day names. If not specified, the following are used:
205 // ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
206 // Note that if the firstDOW option is passed to AnyTime.picker() (see
207 // AnyTime.picker()), this array should nonetheless begin with the
208 // desired abbreviation for Sunday.
209 //
210 // dayNames - an array of seven strings, indexed 0-6, to be used as
211 // day names. If not specified, the following are used: ['Sunday',
212 // 'Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
213 // Note that if the firstDOW option is passed to AnyTime.picker() (see
214 // AnyTime.picker()), this array should nonetheless begin with the
215 // desired name for Sunday.
216 //
217 // eraAbbreviations - an array of two strings, indexed 0-1, to be used
218 // as ABBREVIATED era names. Item #0 is the abbreviation for "Before
219 // Common Era" (years before 0001, sometimes represented as negative
220 // years or "B.C"), while item #1 is the abbreviation for "Common Era"
221 // (years from 0001 to present, usually represented as unsigned years
222 // or years "A.D."). If not specified, the following are used:
223 // ['BCE','CE']
224 //
225 // format - a string specifying the pattern of strings involved in the
226 // conversion. The parse() method can take a string in this format and
227 // convert it to a Date, and the format() method can take a Date object
228 // and convert it to a string matching the format.
229 //
230 // Fields in the format string must match those for the DATE_FORMAT()
231 // function in MySQL, as defined here:
232 // http://tinyurl.com/bwd45#function_date-format
233 //
234 // IMPORTANT: Some MySQL specifiers are not supported (especially
235 // those involving day-of-the-year, week-of-the-year) or approximated.
236 // See the code for exact behavior.
237 //
238 // In addition to the MySQL format specifiers, the following custom
239 // specifiers are also supported:
240 //
241 // %B - If the year is before 0001, then the "Before Common Era"
242 // abbreviation (usually BCE or the obsolete BC) will go here.
243 //
244 // %C - If the year is 0001 or later, then the "Common Era"
245 // abbreviation (usually CE or the obsolete AD) will go here.
246 //
247 // %E - If the year is before 0001, then the "Before Common Era"
248 // abbreviation (usually BCE or the obsolete BC) will go here.
249 // Otherwise, the "Common Era" abbreviation (usually CE or the
250 // obsolete AD) will go here.
251 //
252 // %Z - The current four-digit year, without any sign. This is
253 // commonly used with years that might be before (or after) 0001,
254 // when the %E (or %B and %C) specifier is used instead of a sign.
255 // For example, 45 BCE is represented "0045". By comparison, in
256 // the "%Y" format, 45 BCE is represented "-0045".
257 //
258 // %z - The current year, without any sign, using only the necessary
259 // number of digits. This if the year is commonly used with years
260 // that might be before (or after) 0001, when the %E (or %B and %C)
261 // specifier is used instead of a sign. For example, the year
262 // 45 BCE is represented as "45", and the year 312 CE as "312".
263 //
264 // %# - the timezone offset, with a sign, in minutes.
265 //
266 // %+ - the timezone offset, with a sign, in hours and minutes, in
267 // four-digit, 24-hour format with no delimiter (for example, +0530).
268 // To remember the difference between %+ and %-, it might be helpful
269 // to remember that %+ might have more characters than %-.
270 //
271 // %: - the timezone offset, with a sign, in hours and minutes, in
272 // four-digit, 24-hour format with a colon delimiter (for example,
273 // +05:30). This is similar to the %z format used by Java.
274 // To remember the difference between %: and %;, it might be helpful
275 // to remember that a colon (:) has a period (.) on the bottom and
276 // a semicolon (;) has a comma (,), and in English sentence structure,
277 // a period represents a more significant stop than a comma, and
278 // %: might be a longer string than %; (I know it's a stretch, but
279 // it's easier than looking it up every time)!
280 //
281 // %- - the timezone offset, with a sign, in hours and minutes, in
282 // three-or-four-digit, 24-hour format with no delimiter (for
283 // example, +530).
284 //
285 // %; - the timezone offset, with a sign, in hours and minutes, in
286 // three-or-four-digit, 24-hour format with a colon delimiter
287 // (for example, +5:30).
288 //
289 // %@ - the timezone offset label. By default, this will be the
290 // string "UTC" followed by the offset, with a sign, in hours and
291 // minutes, in four-digit, 24-hour format with a colon delimiter
292 // (for example, UTC+05:30). However, if Any+Time(TM) has been
293 // extended with a member named utcLabel (for example, by the
294 // anytimetz.js file), then it is assumed to be an array of arrays,
295 // where the primary array is indexed by time zone offsets, and
296 // each sub-array contains a potential label for that offset.
297 // When parsing with %@, the array is scanned for matches to the
298 // input string, and if a match is found, the corresponding UTC
299 // offset is used. When formatting, the array is scanned for a
300 // matching offset, and if one is found, the first member of the
301 // sub-array is used for output (unless overridden with
302 // utcFormatOffsetSubIndex or setUtcFormatOffsetSubIndex()).
303 // If the array does not exist, or does not contain a sub-array
304 // for the offset, then the default format is used.
305 //
306 // monthAbbreviations - an array of twelve strings, indexed 0-6, to be
307 // used as ABBREVIATED month names. If not specified, the following
308 // are used: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep',
309 // 'Oct','Nov','Dec']
310 //
311 // monthNames - an array of twelve strings, indexed 0-6, to be used as
312 // month names. If not specified, the following are used:
313 // ['January','February','March','April','May','June','July',
314 // 'August','September','October','November','December']
315 //
316 // utcFormatOffsetAlleged - the offset from UTC, in minutes, to claim that
317 // a Date object represents during formatting, even though it is formatted
318 // using local time. Unlike utcFormatOffsetImposed, which actually
319 // converts the Date object to the specified different time zone, this
320 // option merely reports the alleged offset when a timezone specifier
321 // (%#, %+, %-, %:, %; %@) is encountered in the format string.
322 // This primarily exists so AnyTime.picker can edit the time as specified
323 // (without conversion to local time) and then convert the edited time to
324 // a different time zone (as selected using the picker). Any initial
325 // value specified here can be changed by setUtcFormatOffsetAlleged().
326 // If a format offset is alleged, one cannot also be imposed (the imposed
327 // offset is ignored).
328 //
329 // utcFormatOffsetImposed - the offset from UTC, in minutes, to specify when
330 // formatting a Date object. By default, a Date is always formatted
331 // using the local time zone.
332 //
333 // utcFormatOffsetSubIndex - when extending AnyTime with a utcLabel array
334 // (for example, by the anytimetz.js file), the specified sub-index is
335 // used to choose the Time Zone label for the UTC offset when formatting
336 // a Date object. This primarily exists so AnyTime.picker can specify
337 // the label selected using the picker. Any initial value specified here
338 // can be changed by setUtcFormatOffsetSubIndex().
339 //
340 // utcParseOffsetAssumed - the offset from UTC, in minutes, to assume when
341 // parsing a String object. By default, a Date is always parsed using the
342 // local time zone, unless the format string includes a timezone
343 // specifier (%#, %+, %-, %:, %; or %@), in which case the timezone
344 // specified in the string is used. The Date object created by parsing
345 // always represents local time regardless of the input time zone.
346 //
347 // utcParseOffsetCapture - if true, any parsed string is always treated as
348 // though it represents local time, and any offset specified by the string
349 // (or utcParseOffsetAssume) is captured for return by the
350 // getUtcParseOffsetCaptured() method. If the %@ format specifier is
351 // used, the sub-index of any matched label is also captured for return
352 // by the getUtcParseOffsetSubIndex() method. This primarily exists so
353 // AnyTime.picker can edit the time as specified (without conversion to
354 // local time) and then convert the edited time to a different time zone
355 // (as selected using the picker).
356 //=============================================================================
357
358 AnyTime.Converter = function(options)
359 {
360 // private members
361
362 var _flen = 0;
363 var _longDay = 9;
364 var _longMon = 9;
365 var _shortDay = 6;
366 var _shortMon = 3;
367 var _offAl = Number.MIN_VALUE; // format time zone offset alleged
368 var _offCap = Number.MIN_VALUE; // parsed time zone offset captured
369 var _offF = Number.MIN_VALUE; // format time zone offset imposed
370 var _offFSI = (-1); // format time zone label subindex
371 var _offP = Number.MIN_VALUE; // parsed time zone offset assumed
372 var _offPSI = (-1); // parsed time zone label subindex captured
373 var _captureOffset = false;
374
375 // public members
376
377 this.fmt = '%Y-%m-%d %T';
378 this.dAbbr = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
379 this.dNames = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
380 this.eAbbr = ['BCE','CE'];
381 this.mAbbr = [ 'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec' ];
382 this.mNames = [ 'January','February','March','April','May','June','July','August','September','October','November','December' ];
383 this.baseYear = null;
384
385 //-------------------------------------------------------------------------
386 // AnyTime.Converter.dAt() returns true if the character in str at pos
387 // is a digit.
388 //-------------------------------------------------------------------------
389
390 this.dAt = function( str, pos )
391 {
392 return ( (str.charCodeAt(pos)>='0'.charCodeAt(0)) &&
393 (str.charCodeAt(pos)<='9'.charCodeAt(0)) );
394 };
395
396 //-------------------------------------------------------------------------
397 // AnyTime.Converter.format() returns a String containing the value
398 // of a specified Date object, using the format string passed to
399 // AnyTime.Converter().
400 //
401 // Method parameter:
402 //
403 // date - the Date object to be converted
404 //-------------------------------------------------------------------------
405
406 this.format = function( date )
407 {
408 var d = new Date(date.getTime());
409 if ( ( _offAl == Number.MIN_VALUE ) && ( _offF != Number.MIN_VALUE ) )
410 d.setTime( ( d.getTime() + (d.getTimezoneOffset()*60000) ) + (_offF*60000) );
411
412 var t;
413 var str = '';
414 for ( var f = 0 ; f < _flen ; f++ )
415 {
416 if ( this.fmt.charAt(f) != '%' )
417 str += this.fmt.charAt(f);
418 else
419 {
420 var ch = this.fmt.charAt(f+1)
421 switch ( ch )
422 {
423 case 'a': // Abbreviated weekday name (Sun..Sat)
424 str += this.dAbbr[ d.getDay() ];
425 break;
426 case 'B': // BCE string (eAbbr[0], usually BCE or BC, only if appropriate) (NON-MYSQL)
427 if ( d.getFullYear() < 0 )
428 str += this.eAbbr[0];
429 break;
430 case 'b': // Abbreviated month name (Jan..Dec)
431 str += this.mAbbr[ d.getMonth() ];
432 break;
433 case 'C': // CE string (eAbbr[1], usually CE or AD, only if appropriate) (NON-MYSQL)
434 if ( d.getFullYear() > 0 )
435 str += this.eAbbr[1];
436 break;
437 case 'c': // Month, numeric (0..12)
438 str += d.getMonth()+1;
439 break;
440 case 'd': // Day of the month, numeric (00..31)
441 t = d.getDate();
442 if ( t < 10 ) str += '0';
443 str += String(t);
444 break;
445 case 'D': // Day of the month with English suffix (0th, 1st,...)
446 t = String(d.getDate());
447 str += t;
448 if ( ( t.length == 2 ) && ( t.charAt(0) == '1' ) )
449 str += 'th';
450 else
451 {
452 switch ( t.charAt( t.length-1 ) )
453 {
454 case '1': str += 'st'; break;
455 case '2': str += 'nd'; break;
456 case '3': str += 'rd'; break;
457 default: str += 'th'; break;
458 }
459 }
460 break;
461 case 'E': // era string (from eAbbr[], BCE, CE, BC or AD) (NON-MYSQL)
462 str += this.eAbbr[ (d.getFullYear()<0) ? 0 : 1 ];
463 break;
464 case 'e': // Day of the month, numeric (0..31)
465 str += d.getDate();
466 break;
467 case 'H': // Hour (00..23)
468 t = d.getHours();
469 if ( t < 10 ) str += '0';
470 str += String(t);
471 break;
472 case 'h': // Hour (01..12)
473 case 'I': // Hour (01..12)
474 t = d.getHours() % 12;
475 if ( t == 0 )
476 str += '12';
477 else
478 {
479 if ( t < 10 ) str += '0';
480 str += String(t);
481 }
482 break;
483 case 'i': // Minutes, numeric (00..59)
484 t = d.getMinutes();
485 if ( t < 10 ) str += '0';
486 str += String(t);
487 break;
488 case 'k': // Hour (0..23)
489 str += d.getHours();
490 break;
491 case 'l': // Hour (1..12)
492 t = d.getHours() % 12;
493 if ( t == 0 )
494 str += '12';
495 else
496 str += String(t);
497 break;
498 case 'M': // Month name (January..December)
499 str += this.mNames[ d.getMonth() ];
500 break;
501 case 'm': // Month, numeric (00..12)
502 t = d.getMonth() + 1;
503 if ( t < 10 ) str += '0';
504 str += String(t);
505 break;
506 case 'p': // AM or PM
507 str += ( ( d.getHours() < 12 ) ? 'AM' : 'PM' );
508 break;
509 case 'r': // Time, 12-hour (hh:mm:ss followed by AM or PM)
510 t = d.getHours() % 12;
511 if ( t == 0 )
512 str += '12:';
513 else
514 {
515 if ( t < 10 ) str += '0';
516 str += String(t) + ':';
517 }
518 t = d.getMinutes();
519 if ( t < 10 ) str += '0';
520 str += String(t) + ':';
521 t = d.getSeconds();
522 if ( t < 10 ) str += '0';
523 str += String(t);
524 str += ( ( d.getHours() < 12 ) ? 'AM' : 'PM' );
525 break;
526 case 'S': // Seconds (00..59)
527 case 's': // Seconds (00..59)
528 t = d.getSeconds();
529 if ( t < 10 ) str += '0';
530 str += String(t);
531 break;
532 case 'T': // Time, 24-hour (hh:mm:ss)
533 t = d.getHours();
534 if ( t < 10 ) str += '0';
535 str += String(t) + ':';
536 t = d.getMinutes();
537 if ( t < 10 ) str += '0';
538 str += String(t) + ':';
539 t = d.getSeconds();
540 if ( t < 10 ) str += '0';
541 str += String(t);
542 break;
543 case 'W': // Weekday name (Sunday..Saturday)
544 str += this.dNames[ d.getDay() ];
545 break;
546 case 'w': // Day of the week (0=Sunday..6=Saturday)
547 str += d.getDay();
548 break;
549 case 'Y': // Year, numeric, four digits (negative if before 0001)
550 str += AnyTime.pad(d.getFullYear(),4);
551 break;
552 case 'y': // Year, numeric (two digits, negative if before 0001)
553 t = d.getFullYear() % 100;
554 str += AnyTime.pad(t,2);
555 break;
556 case 'Z': // Year, numeric, four digits, unsigned (NON-MYSQL)
557 str += AnyTime.pad(Math.abs(d.getFullYear()),4);
558 break;
559 case 'z': // Year, numeric, variable length, unsigned (NON-MYSQL)
560 str += Math.abs(d.getFullYear());
561 break;
562 case '%': // A literal '%' character
563 str += '%';
564 break;
565 case '#': // signed timezone offset in minutes
566 t = ( _offAl != Number.MIN_VALUE ) ? _offAl :
567 ( _offF == Number.MIN_VALUE ) ? (0-d.getTimezoneOffset()) : _offF;
568 if ( t >= 0 )
569 str += '+';
570 str += t;
571 break;
572 case '@': // timezone offset label
573 t = ( _offAl != Number.MIN_VALUE ) ? _offAl :
574 ( _offF == Number.MIN_VALUE ) ? (0-d.getTimezoneOffset()) : _offF;
575 if ( AnyTime.utcLabel && AnyTime.utcLabel[t] )
576 {
577 if ( ( _offFSI > 0 ) && ( _offFSI < AnyTime.utcLabel[t].length ) )
578 str += AnyTime.utcLabel[t][_offFSI];
579 else
580 str += AnyTime.utcLabel[t][0];
581 break;
582 }
583 str += 'UTC';
584 ch = ':'; // drop through for offset formatting
585 case '+': // signed, 4-digit timezone offset in hours and minutes
586 case '-': // signed, 3-or-4-digit timezone offset in hours and minutes
587 case ':': // signed 4-digit timezone offset with colon delimiter
588 case ';': // signed 3-or-4-digit timezone offset with colon delimiter
589 t = ( _offAl != Number.MIN_VALUE ) ? _offAl :
590 ( _offF == Number.MIN_VALUE ) ? (0-d.getTimezoneOffset()) : _offF;
591 if ( t < 0 )
592 str += '-';
593 else
594 str += '+';
595 t = Math.abs(t);
596 str += ((ch=='+')||(ch==':')) ? AnyTime.pad(Math.floor(t/60),2) : Math.floor(t/60);
597 if ( (ch==':') || (ch==';') )
598 str += ':';
599 str += AnyTime.pad(t%60,2);
600 break;
601 case 'f': // Microseconds (000000..999999)
602 case 'j': // Day of year (001..366)
603 case 'U': // Week (00..53), where Sunday is the first day of the week
604 case 'u': // Week (00..53), where Monday is the first day of the week
605 case 'V': // Week (01..53), where Sunday is the first day of the week; used with %X
606 case 'v': // Week (01..53), where Monday is the first day of the week; used with %x
607 case 'X': // Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
608 case 'x': // Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
609 throw '%'+ch+' not implemented by AnyTime.Converter';
610 default: // for any character not listed above
611 str += this.fmt.substr(f,2);
612 } // switch ( this.fmt.charAt(f+1) )
613 f++;
614 } // else
615 } // for ( var f = 0 ; f < _flen ; f++ )
616 return str;
617
618 }; // AnyTime.Converter.format()
619
620 //-------------------------------------------------------------------------
621 // AnyTime.Converter.getUtcParseOffsetCaptured() returns the UTC offset
622 // last captured by a parsed string (or assumed by utcParseOffsetAssumed).
623 // It returns Number.MIN_VALUE if this object was not constructed with
624 // the utcParseOffsetCapture option set to true, or if an offset was not
625 // specified by the last parsed string or utcParseOffsetAssumed.
626 //-------------------------------------------------------------------------
627
628 this.getUtcParseOffsetCaptured = function()
629 {
630 return _offCap;
631 };
632
633 //-------------------------------------------------------------------------
634 // AnyTime.Converter.getUtcParseOffsetCaptured() returns the UTC offset
635 // last captured by a parsed string (or assumed by utcParseOffsetAssumed).
636 // It returns Number.MIN_VALUE if this object was not constructed with
637 // the utcParseOffsetCapture option set to true, or if an offset was not
638 // specified by the last parsed string or utcParseOffsetAssumed.
639 //-------------------------------------------------------------------------
640
641 this.getUtcParseOffsetSubIndex = function()
642 {
643 return _offPSI;
644 };
645
646 //-------------------------------------------------------------------------
647 // AnyTime.Converter.parse() returns a Date initialized from a specified
648 // string, using the format passed to AnyTime.Converter().
649 //
650 // Method parameter:
651 //
652 // str - the String object to be converted
653 //-------------------------------------------------------------------------
654
655 this.parse = function( str )
656 {
657 _offCap = _offP;
658 _offPSI = (-1);
659 var era = 1;
660 var time = new Date(0,0,1,0,0,0,0);
661 var slen = str.length;
662 var s = 0;
663 var tzSign = 1, tzOff = _offP;
664 var i, matched, sub, sublen, temp;
665 for ( var f = 0 ; f < _flen ; f++ )
666 {
667 if ( this.fmt.charAt(f) == '%' )
668 {
669 var ch = this.fmt.charAt(f+1);
670 switch ( ch )
671 {
672 case 'a': // Abbreviated weekday name (Sun..Sat)
673 matched = false;
674 for ( sublen = 0 ; s + sublen < slen ; sublen++ )
675 {
676 sub = str.substr(s,sublen);
677 for ( i = 0 ; i < 12 ; i++ )
678 if ( this.dAbbr[i] == sub )
679 {
680 matched = true;
681 s += sublen;
682 break;
683 }
684 if ( matched )
685 break;
686 } // for ( sublen ... )
687 if ( ! matched )
688 throw 'unknown weekday: '+str.substr(s);
689 break;
690 case 'B': // BCE string (eAbbr[0]), only if needed. (NON-MYSQL)
691 sublen = this.eAbbr[0].length;
692 if ( ( s + sublen <= slen ) && ( str.substr(s,sublen) == this.eAbbr[0] ) )
693 {
694 era = (-1);
695 s += sublen;
696 }
697 break;
698 case 'b': // Abbreviated month name (Jan..Dec)
699 matched = false;
700 for ( sublen = 0 ; s + sublen < slen ; sublen++ )
701 {
702 sub = str.substr(s,sublen);
703 for ( i = 0 ; i < 12 ; i++ )
704 if ( this.mAbbr[i] == sub )
705 {
706 time.setMonth( i );
707 matched = true;
708 s += sublen;
709 break;
710 }
711 if ( matched )
712 break;
713 } // for ( sublen ... )
714 if ( ! matched )
715 throw 'unknown month: '+str.substr(s);
716 break;
717 case 'C': // CE string (eAbbr[1]), only if needed. (NON-MYSQL)
718 sublen = this.eAbbr[1].length;
719 if ( ( s + sublen <= slen ) && ( str.substr(s,sublen) == this.eAbbr[1] ) )
720 s += sublen; // note: CE is the default era
721 break;
722 case 'c': // Month, numeric (0..12)
723 if ( ( s+1 < slen ) && this.dAt(str,s+1) )
724 {
725 time.setMonth( (Number(str.substr(s,2))-1)%12 );
726 s += 2;
727 }
728 else
729 {
730 time.setMonth( (Number(str.substr(s,1))-1)%12 );
731 s++;
732 }
733 break;
734 case 'D': // Day of the month with English suffix (0th,1st,...)
735 if ( ( s+1 < slen ) && this.dAt(str,s+1) )
736 {
737 time.setDate( Number(str.substr(s,2)) );
738 s += 4;
739 }
740 else
741 {
742 time.setDate( Number(str.substr(s,1)) );
743 s += 3;
744 }
745 break;
746 case 'd': // Day of the month, numeric (00..31)
747 time.setDate( Number(str.substr(s,2)) );
748 s += 2;
749 break;
750 case 'E': // era string (from eAbbr[]) (NON-MYSQL)
751 sublen = this.eAbbr[0].length;
752 if ( ( s + sublen <= slen ) && ( str.substr(s,sublen) == this.eAbbr[0] ) )
753 {
754 era = (-1);
755 s += sublen;
756 }
757 else if ( ( s + ( sublen = this.eAbbr[1].length ) <= slen ) && ( str.substr(s,sublen) == this.eAbbr[1] ) )
758 s += sublen; // note: CE is the default era
759 else
760 throw 'unknown era: '+str.substr(s);
761 break;
762 case 'e': // Day of the month, numeric (0..31)
763 if ( ( s+1 < slen ) && this.dAt(str,s+1) )
764 {
765 time.setDate( Number(str.substr(s,2)) );
766 s += 2;
767 }
768 else
769 {
770 time.setDate( Number(str.substr(s,1)) );
771 s++;
772 }
773 break;
774 case 'f': // Microseconds (000000..999999)
775 s += 6; // SKIPPED!
776 break;
777 case 'H': // Hour (00..23)
778 time.setHours( Number(str.substr(s,2)) );
779 s += 2;
780 break;
781 case 'h': // Hour (01..12)
782 case 'I': // Hour (01..12)
783 time.setHours( Number(str.substr(s,2)) );
784 s += 2;
785 break;
786 case 'i': // Minutes, numeric (00..59)
787 time.setMinutes( Number(str.substr(s,2)) );
788 s += 2;
789 break;
790 case 'k': // Hour (0..23)
791 if ( ( s+1 < slen ) && this.dAt(str,s+1) )
792 {
793 time.setHours( Number(str.substr(s,2)) );
794 s += 2;
795 }
796 else
797 {
798 time.setHours( Number(str.substr(s,1)) );
799 s++;
800 }
801 break;
802 case 'l': // Hour (1..12)
803 if ( ( s+1 < slen ) && this.dAt(str,s+1) )
804 {
805 time.setHours( Number(str.substr(s,2)) );
806 s += 2;
807 }
808 else
809 {
810 time.setHours( Number(str.substr(s,1)) );
811 s++;
812 }
813 break;
814 case 'M': // Month name (January..December)
815 matched = false;
816 for (sublen=_shortMon ; s + sublen <= slen ; sublen++ )
817 {
818 if ( sublen > _longMon )
819 break;
820 sub = str.substr(s,sublen);
821 for ( i = 0 ; i < 12 ; i++ )
822 {
823 if ( this.mNames[i] == sub )
824 {
825 time.setMonth( i );
826 matched = true;
827 s += sublen;
828 break;
829 }
830 }
831 if ( matched )
832 break;
833 }
834 break;
835 case 'm': // Month, numeric (00..12)
836 time.setMonth( (Number(str.substr(s,2))-1)%12 );
837 s += 2;
838 break;
839 case 'p': // AM or PM
840 if ( time.getHours() == 12 )
841 {
842 if ( str.charAt(s) == 'A' )
843 time.setHours(0);
844 }
845 else if ( str.charAt(s) == 'P' )
846 time.setHours( time.getHours() + 12 );
847 s += 2;
848 break;
849 case 'r': // Time, 12-hour (hh:mm:ss followed by AM or PM)
850 time.setHours(Number(str.substr(s,2)));
851 time.setMinutes(Number(str.substr(s+3,2)));
852 time.setSeconds(Number(str.substr(s+6,2)));
853 if ( time.getHours() == 12 )
854 {
855 if ( str.charAt(s) == 'A' )
856 time.setHours(0);
857 }
858 else if ( str.charAt(s) == 'P' )
859 time.setHours( time.getHours() + 12 );
860 s += 10;
861 break;
862 case 'S': // Seconds (00..59)
863 case 's': // Seconds (00..59)
864 time.setSeconds(Number(str.substr(s,2)));
865 s += 2;
866 break;
867 case 'T': // Time, 24-hour (hh:mm:ss)
868 time.setHours(Number(str.substr(s,2)));
869 time.setMinutes(Number(str.substr(s+3,2)));
870 time.setSeconds(Number(str.substr(s+6,2)));
871 s += 8;
872 break;
873 case 'W': // Weekday name (Sunday..Saturday)
874 matched = false;
875 for (sublen=_shortDay ; s + sublen <= slen ; sublen++ )
876 {
877 if ( sublen > _longDay )
878 break;
879 sub = str.substr(s,sublen);
880 for ( i = 0 ; i < 7 ; i++ )
881 {
882 if ( this.dNames[i] == sub )
883 {
884 matched = true;
885 s += sublen;
886 break;
887 }
888 }
889 if ( matched )
890 break;
891 }
892 break;
893 case 'w': // Day of the week (0=Sunday..6=Saturday) (ignored)
894 s += 1;
895 break;
896 case 'Y': // Year, numeric, four digits, negative if before 0001
897 i = 4;
898 if ( str.substr(s,1) == '-' )
899 i++;
900 time.setFullYear(Number(str.substr(s,i)));
901 s += i;
902 break;
903 case 'y': // Year, numeric (two digits), negative before baseYear
904 i = 2;
905 if ( str.substr(s,1) == '-' )
906 i++;
907 temp = Number(str.substr(s,i));
908 if ( typeof(this.baseYear) == 'number' )
909 temp += this.baseYear;
910 else if ( temp < 70 )
911 temp += 2000;
912 else
913 temp += 1900;
914 time.setFullYear(temp);
915 s += i;
916 break;
917 case 'Z': // Year, numeric, four digits, unsigned (NON-MYSQL)
918 time.setFullYear(Number(str.substr(s,4)));
919 s += 4;
920 break;
921 case 'z': // Year, numeric, variable length, unsigned (NON-MYSQL)
922 i = 0;
923 while ( ( s < slen ) && this.dAt(str,s) )
924 i = ( i * 10 ) + Number(str.charAt(s++));
925 time.setFullYear(i);
926 break;
927 case '#': // signed timezone offset in minutes.
928 if ( str.charAt(s++) == '-' )
929 tzSign = (-1);
930 for ( tzOff = 0 ; ( s < slen ) && (String(i=Number(str.charAt(s)))==str.charAt(s)) ; s++ )
931 tzOff = ( tzOff * 10 ) + i;
932 tzOff *= tzSign;
933 break;
934 case '@': // timezone label
935 _offPSI = (-1);
936 if ( AnyTime.utcLabel )
937 {
938 matched = false;
939 for ( tzOff in AnyTime.utcLabel )
940 if ( ! Array.prototype[tzOff] ) // prototype.js compatibility issue
941 {
942 for ( i = 0 ; i < AnyTime.utcLabel[tzOff].length ; i++ )
943 {
944 sub = AnyTime.utcLabel[tzOff][i];
945 sublen = sub.length;
946 if ( ( s+sublen <= slen ) && ( str.substr(s,sublen) == sub ) )
947 {
948 s+=sublen;
949 matched = true;
950 break;
951 }
952 }
953 if ( matched )
954 break;
955 }
956 if ( matched )
957 {
958 _offPSI = i;
959 tzOff = Number(tzOff);
960 break; // case
961 }
962 }
963 if ( ( s+9 < slen ) || ( str.substr(s,3) != "UTC" ) )
964 throw 'unknown time zone: '+str.substr(s);
965 s += 3;
966 ch = ':'; // drop through for offset parsing
967 case '-': // signed, 3-or-4-digit timezone offset in hours and minutes
968 case '+': // signed, 4-digit timezone offset in hours and minutes
969 case ':': // signed 4-digit timezone offset with colon delimiter
970 case ';': // signed 3-or-4-digit timezone offset with colon delimiter
971 if ( str.charAt(s++) == '-' )
972 tzSign = (-1);
973 tzOff = Number(str.charAt(s));
974 if ( (ch=='+')||(ch==':')||((s+3<slen)&&(String(Number(str.charAt(s+3)))!==str.charAt(s+3))) )
975 tzOff = (tzOff*10) + Number(str.charAt(++s));
976 tzOff *= 60;
977 if ( (ch==':') || (ch==';') )
978 s++; // skip ":" (assumed)
979 tzOff = ( tzOff + Number(str.substr(++s,2)) ) * tzSign;
980 s += 2;
981 break;
982 case 'j': // Day of year (001..366)
983 case 'U': // Week (00..53), where Sunday is the first day of the week
984 case 'u': // Week (00..53), where Monday is the first day of the week
985 case 'V': // Week (01..53), where Sunday is the first day of the week; used with %X
986 case 'v': // Week (01..53), where Monday is the first day of the week; used with %x
987 case 'X': // Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
988 case 'x': // Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
989 throw '%'+this.fmt.charAt(f+1)+' not implemented by AnyTime.Converter';
990 case '%': // A literal '%' character
991 default: // for any character not listed above
992 throw '%'+this.fmt.charAt(f+1)+' reserved for future use';
993 break;
994 }
995 f++;
996 } // if ( this.fmt.charAt(f) == '%' )
997 else if ( this.fmt.charAt(f) != str.charAt(s) )
998 throw str + ' is not in "' + this.fmt + '" format';
999 else
1000 s++;
1001 } // for ( var f ... )
1002 if ( era < 0 )
1003 time.setFullYear( 0 - time.getFullYear() );
1004 if ( tzOff != Number.MIN_VALUE )
1005 {
1006 if ( _captureOffset )
1007 _offCap = tzOff;
1008 else
1009 time.setTime( ( time.getTime() - (tzOff*60000) ) - (time.getTimezoneOffset()*60000) );
1010 }
1011
1012 return time;
1013
1014 }; // AnyTime.Converter.parse()
1015
1016 //-------------------------------------------------------------------------
1017 // AnyTime.Converter.setUtcFormatOffsetAlleged() sets the offset from
1018 // UTC, in minutes, to claim that a Date object represents during
1019 // formatting, even though it is formatted using local time. This merely
1020 // reports the alleged offset when a timezone specifier (%#, %+, %-, %:,
1021 // %; or %@) is encountered in the format string--it does not otherwise
1022 // affect the date/time value. This primarily exists so AnyTime.picker
1023 // can edit the time as specified (without conversion to local time) and
1024 // then convert the edited time to a different time zone (as selected
1025 // using the picker). This method returns the previous value, if any,
1026 // set by the utcFormatOffsetAlleged option, or a previous call to
1027 // setUtcFormatOffsetAlleged(), or Number.MIN_VALUE if no offset was
1028 // previously-alleged. Call this method with Number.MIN_VALUE to cancel
1029 // any prior value. Note that if a format offset is alleged, any offset
1030 // specified by option utcFormatOffsetImposed is ignored.
1031 //-------------------------------------------------------------------------
1032
1033 this.setUtcFormatOffsetAlleged = function( offset )
1034 {
1035 var prev = _offAl;
1036 _offAl = offset;
1037 return prev;
1038 };
1039
1040 //-------------------------------------------------------------------------
1041 // AnyTime.Converter.setUtcFormatOffsetSubIndex() sets the sub-index
1042 // to choose from the AnyTime.utcLabel array of arrays when formatting
1043 // a Date using the %@ specifier. For more information, see option
1044 // AnyTime.Converter.utcFormatOffsetSubIndex. This primarily exists so
1045 // AnyTime.picker can specify the Time Zone label selected using the
1046 // picker). This method returns the previous value, if any, set by the
1047 // utcFormatOffsetSubIndex option, or a previous call to
1048 // setUtcFormatOffsetAlleged(), or (-1) if no sub-index was previously-
1049 // chosen. Call this method with (-1) to cancel any prior value.
1050 //-------------------------------------------------------------------------
1051
1052 this.setUtcFormatOffsetSubIndex = function( subIndex )
1053 {
1054 var prev = _offFSI;
1055 _offFSI = subIndex;
1056 return prev;
1057 };
1058
1059 //-------------------------------------------------------------------------
1060 // AnyTime.Converter construction code:
1061 //-------------------------------------------------------------------------
1062
1063 (function(_this)
1064 {
1065 var i, len;
1066
1067 options = jQuery.extend(true,{},options||{});
1068
1069 if ( options.baseYear )
1070 _this.baseYear = Number(options.baseYear);
1071
1072 if ( options.format )
1073 _this.fmt = options.format;
1074
1075 _flen = _this.fmt.length;
1076
1077 if ( options.dayAbbreviations )
1078 _this.dAbbr = $.makeArray( options.dayAbbreviations );
1079
1080 if ( options.dayNames )
1081 {
1082 _this.dNames = $.makeArray( options.dayNames );
1083 _longDay = 1;
1084 _shortDay = 1000;
1085 for ( i = 0 ; i < 7 ; i++ )
1086 {
1087 len = _this.dNames[i].length;
1088 if ( len > _longDay )
1089 _longDay = len;
1090 if ( len < _shortDay )
1091 _shortDay = len;
1092 }
1093 }
1094
1095 if ( options.eraAbbreviations )
1096 _this.eAbbr = $.makeArray(options.eraAbbreviations);
1097
1098 if ( options.monthAbbreviations )
1099 _this.mAbbr = $.makeArray(options.monthAbbreviations);
1100
1101 if ( options.monthNames )
1102 {
1103 _this.mNames = $.makeArray( options.monthNames );
1104 _longMon = 1;
1105 _shortMon = 1000;
1106 for ( i = 0 ; i < 12 ; i++ )
1107 {
1108 len = _this.mNames[i].length;
1109 if ( len > _longMon )
1110 _longMon = len;
1111 if ( len < _shortMon )
1112 _shortMon = len;
1113 }
1114 }
1115
1116 if ( typeof options.utcFormatOffsetImposed != "undefined" )
1117 _offF = options.utcFormatOffsetImposed;
1118
1119 if ( typeof options.utcParseOffsetAssumed != "undefined" )
1120 _offP = options.utcParseOffsetAssumed;
1121
1122 if ( options.utcParseOffsetCapture )
1123 _captureOffset = true;
1124
1125 })(this); // AnyTime.Converter construction
1126
1127 }; // AnyTime.Converter =
1128
1129 //=============================================================================
1130 // AnyTime.noPicker()
1131 //
1132 // Removes the date/time entry picker attached to a specified text field.
1133 //=============================================================================
1134
1135 AnyTime.noPicker = function( id )
1136 {
1137 if ( __pickers[id] )
1138 {
1139 __pickers[id].cleanup();
1140 delete __pickers[id];
1141 }
1142 };
1143
1144 //=============================================================================
1145 // AnyTime.picker()
1146 //
1147 // Creates a date/time entry picker attached to a specified text field.
1148 // Instead of entering a date and/or time into the text field, the user
1149 // selects legal combinations using the picker, and the field is auto-
1150 // matically populated. The picker can be incorporated into the page
1151 // "inline", or used as a "popup" that appears when the text field is
1152 // clicked and disappears when the picker is dismissed. Ajax can be used
1153 // to send the selected value to a server to approve or veto it.
1154 //
1155 // To create a picker, simply include the necessary files in an HTML page
1156 // and call the function for each date/time input field. The following
1157 // example creates a popup picker for field "foo" using the default
1158 // format, and a second date-only (no time) inline (always-visible)
1159 // Ajax-enabled picker for field "bar":
1160 //
1161 // <link rel="stylesheet" type="text/css" href="anytime.css" />
1162 // <script type="text/javascript" src="jquery.js"></script>
1163 // <script type="text/javascript" src="anytime.js"></script>
1164 // <input type="text" id="foo" tabindex="1" value="1967-07-30 23:45" />
1165 // <input type="text" id="bar" tabindex="2" value="01/06/90" />
1166 // <script type="text/javascript">
1167 // AnyTime.picker( "foo" );
1168 // AnyTime.picker( "bar", { placement:"inline", format: "%m/%d/%y",
1169 // ajaxOptions { url: "/some/server/page/" } } );
1170 // </script>
1171 //
1172 // The appearance of the picker can be extensively modified using CSS styles.
1173 // A default appearance can be achieved by the "anytime.css" stylesheet that
1174 // accompanies this script. The default style looks better in browsers other
1175 // than Internet Explorer (before IE8) because older versions of IE do not
1176 // properly implement the CSS box model standard; however, it is passable in
1177 // Internet Explorer as well.
1178 //
1179 // Method parameters:
1180 //
1181 // id - the "id" attribute of the textfield to associate with the
1182 // AnyTime.picker object. The AnyTime.picker will attach itself
1183 // to the textfield and manage its value.
1184 //
1185 // options - an object (associative array) of optional parameters that
1186 // override default behaviors. The supported options are:
1187 //
1188 // ajaxOptions - options passed to jQuery's $.ajax() method whenever
1189 // the user dismisses a popup picker or selects a value in an inline
1190 // picker. The input's name (or ID) and value are passed to the
1191 // server (appended to ajaxOptions.data, if present), and the
1192 // "success" handler sets the input's value to the responseText.
1193 // Therefore, the text returned by the server must be valid for the
1194 // input'sdate/time format, and the server can approve or veto the
1195 // value chosen by the user. For more information, see:
1196 // http://docs.jquery.com/Ajax.
1197 // If ajaxOptions.success is specified, it is used instead of the
1198 // default "success" behavior.
1199 //
1200 // askEra - if true, buttons to select the era are shown on the year
1201 // selector popup, even if format specifier does not include the
1202 // era. If false, buttons to select the era are NOT shown, even
1203 // if the format specifier includes ther era. Normally, era buttons
1204 // are only shown if the format string specifies the era.
1205 //
1206 // askSecond - if false, buttons for number-of-seconds are not shown
1207 // even if the format includes seconds. Normally, the buttons
1208 // are shown if the format string includes seconds.
1209 //
1210 // earliest - String or Date object representing the earliest date/time
1211 // that a user can select. For best results if the field is only
1212 // used to specify a date, be sure to set the time to 00:00:00.
1213 // If a String is used, it will be parsed according to the picker's
1214 // format (see AnyTime.Converter.format()).
1215 //
1216 // firstDOW - a value from 0 (Sunday) to 6 (Saturday) stating which
1217 // day should appear at the beginning of the week. The default is 0
1218 // (Sunday). The most common substitution is 1 (Monday). Note that
1219 // if custom arrays are specified for AnyTime.Converter's dayAbbreviations
1220 // and/or dayNames options, they should nonetheless begin with the
1221 // value for Sunday.
1222 //
1223 // hideInput - if true, the <input> is "hidden" (the picker appears in
1224 // its place). This actually sets the border, height, margin, padding
1225 // and width of the field as small as possivle, so it can still get focus.
1226 // If you try to hide the field using traditional techniques (such as
1227 // setting "display:none"), the picker will not behave correctly.
1228 //
1229 // labelDayOfMonth - the label for the day-of-month "buttons".
1230 // Can be any HTML! If not specified, "Day of Month" is assumed.
1231 //
1232 // labelDismiss - the label for the dismiss "button" (if placement is
1233 // "popup"). Can be any HTML! If not specified, "X" is assumed.
1234 //
1235 // labelHour - the label for the hour "buttons".
1236 // Can be any HTML! If not specified, "Hour" is assumed.
1237 //
1238 // labelMinute - the label for the minute "buttons".
1239 // Can be any HTML! If not specified, "Minute" is assumed.
1240 //
1241 // labelMonth - the label for the month "buttons".
1242 // Can be any HTML! If not specified, "Month" is assumed.
1243 //
1244 // labelTimeZone - the label for the UTC offset (timezone) "buttons".
1245 // Can be any HTML! If not specified, "Time Zone" is assumed.
1246 //
1247 // labelSecond - the label for the second "buttons".
1248 // Can be any HTML! If not specified, "Second" is assumed.
1249 // This option is ignored if askSecond is false!
1250 //
1251 // labelTitle - the label for the "title bar". Can be any HTML!
1252 // If not specified, then whichever of the following is most
1253 // appropriate is used: "Select a Date and Time", "Select a Date"
1254 // or "Select a Time", or no label if only one field is present.
1255 //
1256 // labelYear - the label for the year "buttons".
1257 // Can be any HTML! If not specified, "Year" is assumed.
1258 //
1259 // latest - String or Date object representing the latest date/time
1260 // that a user can select. For best results if the field is only
1261 // used to specify a date, be sure to set the time to 23:59:59.
1262 // If a String is used, it will be parsed according to the picker's
1263 // format (see AnyTime.Converter.format()).
1264 //
1265 // placement - One of the following strings:
1266 //
1267 // "popup" = the picker appears above its <input> when the input
1268 // receives focus, and disappears when it is dismissed. This is
1269 // the default behavior.
1270 //
1271 // "inline" = the picker is placed immediately after the <input>
1272 // and remains visible at all times. When choosing this placement,
1273 // it is best to make the <input> invisible and use only the
1274 // picker to select dates. The <input> value can still be used
1275 // during form submission as it will always reflect the current
1276 // picker state.
1277 //
1278 // WARNING: when using "inline" and XHTML and including a day-of-
1279 // the-month format field, the input may only appear where a <table>
1280 // element is permitted (for example, NOT within a <p> element).
1281 // This is because the picker uses a <table> element to arrange
1282 // the day-of-the-month (calendar) buttons. Failure to follow this
1283 // advice may result in an "unknown error" in Internet Explorer.
1284 //
1285 // The following additional options may be specified; see documentation
1286 // for AnyTime.Converter (above) for information about these options:
1287 //
1288 // baseYear
1289 // dayAbbreviations
1290 // dayNames
1291 // eraAbbreviations
1292 // format
1293 // monthAbbreviations
1294 // monthNames
1295 //
1296 // Other behavior, such as how to format the values on the display
1297 // and which "buttons" to include, is inferred from the format string.
1298 //=============================================================================
1299
1300 AnyTime.picker = function( id, options )
1301 {
1302 // Create a new private object instance to manage the picker,
1303 // if one does not already exist.
1304
1305 if ( __pickers[id] )
1306 throw 'Cannot create another AnyTime picker for "'+id+'"';
1307
1308 var _this = null;
1309
1310 __pickers[id] =
1311 {
1312 // private members
1313
1314 twelveHr: false,
1315 ajaxOpts: null, // options for AJAX requests
1316 denyTab: true, // set to true to stop Opera from tabbing away
1317 askEra: false, // prompt the user for the era in yDiv?
1318 cloak: null, // cloak div
1319 conv: null, // AnyTime.Converter
1320 bMinW: 0, // min width of body div
1321 bMinH: 0, // min height of body div
1322 dMinW: 0, // min width of date div
1323 dMinH: 0, // min height of date div
1324 div: null, // picker div
1325 dB: null, // body div
1326 dD: null, // date div
1327 dY: null, // years div
1328 dMo: null, // months div
1329 dDoM: null, // date-of-month table
1330 hDoM: null, // date-of-month heading
1331 hMo: null, // month heading
1332 hTitle: null, // title heading
1333 hY: null, // year heading
1334 dT: null, // time div
1335 dH: null, // hours div
1336 dM: null, // minutes div
1337 dS: null, // seconds div
1338 dO: null, // offset (time zone) div
1339 earliest: null, // earliest selectable date/time
1340 fBtn: null, // button with current focus
1341 fDOW: 0, // index to use as first day-of-week
1342 hBlur: null, // input handler
1343 hClick: null, // input handler
1344 hFocus: null, // input handler
1345 hKeydown: null, // input handler
1346 hKeypress: null, // input handler
1347 id: null, // picker ID
1348 inp: null, // input text field
1349 latest: null, // latest selectable date/time
1350 lastAjax: null, // last value submitted using AJAX
1351 lostFocus: false, // when focus is lost, must redraw
1352 lX: 'X', // label for dismiss button
1353 lY: 'Year', // label for year
1354 lO: 'Time Zone', // label for UTC offset (time zone)
1355 oBody: null, // UTC offset selector popup
1356 oConv: null, // AnyTime.Converter for offset display
1357 oCur: null, // current-UTC-offset button
1358 oDiv: null, // UTC offset selector popup
1359 oLab: null, // UTC offset label
1360 oListMinW: 0, // min width of offset list element
1361 oMinW: 0, // min width of UTC offset element
1362 oSel: null, // select (plus/minus) UTC-offset button
1363 offMin: Number.MIN_VALUE, // current UTC offset in minutes
1364 offSI: -1, // current UTC label sub-index (if any)
1365 offStr: "", // current UTC offset (time zone) string
1366 pop: true, // picker is a popup?
1367 time: null, // current date/time
1368 tMinW: 0, // min width of time div
1369 tMinH: 0, // min height of time div
1370 url: null, // URL to submit value using AJAX
1371 wMinW: 0, // min width of picker
1372 wMinH: 0, // min height of picker
1373 yAhead: null, // years-ahead button
1374 y0XXX: null, // millenium-digit-zero button (for focus)
1375 yCur: null, // current-year button
1376 yDiv: null, // year selector popup
1377 yLab: null, // year label
1378 yNext: null, // next-year button
1379 yPast: null, // years-past button
1380 yPrior: null, // prior-year button
1381
1382 //---------------------------------------------------------------------
1383 // .initialize() initializes the picker instance.
1384 //---------------------------------------------------------------------
1385
1386 initialize: function( id )
1387 {
1388 _this = this;
1389
1390 this.id = 'AnyTime--'+id.replace(/[^-_.A-Za-z0-9]/g,'--AnyTime--');
1391
1392 options = jQuery.extend(true,{},options||{});
1393 options.utcParseOffsetCapture = true;
1394 this.conv = new AnyTime.Converter(options);
1395
1396 if ( options.placement )
1397 {
1398 if ( options.placement == 'inline' )
1399 this.pop = false;
1400 else if ( options.placement != 'popup' )
1401 throw 'unknown placement: ' + options.placement;
1402 }
1403
1404 if ( options.ajaxOptions )
1405 {
1406 this.ajaxOpts = jQuery.extend( {}, options.ajaxOptions );
1407 if ( ! this.ajaxOpts.success )
1408 this.ajaxOpts.success = function(data,status) { _this.inp.val(data); };
1409 }
1410
1411 if ( options.earliest )
1412 {
1413 if ( typeof options.earliest.getTime == 'function' )
1414 this.earliest = options.earliest.getTime();
1415 else
1416 this.earliest = this.conv.parse( options.earliest.toString() );
1417 }
1418
1419 if ( options.firstDOW )
1420 {
1421 if ( ( options.firstDOW < 0 ) || ( options.firstDOW > 6 ) )
1422 throw new Exception('illegal firstDOW: ' + options.firstDOW);
1423 this.fDOW = options.firstDOW;
1424 }
1425
1426 if ( options.latest )
1427 {
1428 if ( typeof options.latest.getTime == 'function' )
1429 this.latest = options.latest.getTime();
1430 else
1431 this.latest = this.conv.parse( options.latest.toString() );
1432 }
1433
1434 this.lX = options.labelDismiss || 'X';
1435 this.lY = options.labelYear || 'Year';
1436 this.lO = options.labelTimeZone || 'Time Zone';
1437
1438 // Infer what we can about what to display from the format.
1439
1440 var i;
1441 var t;
1442 var lab;
1443 var shownFields = 0;
1444 var format = this.conv.fmt;
1445
1446 if ( typeof options.askEra != 'undefined' )
1447 this.askEra = options.askEra;
1448 else
1449 this.askEra = (format.indexOf('%B')>=0) || (format.indexOf('%C')>=0) || (format.indexOf('%E')>=0);
1450 var askYear = (format.indexOf('%Y')>=0) || (format.indexOf('%y')>=0) || (format.indexOf('%Z')>=0) || (format.indexOf('%z')>=0);
1451 var askMonth = (format.indexOf('%b')>=0) || (format.indexOf('%c')>=0) || (format.indexOf('%M')>=0) || (format.indexOf('%m')>=0);
1452 var askDoM = (format.indexOf('%D')>=0) || (format.indexOf('%d')>=0) || (format.indexOf('%e')>=0);
1453 var askDate = askYear || askMonth || askDoM;
1454 this.twelveHr = (format.indexOf('%h')>=0) || (format.indexOf('%I')>=0) || (format.indexOf('%l')>=0) || (format.indexOf('%r')>=0);
1455 var askHour = this.twelveHr || (format.indexOf('%H')>=0) || (format.indexOf('%k')>=0) || (format.indexOf('%T')>=0);
1456 var askMinute = (format.indexOf('%i')>=0) || (format.indexOf('%r')>=0) || (format.indexOf('%T')>=0);
1457 var askSec = ( (format.indexOf('%r')>=0) || (format.indexOf('%S')>=0) || (format.indexOf('%s')>=0) || (format.indexOf('%T')>=0) );
1458 if ( askSec && ( typeof options.askSecond != 'undefined' ) )
1459 askSec = options.askSecond;
1460 var askOff = ( (format.indexOf('%#')>=0) || (format.indexOf('%+')>=0) || (format.indexOf('%-')>=0) || (format.indexOf('%:')>=0) || (format.indexOf('%;')>=0) || (format.indexOf('%<')>=0) || (format.indexOf('%>')>=0) || (format.indexOf('%@')>=0) );
1461 var askTime = askHour || askMinute || askSec || askOff;
1462
1463 if ( askOff )
1464 this.oConv = new AnyTime.Converter( { format: options.formatUtcOffset ||
1465 format.match(/\S*%[-+:;<>#@]\S*/g).join(' ') } );
1466
1467 // Create the picker HTML and add it to the page.
1468 // Popup pickers will be moved to the end of the body
1469 // once the entire page has loaded.
1470
1471 this.inp = $(document.getElementById(id)); // avoids ID-vs-pseudo-selector probs like id="foo:bar"
1472 this.div = $( '<div class="AnyTime-win AnyTime-pkr ui-widget ui-widget-content ui-corner-all" style="width:0;height:0" id="' + this.id + '" aria-live="off"/>' );
1473 this.inp.after(this.div);
1474 this.wMinW = this.div.outerWidth(!$.browser.safari);
1475 this.wMinH = this.div.AnyTime_height(true);
1476 this.hTitle = $( '<h5 class="AnyTime-hdr ui-widget-header ui-corner-top"/>' );
1477 this.div.append( this.hTitle );
1478 this.dB = $( '<div class="AnyTime-body" style="width:0;height:0"/>' );
1479 this.div.append( this.dB );
1480 this.bMinW = this.dB.outerWidth(true);
1481 this.bMinH = this.dB.AnyTime_height(true);
1482
1483 if ( options.hideInput )
1484 this.inp.css({border:0,height:'1px',margin:0,padding:0,width:'1px'});
1485
1486 // Add dismiss box to title (if popup)
1487
1488 t = null;
1489 var xDiv = null;
1490 if ( this.pop )
1491 {
1492 xDiv = $( '<div class="AnyTime-x-btn ui-state-default">'+this.lX+'</div>' );
1493 this.hTitle.append( xDiv );
1494 xDiv.click(function(e){_this.dismiss(e);});
1495 }
1496
1497 // date (calendar) portion
1498
1499 lab = '';
1500 if ( askDate )
1501 {
1502 this.dD = $( '<div class="AnyTime-date" style="width:0;height:0"/>' );
1503 this.dB.append( this.dD );
1504 this.dMinW = this.dD.outerWidth(true);
1505 this.dMinH = this.dD.AnyTime_height(true);
1506
1507 if ( askYear )
1508 {
1509 this.yLab = $('<h6 class="AnyTime-lbl AnyTime-lbl-yr">' + this.lY + '</h6>');
1510 this.dD.append( this.yLab );
1511
1512 this.dY = $( '<ul class="AnyTime-yrs ui-helper-reset" />' );
1513 this.dD.append( this.dY );
1514
1515 this.yPast = this.btn(this.dY,'&lt;',this.newYear,['yrs-past'],'- '+this.lY);
1516 this.yPrior = this.btn(this.dY,'1',this.newYear,['yr-prior'],'-1 '+this.lY);
1517 this.yCur = this.btn(this.dY,'2',this.newYear,['yr-cur'],this.lY);
1518 this.yCur.removeClass('ui-state-default');
1519 this.yCur.addClass('AnyTime-cur-btn ui-state-default ui-state-highlight');
1520
1521 this.yNext = this.btn(this.dY,'3',this.newYear,['yr-next'],'+1 '+this.lY);
1522 this.yAhead = this.btn(this.dY,'&gt;',this.newYear,['yrs-ahead'],'+ '+this.lY);
1523
1524 shownFields++;
1525
1526 } // if ( askYear )
1527
1528 if ( askMonth )
1529 {
1530 lab = options.labelMonth || 'Month';
1531 this.hMo = $( '<h6 class="AnyTime-lbl AnyTime-lbl-month">' + lab + '</h6>' );
1532 this.dD.append( this.hMo );
1533 this.dMo = $('<ul class="AnyTime-mons" />');
1534 this.dD.append(this.dMo);
1535 for ( i = 0 ; i < 12 ; i++ )
1536 {
1537 var mBtn = this.btn( this.dMo, this.conv.mAbbr[i],
1538 function( event )
1539 {
1540 var elem = $(event.target);
1541 if ( elem.hasClass("AnyTime-out-btn") )
1542 return;
1543 var mo = event.target.AnyTime_month;
1544 var t = new Date(this.time.getTime());
1545 if ( t.getDate() > __daysIn[mo] )
1546 t.setDate(__daysIn[mo])
1547 t.setMonth(mo);
1548 this.set(t);
1549 this.upd(elem);
1550 },
1551 ['mon','mon'+String(i+1)], lab+' '+this.conv.mNames[i] );
1552 mBtn[0].AnyTime_month = i;
1553 }
1554 shownFields++;
1555 }
1556
1557 if ( askDoM )
1558 {
1559 lab = options.labelDayOfMonth || 'Day of Month';
1560 this.hDoM = $('<h6 class="AnyTime-lbl AnyTime-lbl-dom">' + lab + '</h6>' );
1561 this.dD.append( this.hDoM );
1562 this.dDoM = $( '<table border="0" cellpadding="0" cellspacing="0" class="AnyTime-dom-table"/>' );
1563 this.dD.append( this.dDoM );
1564 t = $( '<thead class="AnyTime-dom-head"/>' );
1565 this.dDoM.append(t);
1566 var tr = $( '<tr class="AnyTime-dow"/>' );
1567 t.append(tr);
1568 for ( i = 0 ; i < 7 ; i++ )
1569 tr.append( '<th class="AnyTime-dow AnyTime-dow'+String(i+1)+'">'+this.conv.dAbbr[(this.fDOW+i)%7]+'</th>' );
1570
1571 var tbody = $( '<tbody class="AnyTime-dom-body" />' );
1572 this.dDoM.append(tbody);
1573 for ( var r = 0 ; r < 6 ; r++ )
1574 {
1575 tr = $( '<tr class="AnyTime-wk AnyTime-wk'+String(r+1)+'"/>' );
1576 tbody.append(tr);
1577 for ( i = 0 ; i < 7 ; i++ )
1578 this.btn( tr, 'x',
1579 function( event )
1580 {
1581 var elem = $(event.target);
1582 if ( elem.hasClass("AnyTime-out-btn") )
1583 return;
1584 var dom = Number(elem.html());
1585 if ( dom )
1586 {
1587 var t = new Date(this.time.getTime());
1588 t.setDate(dom);
1589 this.set(t);
1590 this.upd(elem);
1591 }
1592 },
1593 ['dom'], lab );
1594 }
1595 shownFields++;
1596
1597 } // if ( askDoM )
1598
1599 } // if ( askDate )
1600
1601 // time portion
1602
1603 if ( askTime )
1604 {
1605 var tensDiv, onesDiv;
1606
1607 this.dT = $('<div class="AnyTime-time" style="width:0;height:0" />');
1608 this.dB.append(this.dT);
1609 this.tMinW = this.dT.outerWidth(true);
1610 this.tMinH = this.dT.AnyTime_height(true);
1611
1612 if ( askHour )
1613 {
1614 this.dH = $('<div class="AnyTime-hrs"/>');
1615 this.dT.append(this.dH);
1616
1617 lab = options.labelHour || 'Hour';
1618 this.dH.append( $('<h6 class="AnyTime-lbl AnyTime-lbl-hr">'+lab+'</h6>') );
1619 var amDiv = $('<ul class="AnyTime-hrs-am"/>');
1620 this.dH.append( amDiv );
1621 var pmDiv = $('<ul class="AnyTime-hrs-pm"/>');
1622 this.dH.append( pmDiv );
1623
1624 for ( i = 0 ; i < 12 ; i++ )
1625 {
1626 if ( this.twelveHr )
1627 {
1628 if ( i == 0 )
1629 t = '12am';
1630 else
1631 t = String(i)+'am';
1632 }
1633 else
1634 t = AnyTime.pad(i,2);
1635
1636 this.btn( amDiv, t, this.newHour,['hr','hr'+String(i)],lab+' '+t);
1637
1638 if ( this.twelveHr )
1639 {
1640 if ( i == 0 )
1641 t = '12pm';
1642 else
1643 t = String(i)+'pm';
1644 }
1645 else
1646 t = i+12;
1647
1648 this.btn( pmDiv, t, this.newHour,['hr','hr'+String(i+12)],lab+' '+t);
1649 }
1650
1651 shownFields++;
1652
1653 } // if ( askHour )
1654
1655 if ( askMinute )
1656 {
1657 this.dM = $('<div class="AnyTime-mins"/>');
1658 this.dT.append(this.dM);
1659
1660 lab = options.labelMinute || 'Minute';
1661 this.dM.append( $('<h6 class="AnyTime-lbl AnyTime-lbl-min">'+lab+'</h6>') );
1662 tensDiv = $('<ul class="AnyTime-mins-tens"/>');
1663 this.dM.append(tensDiv);
1664
1665 for ( i = 0 ; i < 6 ; i++ )
1666 this.btn( tensDiv, i,
1667 function( event )
1668 {
1669 var elem = $(event.target);
1670 if ( elem.hasClass("AnyTime-out-btn") )
1671 return;
1672 var t = new Date(this.time.getTime());
1673 t.setMinutes( (Number(elem.text())*10) + (this.time.getMinutes()%10) );
1674 this.set(t);
1675 this.upd(elem);
1676 },
1677 ['min-ten','min'+i+'0'], lab+' '+i+'0' );
1678 for ( ; i < 12 ; i++ )
1679 this.btn( tensDiv, '&#160;', $.noop, ['min-ten','min'+i+'0'], lab+' '+i+'0' ).addClass('AnyTime-min-ten-btn-empty ui-state-default ui-state-disabled');
1680
1681 onesDiv = $('<ul class="AnyTime-mins-ones"/>');
1682 this.dM.append(onesDiv);
1683 for ( i = 0 ; i < 10 ; i++ )
1684 this.btn( onesDiv, i,
1685 function( event )
1686 {
1687 var elem = $(event.target);
1688 if ( elem.hasClass("AnyTime-out-btn") )
1689 return;
1690 var t = new Date(this.time.getTime());
1691 t.setMinutes( (Math.floor(this.time.getMinutes()/10)*10)+Number(elem.text()) );
1692 this.set(t);
1693 this.upd(elem);
1694 },
1695 ['min-one','min'+i], lab+' '+i );
1696 for ( ; i < 12 ; i++ )
1697 this.btn( onesDiv, '&#160;', $.noop, ['min-one','min'+i+'0'], lab+' '+i ).addClass('AnyTime-min-one-btn-empty ui-state-default ui-state-disabled');
1698
1699 shownFields++;
1700
1701 } // if ( askMinute )
1702
1703 if ( askSec )
1704 {
1705 this.dS = $('<div class="AnyTime-secs"/>');
1706 this.dT.append(this.dS);
1707 lab = options.labelSecond || 'Second';
1708 this.dS.append( $('<h6 class="AnyTime-lbl AnyTime-lbl-sec">'+lab+'</h6>') );
1709 tensDiv = $('<ul class="AnyTime-secs-tens"/>');
1710 this.dS.append(tensDiv);
1711
1712 for ( i = 0 ; i < 6 ; i++ )
1713 this.btn( tensDiv, i,
1714 function( event )
1715 {
1716 var elem = $(event.target);
1717 if ( elem.hasClass("AnyTime-out-btn") )
1718 return;
1719 var t = new Date(this.time.getTime());
1720 t.setSeconds( (Number(elem.text())*10) + (this.time.getSeconds()%10) );
1721 this.set(t);
1722 this.upd(elem);
1723 },
1724 ['sec-ten','sec'+i+'0'], lab+' '+i+'0' );
1725 for ( ; i < 12 ; i++ )
1726 this.btn( tensDiv, '&#160;', $.noop, ['sec-ten','sec'+i+'0'], lab+' '+i+'0' ).addClass('AnyTime-sec-ten-btn-empty ui-state-default ui-state-disabled');
1727
1728 onesDiv = $('<ul class="AnyTime-secs-ones"/>');
1729 this.dS.append(onesDiv);
1730 for ( i = 0 ; i < 10 ; i++ )
1731 this.btn( onesDiv, i,
1732 function( event )
1733 {
1734 var elem = $(event.target);
1735 if ( elem.hasClass("AnyTime-out-btn") )
1736 return;
1737 var t = new Date(this.time.getTime());
1738 t.setSeconds( (Math.floor(this.time.getSeconds()/10)*10) + Number(elem.text()) );
1739 this.set(t);
1740 this.upd(elem);
1741 },
1742 ['sec-one','sec'+i], lab+' '+i );
1743 for ( ; i < 12 ; i++ )
1744 this.btn( onesDiv, '&#160;', $.noop, ['sec-one','sec'+i+'0'], lab+' '+i ).addClass('AnyTime-sec-one-btn-empty ui-state-default ui-state-disabled');
1745
1746 shownFields++;
1747
1748 } // if ( askSec )
1749
1750 if ( askOff )
1751 {
1752 this.dO = $('<div class="AnyTime-offs" />');
1753 this.dT.append(this.dO);
1754 this.oMinW = this.dO.outerWidth(true);
1755
1756 this.oLab = $('<h6 class="AnyTime-lbl AnyTime-lbl-off">' + this.lO + '</h6>');
1757 this.dO.append( this.oLab );
1758
1759 var offDiv = $('<ul class="AnyTime-off-list ui-helper-reset" />');
1760 this.dO.append(offDiv);
1761
1762 this.oCur = this.btn(offDiv,'',this.newOffset,['off','off-cur'],lab);
1763 this.oCur.removeClass('ui-state-default');
1764 this.oCur.addClass('AnyTime-cur-btn ui-state-default ui-state-highlight');
1765 this.oCur.css({overflow:"hidden"});
1766
1767 this.oSel = this.btn(offDiv,'&#177;',this.newOffset,['off','off-select'],'+/- '+this.lO);
1768 this.oListMinW = this.oCur.outerWidth(true)+this.oSel.outerWidth(true);
1769
1770 shownFields++;
1771 }
1772
1773 } // if ( askTime )
1774
1775 // Set the title. If a title option has been specified, use it.
1776 // Otherwise, determine a worthy title based on which (and how many)
1777 // format fields have been specified.
1778
1779 if ( options.labelTitle )
1780 this.hTitle.append( options.labelTitle );
1781 else if ( shownFields > 1 )
1782 this.hTitle.append( 'Select a '+(askDate?(askTime?'Date and Time':'Date'):'Time') );
1783 else
1784 this.hTitle.append( 'Select' );
1785
1786
1787 // Initialize the picker's date/time value.
1788
1789 try
1790 {
1791 this.time = this.conv.parse(this.inp.val());
1792 this.offMin = this.conv.getUtcParseOffsetCaptured();
1793 this.offSI = this.conv.getUtcParseOffsetSubIndex();
1794 }
1795 catch ( e )
1796 {
1797 this.time = new Date();
1798 }
1799 this.lastAjax = this.time;
1800
1801
1802 // If this is a popup picker, hide it until needed.
1803
1804 if ( this.pop )
1805 {
1806 this.div.hide();
1807 if ( __iframe )
1808 __iframe.hide();
1809 this.div.css('position','absolute');
1810 }
1811
1812 // Setup event listeners for the input and resize listeners for
1813 // the picker. Add the picker to the instances list (which is used
1814 // to hide pickers if the user clicks off of them).
1815
1816 this.inp.blur( this.hBlur =
1817 function(e)
1818 {
1819 _this.inpBlur(e);
1820 } );
1821
1822 this.inp.click( this.hClick =
1823 function(e)
1824 {
1825 _this.showPkr(e);
1826 } );
1827
1828 this.inp.focus( this.hFocus =
1829 function(e)
1830 {
1831 if ( _this.lostFocus )
1832 _this.showPkr(e);
1833 _this.lostFocus = false;
1834 } );
1835
1836 this.inp.keydown( this.hKeydown =
1837 function(e)
1838 {
1839 _this.key(e);
1840 } );
1841
1842 this.inp.keypress( this.hKeypress =
1843 function(e)
1844 {
1845 if ( $.browser.opera && _this.denyTab )
1846 e.preventDefault();
1847 } );
1848
1849 this.div.click(
1850 function(e)
1851 {
1852 _this.lostFocus = false;
1853 _this.inp.focus();
1854 } );
1855
1856 $(window).resize(
1857 function(e)
1858 {
1859 _this.pos(e);
1860 } );
1861
1862 if ( __initialized )
1863 this.onReady();
1864
1865 }, // initialize()
1866
1867
1868 //---------------------------------------------------------------------
1869 // .ajax() notifies the server of a value change using Ajax.
1870 //---------------------------------------------------------------------
1871
1872 ajax: function()
1873 {
1874 if ( this.ajaxOpts && ( this.time.getTime() != this.lastAjax.getTime() ) )
1875 {
1876 try
1877 {
1878 var opts = jQuery.extend( {}, this.ajaxOpts );
1879 if ( typeof opts.data == 'object' )
1880 opts.data[this.inp[0].name||this.inp[0].id] = this.inp.val();
1881 else
1882 {
1883 var opt = (this.inp[0].name||this.inp[0].id) + '=' + encodeURI(this.inp.val());
1884 if ( opts.data )
1885 opts.data += '&' + opt;
1886 else
1887 opts.data = opt;
1888 }
1889 $.ajax( opts );
1890 this.lastAjax = this.time;
1891 }
1892 catch( e )
1893 {
1894 }
1895 }
1896 return;
1897
1898 }, // .ajax()
1899
1900 //---------------------------------------------------------------------
1901 // .askOffset() is called by this.newOffset() when the UTC offset or
1902 // +- selection button is clicked.
1903 //---------------------------------------------------------------------
1904
1905 askOffset: function( event )
1906 {
1907 if ( ! this.oDiv )
1908 {
1909 this.makeCloak();
1910
1911 this.oDiv = $('<div class="AnyTime-win AnyTime-off-selector ui-widget ui-widget-content ui-corner-all" style="position:absolute" />');
1912 this.div.append(this.oDiv);
1913
1914 // the order here (HDR,BODY,XDIV,TITLE) is important for width calcluation:
1915 var title = $('<h5 class="AnyTime-hdr AnyTime-hdr-off-selector ui-widget-header ui-corner-top" />');
1916 this.oDiv.append( title );
1917 this.oBody = $('<div class="AnyTime-body AnyTime-body-off-selector" style="overflow:auto;white-space:nowrap" />');
1918 this.oDiv.append( this.oBody );
1919 var oBHS = this.oBody.AnyTime_height(true); // body spacing
1920 var oBWS = this.oBody.AnyTime_width(true);
1921 var oTWS = title.AnyTime_width(true);
1922
1923 var xDiv = $('<div class="AnyTime-x-btn ui-state-default">'+this.lX+'</div>');
1924 title.append(xDiv);
1925 xDiv.click(function(e){_this.dismissODiv(e);});
1926 title.append( this.lO );
1927 if ( __msie6 || __msie7 ) // IE bugs!
1928 title.width(String(this.lO.length*0.8)+"em");
1929 var oBW = title.AnyTime_width(true) - oBWS; // initial body width
1930
1931 var cont = $('<ul class="AnyTime-off-off" />' );
1932 var last = null;
1933 this.oBody.append(cont);
1934 var useSubIndex = (this.oConv.fmt.indexOf('%@')>=0);
1935 var btnW = 0; // determine uniform button width
1936 if ( AnyTime.utcLabel )
1937 for ( var o = -720 ; o < 720 ; o++ )
1938 if ( AnyTime.utcLabel[o] )
1939 {
1940 this.oConv.setUtcFormatOffsetAlleged(o);
1941 for ( var i = 0; i < AnyTime.utcLabel[o].length; i++ )
1942 {
1943 this.oConv.setUtcFormatOffsetSubIndex(i);
1944 last = this.btn( cont, this.oConv.format(this.time), this.newOPos, ['off-off'], o );
1945 last[0].AnyTime_offMin = o;
1946 last[0].AnyTime_offSI = i;
1947 var w = last.width();
1948 if ( w > btnW )
1949 btnW = w;
1950 if ( ! useSubIndex )
1951 break; // for
1952 }
1953 }
1954
1955 if ( last )
1956 last.addClass('AnyTime-off-off-last-btn');
1957
1958 // compute optimal width
1959
1960 this.oBody.find('.AnyTime-off-off-btn').width(btnW); // set uniform button width
1961 if ( last )
1962 {
1963 var lW = last.AnyTime_width(true);
1964 if ( lW > oBW )
1965 oBW = lW+1; // expand body to hold buttons
1966 }
1967 this.oBody.width(oBW);
1968 oBW = this.oBody.AnyTime_width(true);
1969 this.oDiv.width( oBW );
1970 if ( __msie6 || __msie7 ) // IE bugs!
1971 title.width( oBW - oTWS );
1972
1973 // compute optimal height
1974
1975 var oH = this.oDiv.AnyTime_height(true);
1976 var oHmax = this.div.height() * 0.75;
1977 if ( oH > oHmax )
1978 {
1979 oH = oHmax;
1980 this.oBody.height(oH-(title.AnyTime_height(true)+oBHS));
1981 this.oBody.width(this.oBody.width()+20); // add nominal px for scrollbar
1982 this.oDiv.width(this.oDiv.width()+20);
1983 if ( __msie6 || __msie7 ) // IE bugs!
1984 title.width( this.oBody.AnyTime_width(true) - oTWS );
1985 }
1986 if ( ! __msie7 ) // IE7 bug!
1987 this.oDiv.height(String(oH)+'px');
1988
1989 } // if ( ! this.oDiv )
1990 else
1991 {
1992 this.cloak.show();
1993 this.oDiv.show();
1994 }
1995 this.pos(event);
1996 this.updODiv(null);
1997
1998 var f = this.oDiv.find('.AnyTime-off-off-btn.AnyTime-cur-btn:first');
1999 if ( ! f.length )
2000 f = this.oDiv.find('.AnyTime-off-off-btn:first');
2001 this.setFocus( f );
2002
2003 }, // .askOffset()
2004
2005 //---------------------------------------------------------------------
2006 // .askYear() is called by this.newYear() when the yPast or yAhead
2007 // button is clicked.
2008 //---------------------------------------------------------------------
2009
2010 askYear: function( event )
2011 {
2012 if ( ! this.yDiv )
2013 {
2014 this.makeCloak();
2015
2016 this.yDiv = $('<div class="AnyTime-win AnyTime-yr-selector ui-widget ui-widget-content ui-corner-all" style="position:absolute" />');
2017 this.div.append(this.yDiv);
2018
2019 var title = $('<h5 class="AnyTime-hdr AnyTime-hdr-yr-selector ui-widget-header ui-corner-top" />');
2020 this.yDiv.append( title );
2021
2022 var xDiv = $('<div class="AnyTime-x-btn ui-state-default">'+this.lX+'</div>');
2023 title.append(xDiv);
2024 xDiv.click(function(e){_this.dismissYDiv(e);});
2025
2026 title.append( this.lY );
2027
2028 var yBody = $('<div class="AnyTime-body AnyTime-body-yr-selector" />');
2029 var yW = yBody.AnyTime_width(true);
2030 var yH = 0;
2031 this.yDiv.append( yBody );
2032
2033 cont = $('<ul class="AnyTime-yr-mil" />' );
2034 yBody.append(cont);
2035 this.y0XXX = this.btn( cont, 0, this.newYPos,['mil','mil0'],this.lY+' '+0+'000');
2036 for ( i = 1; i < 10 ; i++ )
2037 this.btn( cont, i, this.newYPos,['mil','mil'+i],this.lY+' '+i+'000');
2038 yW += cont.AnyTime_width(true);
2039 if ( yH < cont.AnyTime_height(true) )
2040 yH = cont.AnyTime_height(true);
2041
2042 cont = $('<ul class="AnyTime-yr-cent" />' );
2043 yBody.append(cont);
2044 for ( i = 0 ; i < 10 ; i++ )
2045 this.btn( cont, i, this.newYPos,['cent','cent'+i],this.lY+' '+i+'00');
2046 yW += cont.AnyTime_width(true);
2047 if ( yH < cont.AnyTime_height(true) )
2048 yH = cont.AnyTime_height(true);
2049
2050 cont = $('<ul class="AnyTime-yr-dec" />');
2051 yBody.append(cont);
2052 for ( i = 0 ; i < 10 ; i++ )
2053 this.btn( cont, i, this.newYPos,['dec','dec'+i],this.lY+' '+i+'0');
2054 yW += cont.AnyTime_width(true);
2055 if ( yH < cont.AnyTime_height(true) )
2056 yH = cont.AnyTime_height(true);
2057
2058 cont = $('<ul class="AnyTime-yr-yr" />');
2059 yBody.append(cont);
2060 for ( i = 0 ; i < 10 ; i++ )
2061 this.btn( cont, i, this.newYPos,['yr','yr'+i],this.lY+' '+i );
2062 yW += cont.AnyTime_width(true);
2063 if ( yH < cont.AnyTime_height(true) )
2064 yH = cont.AnyTime_height(true);
2065
2066 if ( this.askEra )
2067 {
2068 cont = $('<ul class="AnyTime-yr-era" />' );
2069 yBody.append(cont);
2070
2071 this.btn( cont, this.conv.eAbbr[0],
2072 function( event )
2073 {
2074 var t = new Date(this.time.getTime());
2075 var year = t.getFullYear();
2076 if ( year > 0 )
2077 t.setFullYear(0-year);
2078 this.set(t);
2079 this.updYDiv($(event.target));
2080 },
2081 ['era','bce'], this.conv.eAbbr[0] );
2082
2083 this.btn( cont, this.conv.eAbbr[1],
2084 function( event )
2085 {
2086 var t = new Date(this.time.getTime());
2087 var year = t.getFullYear();
2088 if ( year < 0 )
2089 t.setFullYear(0-year);
2090 this.set(t);
2091 this.updYDiv($(event.target));
2092 },
2093 ['era','ce'], this.conv.eAbbr[1] );
2094
2095 yW += cont.AnyTime_width(true);
2096 if ( yH < cont.AnyTime_height(true) )
2097 yH = cont.AnyTime_height(true);
2098
2099 } // if ( this.askEra )
2100
2101 if ( $.browser.msie ) // IE8+ThemeUI bug!
2102 yW += 1;
2103 else if ( $.browser.safari ) // Safari small-text bug!
2104 yW += 2;
2105 yH += yBody.AnyTime_height(true);
2106 yBody.css('width',String(yW)+'px');
2107 if ( ! __msie7 ) // IE7 bug!
2108 yBody.css('height',String(yH)+'px');
2109 if ( __msie6 || __msie7 ) // IE bugs!
2110 title.width(yBody.outerWidth(true));
2111 yH += title.AnyTime_height(true);
2112 if ( title.AnyTime_width(true) > yW )
2113 yW = title.AnyTime_width(true);
2114 this.yDiv.css('width',String(yW)+'px');
2115 if ( ! __msie7 ) // IE7 bug!
2116 this.yDiv.css('height',String(yH)+'px');
2117
2118 } // if ( ! this.yDiv )
2119 else
2120 {
2121 this.cloak.show();
2122 this.yDiv.show();
2123 }
2124 this.pos(event);
2125 this.updYDiv(null);
2126 this.setFocus( this.yDiv.find('.AnyTime-yr-btn.AnyTime-cur-btn:first') );
2127
2128 }, // .askYear()
2129
2130 //---------------------------------------------------------------------
2131 // .inpBlur() is called when a picker's input loses focus to dismiss
2132 // the popup. A 1/3 second delay is necessary to restore focus if
2133 // the div is clicked (shorter delays don't always work!) To prevent
2134 // problems cause by scrollbar focus (except in FF), focus is
2135 // force-restored if the offset div is visible.
2136 //---------------------------------------------------------------------
2137
2138 inpBlur: function(event)
2139 {
2140 if ( this.oDiv && this.oDiv.is(":visible") )
2141 {
2142 _this.inp.focus();
2143 return;
2144 }
2145 this.lostFocus = true;
2146 setTimeout(
2147 function()
2148 {
2149 if ( _this.lostFocus )
2150 {
2151 _this.div.find('.AnyTime-focus-btn').removeClass('AnyTime-focus-btn ui-state-focus');
2152 if ( _this.pop )
2153 _this.dismiss(event);
2154 else
2155 _this.ajax();
2156 }
2157 }, 334 );
2158 },
2159
2160 //---------------------------------------------------------------------
2161 // .btn() is called by AnyTime.picker() to create a <div> element
2162 // containing an <a> element. The elements are given appropriate
2163 // classes based on the specified "classes" (an array of strings).
2164 // The specified "text" and "title" are used for the <a> element.
2165 // The "handler" is bound to click events for the <div>, which will
2166 // catch bubbling clicks from the <a> as well. The button is
2167 // appended to the specified parent (jQuery), and the <div> jQuery
2168 // is returned.
2169 //---------------------------------------------------------------------
2170
2171 btn: function( parent, text, handler, classes, title )
2172 {
2173 var tagName = ( (parent[0].nodeName.toLowerCase()=='ul')?'li':'td');
2174 var div$ = '<' + tagName +
2175 ' class="AnyTime-btn';
2176 for ( var i = 0 ; i < classes.length ; i++ )
2177 div$ += ' AnyTime-' + classes[i] + '-btn';
2178 var div = $( div$ + ' ui-state-default">' + text + '</' + tagName + '>' );
2179 parent.append(div);
2180 div.AnyTime_title = title;
2181
2182 div.click(
2183 function(e)
2184 {
2185 // bind the handler to the picker so "this" is correct
2186 _this.tempFunc = handler;
2187 _this.tempFunc(e);
2188 });
2189 div.dblclick(
2190 function(e)
2191 {
2192 var elem = $(this);
2193 if ( elem.is('.AnyTime-off-off-btn') )
2194 _this.dismissODiv(e);
2195 else if ( elem.is('.AnyTime-mil-btn') || elem.is('.AnyTime-cent-btn') || elem.is('.AnyTime-dec-btn') || elem.is('.AnyTime-yr-btn') || elem.is('.AnyTime-era-btn') )
2196 _this.dismissYDiv(e);
2197 else if ( _this.pop )
2198 _this.dismiss(e);
2199 });
2200 return div;
2201
2202 }, // .btn()
2203
2204 //---------------------------------------------------------------------
2205 // .cleanup() destroys the DOM events and elements associated with
2206 // the picker so it can be deleted.
2207 //---------------------------------------------------------------------
2208
2209 cleanup: function(event)
2210 {
2211 this.inp.unbind('blur',this.hBlur);
2212 this.inp.unbind('click',this.hClick);
2213 this.inp.unbind('focus',this.hFocus);
2214 this.inp.unbind('keydown',this.hKeydown);
2215 this.inp.unbind('keypress',this.hKeypress);
2216 this.div.remove();
2217 },
2218
2219 //---------------------------------------------------------------------
2220 // .dismiss() dismisses a popup picker.
2221 //---------------------------------------------------------------------
2222
2223 dismiss: function(event)
2224 {
2225 this.ajax();
2226 this.div.hide();
2227 if ( __iframe )
2228 __iframe.hide();
2229 if ( this.yDiv )
2230 this.dismissYDiv();
2231 if ( this.oDiv )
2232 this.dismissODiv();
2233 this.lostFocus = true;
2234 },
2235
2236 //---------------------------------------------------------------------
2237 // .dismissODiv() dismisses the UTC offset selector popover.
2238 //---------------------------------------------------------------------
2239
2240 dismissODiv: function(event)
2241 {
2242 this.oDiv.hide();
2243 this.cloak.hide();
2244 this.setFocus(this.oCur);
2245 },
2246
2247 //---------------------------------------------------------------------
2248 // .dismissYDiv() dismisses the date selector popover.
2249 //---------------------------------------------------------------------
2250
2251 dismissYDiv: function(event)
2252 {
2253 this.yDiv.hide();
2254 this.cloak.hide();
2255 this.setFocus(this.yCur);
2256 },
2257
2258 //---------------------------------------------------------------------
2259 // .setFocus() makes a specified psuedo-button appear to get focus.
2260 //---------------------------------------------------------------------
2261
2262 setFocus: function(btn)
2263 {
2264 if ( ! btn.hasClass('AnyTime-focus-btn') )
2265 {
2266 this.div.find('.AnyTime-focus-btn').removeClass('AnyTime-focus-btn ui-state-focus');
2267 this.fBtn = btn;
2268 btn.removeClass('ui-state-default ui-state-highlight');
2269 btn.addClass('AnyTime-focus-btn ui-state-default ui-state-highlight ui-state-focus');
2270 }
2271 if ( btn.hasClass('AnyTime-off-off-btn') )
2272 {
2273 var oBT = this.oBody.offset().top;
2274 var btnT = btn.offset().top;
2275 var btnH = btn.AnyTime_height(true);
2276 if ( btnT - btnH < oBT ) // move a page up
2277 this.oBody.scrollTop( btnT + this.oBody.scrollTop() - ( this.oBody.innerHeight() + oBT ) + ( btnH * 2 ) );
2278 else if ( btnT + btnH > oBT + this.oBody.innerHeight() ) // move a page down
2279 this.oBody.scrollTop( ( btnT + this.oBody.scrollTop() ) - ( oBT + btnH ) );
2280 }
2281 },
2282
2283 //---------------------------------------------------------------------
2284 // .key() is invoked when a user presses a key while the picker's
2285 // input has focus. A psuedo-button is considered "in focus" and an
2286 // appropriate action is performed according to the WAI-ARIA Authoring
2287 // Practices 1.0 for datepicker from
2288 // www.w3.org/TR/2009/WD-wai-aria-practices-20091215/#datepicker:
2289 //
2290 // * LeftArrow moves focus left, continued to previous week.
2291 // * RightArrow moves focus right, continued to next week.
2292 // * UpArrow moves focus to the same weekday in the previous week.
2293 // * DownArrow moves focus to same weekday in the next week.
2294 // * PageUp moves focus to same day in the previous month.
2295 // * PageDown moves focus to same day in the next month.
2296 // * Shift+Page Up moves focus to same day in the previous year.
2297 // * Shift+Page Down moves focus to same day in the next year.
2298 // * Home moves focus to the first day of the month.
2299 // * End moves focus to the last day of the month.
2300 // * Ctrl+Home moves focus to the first day of the year.
2301 // * Ctrl+End moves focus to the last day of the year.
2302 // * Esc closes a DatePicker that is opened as a Popup.
2303 //
2304 // The following actions (for multiple-date selection) are NOT
2305 // supported:
2306 // * Shift+Arrow performs continous selection.
2307 // * Ctrl+Space multiple selection of certain days.
2308 //
2309 // The authoring practices do not specify behavior for a time picker,
2310 // or for month-and-year pickers that do not have a day-of-the-month,
2311 // but AnyTime.picker uses the following behavior to be as consistent
2312 // as possible with the defined datepicker functionality:
2313 // * LeftArrow moves focus left or up to previous value or field.
2314 // * RightArrow moves focus right or down to next value or field.
2315 // * UpArrow moves focus up or left to previous value or field.
2316 // * DownArrow moves focus down or right to next value or field
2317 // * PageUp moves focus to the current value in the previous units
2318 // (for example, from ten-minutes to hours or one-minutes to
2319 // ten-minutes or months to years).
2320 // * PageDown moves focus to the current value in the next units
2321 // (for example, from hours to ten-minutes or ten-minutes to
2322 // one-minutes or years to months).
2323 // * Home moves the focus to the first unit button.
2324 // * End moves the focus to the last unit button.
2325 //
2326 // In addition, Tab and Shift+Tab move between units (including to/
2327 // from the Day-of-Month table) and also in/out of the picker.
2328 //
2329 // Because AnyTime.picker sets a value as soon as the button receives
2330 // focus, SPACE and ENTER are not needed (the WAI-ARIA guidelines use
2331 // them to select a value.
2332 //---------------------------------------------------------------------
2333
2334 key: function(event)
2335 {
2336 var mo;
2337 var t = null;
2338 var elem = this.div.find('.AnyTime-focus-btn');
2339 var key = event.keyCode || event.which;
2340 this.denyTab = true;
2341
2342 if ( key == 16 ) // Shift
2343 {
2344 }
2345 else if ( ( key == 10 ) || ( key == 13 ) || ( key == 27 ) ) // Enter & Esc
2346 {
2347 if ( this.oDiv && this.oDiv.is(':visible') )
2348 this.dismissODiv(event);
2349 else if ( this.yDiv && this.yDiv.is(':visible') )
2350 this.dismissYDiv(event);
2351 else if ( this.pop )
2352 this.dismiss(event);
2353 }
2354 else if ( ( key == 33 ) || ( ( key == 9 ) && event.shiftKey ) ) // PageUp & Shift+Tab
2355 {
2356 if ( this.fBtn.hasClass('AnyTime-off-off-btn') )
2357 {
2358 if ( key == 9 )
2359 this.dismissODiv(event);
2360 }
2361 else if ( this.fBtn.hasClass('AnyTime-mil-btn') )
2362 {
2363 if ( key == 9 )
2364 this.dismissYDiv(event);
2365 }
2366 else if ( this.fBtn.hasClass('AnyTime-cent-btn') )
2367 this.yDiv.find('.AnyTime-mil-btn.AnyTime-cur-btn').triggerHandler('click');
2368 else if ( this.fBtn.hasClass('AnyTime-dec-btn') )
2369 this.yDiv.find('.AnyTime-cent-btn.AnyTime-cur-btn').triggerHandler('click');
2370 else if ( this.fBtn.hasClass('AnyTime-yr-btn') )
2371 this.yDiv.find('.AnyTime-dec-btn.AnyTime-cur-btn').triggerHandler('click');
2372 else if ( this.fBtn.hasClass('AnyTime-era-btn') )
2373 this.yDiv.find('.AnyTime-yr-btn.AnyTime-cur-btn').triggerHandler('click');
2374 else if ( this.fBtn.parents('.AnyTime-yrs').length )
2375 {
2376 if ( key == 9 )
2377 {
2378 this.denyTab = false;
2379 return;
2380 }
2381 }
2382 else if ( this.fBtn.hasClass('AnyTime-mon-btn') )
2383 {
2384 if ( this.dY )
2385 this.yCur.triggerHandler('click');
2386 else if ( key == 9 )
2387 {
2388 this.denyTab = false;
2389 return;
2390 }
2391 }
2392 else if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2393 {
2394 if ( ( key == 9 ) && event.shiftKey ) // Shift+Tab
2395 {
2396 this.denyTab = false;
2397 return;
2398 }
2399 else // PageUp
2400 {
2401 t = new Date(this.time.getTime());
2402 if ( event.shiftKey )
2403 t.setFullYear(t.getFullYear()-1);
2404 else
2405 {
2406 mo = t.getMonth()-1;
2407 if ( t.getDate() > __daysIn[mo] )
2408 t.setDate(__daysIn[mo])
2409 t.setMonth(mo);
2410 }
2411 this.keyDateChange(t);
2412 }
2413 }
2414 else if ( this.fBtn.hasClass('AnyTime-hr-btn') )
2415 {
2416 t = this.dDoM || this.dMo;
2417 if ( t )
2418 t.AnyTime_clickCurrent();
2419 else if ( this.dY )
2420 this.yCur.triggerHandler('click');
2421 else if ( key == 9 )
2422 {
2423 this.denyTab = false;
2424 return;
2425 }
2426 }
2427 else if ( this.fBtn.hasClass('AnyTime-min-ten-btn') )
2428 {
2429 t = this.dH || this.dDoM || this.dMo;
2430 if ( t )
2431 t.AnyTime_clickCurrent();
2432 else if ( this.dY )
2433 this.yCur.triggerHandler('click');
2434 else if ( key == 9 )
2435 {
2436 this.denyTab = false;
2437 return;
2438 }
2439 }
2440 else if ( this.fBtn.hasClass('AnyTime-min-one-btn') )
2441 this.dM.AnyTime_clickCurrent();
2442 else if ( this.fBtn.hasClass('AnyTime-sec-ten-btn') )
2443 {
2444 if ( this.dM )
2445 t = this.dM.find('.AnyTime-mins-ones');
2446 else
2447 t = this.dH || this.dDoM || this.dMo;
2448 if ( t )
2449 t.AnyTime_clickCurrent();
2450 else if ( this.dY )
2451 this.yCur.triggerHandler('click');
2452 else if ( key == 9 )
2453 {
2454 this.denyTab = false;
2455 return;
2456 }
2457 }
2458 else if ( this.fBtn.hasClass('AnyTime-sec-one-btn') )
2459 this.dS.AnyTime_clickCurrent();
2460 else if ( this.fBtn.hasClass('AnyTime-off-btn') )
2461 {
2462 if ( this.dS )
2463 t = this.dS.find('.AnyTime-secs-ones');
2464 else if ( this.dM )
2465 t = this.dM.find('.AnyTime-mins-ones');
2466 else
2467 t = this.dH || this.dDoM || this.dMo;
2468 if ( t )
2469 t.AnyTime_clickCurrent();
2470 else if ( this.dY )
2471 this.yCur.triggerHandler('click');
2472 else if ( key == 9 )
2473 {
2474 this.denyTab = false;
2475 return;
2476 }
2477 }
2478 }
2479 else if ( ( key == 34 ) || ( key == 9 ) ) // PageDown or Tab
2480 {
2481 if ( this.fBtn.hasClass('AnyTime-mil-btn') )
2482 this.yDiv.find('.AnyTime-cent-btn.AnyTime-cur-btn').triggerHandler('click');
2483 else if ( this.fBtn.hasClass('AnyTime-cent-btn') )
2484 this.yDiv.find('.AnyTime-dec-btn.AnyTime-cur-btn').triggerHandler('click');
2485 else if ( this.fBtn.hasClass('AnyTime-dec-btn') )
2486 this.yDiv.find('.AnyTime-yr-btn.AnyTime-cur-btn').triggerHandler('click');
2487 else if ( this.fBtn.hasClass('AnyTime-yr-btn') )
2488 {
2489 t = this.yDiv.find('.AnyTime-era-btn.AnyTime-cur-btn');
2490 if ( t.length )
2491 t.triggerHandler('click');
2492 else if ( key == 9 )
2493 this.dismissYDiv(event);
2494 }
2495 else if ( this.fBtn.hasClass('AnyTime-era-btn') )
2496 {
2497 if ( key == 9 )
2498 this.dismissYDiv(event);
2499 }
2500 else if ( this.fBtn.hasClass('AnyTime-off-off-btn') )
2501 {
2502 if ( key == 9 )
2503 this.dismissODiv(event);
2504 }
2505 else if ( this.fBtn.parents('.AnyTime-yrs').length )
2506 {
2507 t = this.dDoM || this.dMo || this.dH || this.dM || this.dS || this.dO;
2508 if ( t )
2509 t.AnyTime_clickCurrent();
2510 else if ( key == 9 )
2511 {
2512 this.denyTab = false;
2513 return;
2514 }
2515 }
2516 else if ( this.fBtn.hasClass('AnyTime-mon-btn') )
2517 {
2518 t = this.dDoM || this.dH || this.dM || this.dS || this.dO;
2519 if ( t )
2520 t.AnyTime_clickCurrent();
2521 else if ( key == 9 )
2522 {
2523 this.denyTab = false;
2524 return;
2525 }
2526 }
2527 else if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2528 {
2529 if ( key == 9 ) // Tab
2530 {
2531 t = this.dH || this.dM || this.dS || this.dO;
2532 if ( t )
2533 t.AnyTime_clickCurrent();
2534 else
2535 {
2536 this.denyTab = false;
2537 return;
2538 }
2539 }
2540 else // PageDown
2541 {
2542 t = new Date(this.time.getTime());
2543 if ( event.shiftKey )
2544 t.setFullYear(t.getFullYear()+1);
2545 else
2546 {
2547 mo = t.getMonth()+1;
2548 if ( t.getDate() > __daysIn[mo] )
2549 t.setDate(__daysIn[mo])
2550 t.setMonth(mo);
2551 }
2552 this.keyDateChange(t);
2553 }
2554 }
2555 else if ( this.fBtn.hasClass('AnyTime-hr-btn') )
2556 {
2557 t = this.dM || this.dS || this.dO;
2558 if ( t )
2559 t.AnyTime_clickCurrent();
2560 else if ( key == 9 )
2561 {
2562 this.denyTab = false;
2563 return;
2564 }
2565 }
2566 else if ( this.fBtn.hasClass('AnyTime-min-ten-btn') )
2567 this.dM.find('.AnyTime-mins-ones .AnyTime-cur-btn').triggerHandler('click');
2568 else if ( this.fBtn.hasClass('AnyTime-min-one-btn') )
2569 {
2570 t = this.dS || this.dO;
2571 if ( t )
2572 t.AnyTime_clickCurrent();
2573 else if ( key == 9 )
2574 {
2575 this.denyTab = false;
2576 return;
2577 }
2578 }
2579 else if ( this.fBtn.hasClass('AnyTime-sec-ten-btn') )
2580 this.dS.find('.AnyTime-secs-ones .AnyTime-cur-btn').triggerHandler('click');
2581 else if ( this.fBtn.hasClass('AnyTime-sec-one-btn') )
2582 {
2583 if ( this.dO )
2584 this.dO.AnyTime_clickCurrent();
2585 else if ( key == 9 )
2586 {
2587 this.denyTab = false;
2588 return;
2589 }
2590 }
2591 else if ( this.fBtn.hasClass('AnyTime-off-btn') )
2592 {
2593 if ( key == 9 )
2594 {
2595 this.denyTab = false;
2596 return;
2597 }
2598 }
2599 }
2600 else if ( key == 35 ) // END
2601 {
2602 if ( this.fBtn.hasClass('AnyTime-mil-btn') || this.fBtn.hasClass('AnyTime-cent-btn') ||
2603 this.fBtn.hasClass('AnyTime-dec-btn') || this.fBtn.hasClass('AnyTime-yr-btn') ||
2604 this.fBtn.hasClass('AnyTime-era-btn') )
2605 {
2606 t = this.yDiv.find('.AnyTime-ce-btn');
2607 if ( ! t.length )
2608 t = this.yDiv.find('.AnyTime-yr9-btn');
2609 t.triggerHandler('click');
2610 }
2611 else if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2612 {
2613 t = new Date(this.time.getTime());
2614 t.setDate(1);
2615 t.setMonth(t.getMonth()+1);
2616 t.setDate(t.getDate()-1);
2617 if ( event.ctrlKey )
2618 t.setMonth(11);
2619 this.keyDateChange(t);
2620 }
2621 else if ( this.dS )
2622 this.dS.find('.AnyTime-sec9-btn').triggerHandler('click');
2623 else if ( this.dM )
2624 this.dM.find('.AnyTime-min9-btn').triggerHandler('click');
2625 else if ( this.dH )
2626 this.dH.find('.AnyTime-hr23-btn').triggerHandler('click');
2627 else if ( this.dDoM )
2628 this.dDoM.find('.AnyTime-dom-btn-filled:last').triggerHandler('click');
2629 else if ( this.dMo )
2630 this.dMo.find('.AnyTime-mon12-btn').triggerHandler('click');
2631 else if ( this.dY )
2632 this.yAhead.triggerHandler('click');
2633 }
2634 else if ( key == 36 ) // HOME
2635 {
2636 if ( this.fBtn.hasClass('AnyTime-mil-btn') || this.fBtn.hasClass('AnyTime-cent-btn') ||
2637 this.fBtn.hasClass('AnyTime-dec-btn') || this.fBtn.hasClass('AnyTime-yr-btn') ||
2638 this.fBtn.hasClass('AnyTime-era-btn') )
2639 {
2640 this.yDiv.find('.AnyTime-mil0-btn').triggerHandler('click');
2641 }
2642 else if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2643 {
2644 t = new Date(this.time.getTime());
2645 t.setDate(1);
2646 if ( event.ctrlKey )
2647 t.setMonth(0);
2648 this.keyDateChange(t);
2649 }
2650 else if ( this.dY )
2651 this.yCur.triggerHandler('click');
2652 else if ( this.dMo )
2653 this.dMo.find('.AnyTime-mon1-btn').triggerHandler('click');
2654 else if ( this.dDoM )
2655 this.dDoM.find('.AnyTime-dom-btn-filled:first').triggerHandler('click');
2656 else if ( this.dH )
2657 this.dH.find('.AnyTime-hr0-btn').triggerHandler('click');
2658 else if ( this.dM )
2659 this.dM.find('.AnyTime-min00-btn').triggerHandler('click');
2660 else if ( this.dS )
2661 this.dS.find('.AnyTime-sec00-btn').triggerHandler('click');
2662 }
2663 else if ( key == 37 ) // left arrow
2664 {
2665 if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2666 this.keyDateChange(new Date(this.time.getTime()-__oneDay));
2667 else
2668 this.keyBack();
2669 }
2670 else if ( key == 38 ) // up arrow
2671 {
2672 if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2673 this.keyDateChange(new Date(this.time.getTime()-(7*__oneDay)));
2674 else
2675 this.keyBack();
2676 }
2677 else if ( key == 39 ) // right arrow
2678 {
2679 if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2680 this.keyDateChange(new Date(this.time.getTime()+__oneDay));
2681 else
2682 this.keyAhead();
2683 }
2684 else if ( key == 40 ) // down arrow
2685 {
2686 if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2687 this.keyDateChange(new Date(this.time.getTime()+(7*__oneDay)));
2688 else
2689 this.keyAhead();
2690 }
2691 else if ( ( ( key == 86 ) || ( key == 118 ) ) && event.ctrlKey )
2692 {
2693 this.inp.val("").change();
2694 var _this = this;
2695 setTimeout( function() { _this.showPkr(null); }, 100 );
2696 return;
2697 }
2698 else
2699 this.showPkr(null);
2700
2701 event.preventDefault();
2702
2703 }, // .key()
2704
2705 //---------------------------------------------------------------------
2706 // .keyAhead() is called by #key when a user presses the right or
2707 // down arrow. It moves to the next appropriate button.
2708 //---------------------------------------------------------------------
2709
2710 keyAhead: function()
2711 {
2712 if ( this.fBtn.hasClass('AnyTime-mil9-btn') )
2713 this.yDiv.find('.AnyTime-cent0-btn').triggerHandler('click');
2714 else if ( this.fBtn.hasClass('AnyTime-cent9-btn') )
2715 this.yDiv.find('.AnyTime-dec0-btn').triggerHandler('click');
2716 else if ( this.fBtn.hasClass('AnyTime-dec9-btn') )
2717 this.yDiv.find('.AnyTime-yr0-btn').triggerHandler('click');
2718 else if ( this.fBtn.hasClass('AnyTime-yr9-btn') )
2719 this.yDiv.find('.AnyTime-bce-btn').triggerHandler('click');
2720 else if ( this.fBtn.hasClass('AnyTime-sec9-btn') )
2721 {}
2722 else if ( this.fBtn.hasClass('AnyTime-sec50-btn') )
2723 this.dS.find('.AnyTime-sec0-btn').triggerHandler('click');
2724 else if ( this.fBtn.hasClass('AnyTime-min9-btn') )
2725 {
2726 if ( this.dS )
2727 this.dS.find('.AnyTime-sec00-btn').triggerHandler('click');
2728 }
2729 else if ( this.fBtn.hasClass('AnyTime-min50-btn') )
2730 this.dM.find('.AnyTime-min0-btn').triggerHandler('click');
2731 else if ( this.fBtn.hasClass('AnyTime-hr23-btn') )
2732 {
2733 if ( this.dM )
2734 this.dM.find('.AnyTime-min00-btn').triggerHandler('click');
2735 else if ( this.dS )
2736 this.dS.find('.AnyTime-sec00-btn').triggerHandler('click');
2737 }
2738 else if ( this.fBtn.hasClass('AnyTime-hr11-btn') )
2739 this.dH.find('.AnyTime-hr12-btn').triggerHandler('click');
2740 else if ( this.fBtn.hasClass('AnyTime-mon12-btn') )
2741 {
2742 if ( this.dDoM )
2743 this.dDoM.AnyTime_clickCurrent();
2744 else if ( this.dH )
2745 this.dH.find('.AnyTime-hr0-btn').triggerHandler('click');
2746 else if ( this.dM )
2747 this.dM.find('.AnyTime-min00-btn').triggerHandler('click');
2748 else if ( this.dS )
2749 this.dS.find('.AnyTime-sec00-btn').triggerHandler('click');
2750 }
2751 else if ( this.fBtn.hasClass('AnyTime-yrs-ahead-btn') )
2752 {
2753 if ( this.dMo )
2754 this.dMo.find('.AnyTime-mon1-btn').triggerHandler('click');
2755 else if ( this.dH )
2756 this.dH.find('.AnyTime-hr0-btn').triggerHandler('click');
2757 else if ( this.dM )
2758 this.dM.find('.AnyTime-min00-btn').triggerHandler('click');
2759 else if ( this.dS )
2760 this.dS.find('.AnyTime-sec00-btn').triggerHandler('click');
2761 }
2762 else if ( this.fBtn.hasClass('AnyTime-yr-cur-btn') )
2763 this.yNext.triggerHandler('click');
2764 else
2765 this.fBtn.next().triggerHandler('click');
2766
2767 }, // .keyAhead()
2768
2769
2770 //---------------------------------------------------------------------
2771 // .keyBack() is called by #key when a user presses the left or
2772 // up arrow. It moves to the previous appropriate button.
2773 //---------------------------------------------------------------------
2774
2775 keyBack: function()
2776 {
2777 if ( this.fBtn.hasClass('AnyTime-cent0-btn') )
2778 this.yDiv.find('.AnyTime-mil9-btn').triggerHandler('click');
2779 else if ( this.fBtn.hasClass('AnyTime-dec0-btn') )
2780 this.yDiv.find('.AnyTime-cent9-btn').triggerHandler('click');
2781 else if ( this.fBtn.hasClass('AnyTime-yr0-btn') )
2782 this.yDiv.find('.AnyTime-dec9-btn').triggerHandler('click');
2783 else if ( this.fBtn.hasClass('AnyTime-bce-btn') )
2784 this.yDiv.find('.AnyTime-yr9-btn').triggerHandler('click');
2785 else if ( this.fBtn.hasClass('AnyTime-yr-cur-btn') )
2786 this.yPrior.triggerHandler('click');
2787 else if ( this.fBtn.hasClass('AnyTime-mon1-btn') )
2788 {
2789 if ( this.dY )
2790 this.yCur.triggerHandler('click');
2791 }
2792 else if ( this.fBtn.hasClass('AnyTime-hr0-btn') )
2793 {
2794 if ( this.dDoM )
2795 this.dDoM.AnyTime_clickCurrent();
2796 else if ( this.dMo )
2797 this.dMo.find('.AnyTime-mon12-btn').triggerHandler('click');
2798 else if ( this.dY )
2799 this.yNext.triggerHandler('click');
2800 }
2801 else if ( this.fBtn.hasClass('AnyTime-hr12-btn') )
2802 this.dH.find('.AnyTime-hr11-btn').triggerHandler('click');
2803 else if ( this.fBtn.hasClass('AnyTime-min00-btn') )
2804 {
2805 if ( this.dH )
2806 this.dH.find('.AnyTime-hr23-btn').triggerHandler('click');
2807 else if ( this.dDoM )
2808 this.dDoM.AnyTime_clickCurrent();
2809 else if ( this.dMo )
2810 this.dMo.find('.AnyTime-mon12-btn').triggerHandler('click');
2811 else if ( this.dY )
2812 this.yNext.triggerHandler('click');
2813 }
2814 else if ( this.fBtn.hasClass('AnyTime-min0-btn') )
2815 this.dM.find('.AnyTime-min50-btn').triggerHandler('click');
2816 else if ( this.fBtn.hasClass('AnyTime-sec00-btn') )
2817 {
2818 if ( this.dM )
2819 this.dM.find('.AnyTime-min9-btn').triggerHandler('click');
2820 else if ( this.dH )
2821 this.dH.find('.AnyTime-hr23-btn').triggerHandler('click');
2822 else if ( this.dDoM )
2823 this.dDoM.AnyTime_clickCurrent();
2824 else if ( this.dMo )
2825 this.dMo.find('.AnyTime-mon12-btn').triggerHandler('click');
2826 else if ( this.dY )
2827 this.yNext.triggerHandler('click');
2828 }
2829 else if ( this.fBtn.hasClass('AnyTime-sec0-btn') )
2830 this.dS.find('.AnyTime-sec50-btn').triggerHandler('click');
2831 else
2832 this.fBtn.prev().triggerHandler('click');
2833
2834 }, // .keyBack()
2835
2836 //---------------------------------------------------------------------
2837 // .keyDateChange() is called by #key when an direction key
2838 // (arrows/page/etc) is pressed while the Day-of-Month calendar has
2839 // focus. The current day is adjusted accordingly.
2840 //---------------------------------------------------------------------
2841
2842 keyDateChange: function( newDate )
2843 {
2844 if ( this.fBtn.hasClass('AnyTime-dom-btn') )
2845 {
2846 this.set(newDate);
2847 this.upd(null);
2848 this.setFocus( this.dDoM.find('.AnyTime-cur-btn') );
2849 }
2850 },
2851
2852 //---------------------------------------------------------------------
2853 // .makeCloak() is called by .askOffset() and .askYear() to create
2854 // a cloak div.
2855 //---------------------------------------------------------------------
2856
2857 makeCloak: function()
2858 {
2859 if ( ! this.cloak )
2860 {
2861 this.cloak = $('<div class="AnyTime-cloak" style="position:absolute" />');
2862 this.div.append( this.cloak );
2863 this.cloak.click(
2864 function(e)
2865 {
2866 if ( _this.oDiv && _this.oDiv.is(":visible") )
2867 _this.dismissODiv(e);
2868 else
2869 _this.dismissYDiv(e);
2870 });
2871 }
2872 else
2873 this.cloak.show();
2874 },
2875
2876 //---------------------------------------------------------------------
2877 // .newHour() is called when a user clicks an hour value.
2878 // It changes the date and updates the text field.
2879 //---------------------------------------------------------------------
2880
2881 newHour: function( event )
2882 {
2883 var h;
2884 var t;
2885 var elem = $(event.target);
2886 if ( elem.hasClass("AnyTime-out-btn") )
2887 return;
2888 if ( ! this.twelveHr )
2889 h = Number(elem.text());
2890 else
2891 {
2892 var str = elem.text();
2893 t = str.indexOf('a');
2894 if ( t < 0 )
2895 {
2896 t = Number(str.substr(0,str.indexOf('p')));
2897 h = ( (t==12) ? 12 : (t+12) );
2898 }
2899 else
2900 {
2901 t = Number(str.substr(0,t));
2902 h = ( (t==12) ? 0 : t );
2903 }
2904 }
2905 t = new Date(this.time.getTime());
2906 t.setHours(h);
2907 this.set(t);
2908 this.upd(elem);
2909
2910 }, // .newHour()
2911
2912 //---------------------------------------------------------------------
2913 // .newOffset() is called when a user clicks the UTC offset (timezone)
2914 // (or +/- button) to shift the year. It changes the date and updates
2915 // the text field.
2916 //---------------------------------------------------------------------
2917
2918 newOffset: function( event )
2919 {
2920 if ( event.target == this.oSel[0] )
2921 this.askOffset(event);
2922 else
2923 {
2924 this.upd(this.oCur);
2925 }
2926 },
2927
2928 //---------------------------------------------------------------------
2929 // .newOPos() is called internally whenever a user clicks an offset
2930 // selection value. It changes the date and updates the text field.
2931 //---------------------------------------------------------------------
2932
2933 newOPos: function( event )
2934 {
2935 var elem = $(event.target);
2936 this.offMin = elem[0].AnyTime_offMin;
2937 this.offSI = elem[0].AnyTime_offSI;
2938 var t = new Date(this.time.getTime());
2939 this.set(t);
2940 this.updODiv(elem);
2941
2942 }, // .newOPos()
2943
2944 //---------------------------------------------------------------------
2945 // .newYear() is called when a user clicks a year (or one of the
2946 // "arrows") to shift the year. It changes the date and updates the
2947 // text field.
2948 //---------------------------------------------------------------------
2949
2950 newYear: function( event )
2951 {
2952 var elem = $(event.target);
2953 if ( elem.hasClass("AnyTime-out-btn") )
2954 return;
2955 var txt = elem.text();
2956 if ( ( txt == '<' ) || ( txt == '&lt;' ) )
2957 this.askYear(event);
2958 else if ( ( txt == '>' ) || ( txt == '&gt;' ) )
2959 this.askYear(event);
2960 else
2961 {
2962 var t = new Date(this.time.getTime());
2963 t.setFullYear(Number(txt));
2964 this.set(t);
2965 this.upd(this.yCur);
2966 }
2967 },
2968
2969 //---------------------------------------------------------------------
2970 // .newYPos() is called internally whenever a user clicks a year
2971 // selection value. It changes the date and updates the text field.
2972 //---------------------------------------------------------------------
2973
2974 newYPos: function( event )
2975 {
2976 var elem = $(event.target);
2977 if ( elem.hasClass("AnyTime-out-btn") )
2978 return;
2979
2980 var era = 1;
2981 var year = this.time.getFullYear();
2982 if ( year < 0 )
2983 {
2984 era = (-1);
2985 year = 0 - year;
2986 }
2987 year = AnyTime.pad( year, 4 );
2988 if ( elem.hasClass('AnyTime-mil-btn') )
2989 year = elem.html() + year.substring(1,4);
2990 else if ( elem.hasClass('AnyTime-cent-btn') )
2991 year = year.substring(0,1) + elem.html() + year.substring(2,4);
2992 else if ( elem.hasClass('AnyTime-dec-btn') )
2993 year = year.substring(0,2) + elem.html() + year.substring(3,4);
2994 else
2995 year = year.substring(0,3) + elem.html();
2996 if ( year == '0000' )
2997 year = 1;
2998 var t = new Date(this.time.getTime());
2999 t.setFullYear( era * year );
3000 this.set(t);
3001 this.updYDiv(elem);
3002
3003 }, // .newYPos()
3004
3005 //---------------------------------------------------------------------
3006 // .onReady() initializes the picker after the page has loaded and,
3007 // if IE6, after the iframe has been created.
3008 //---------------------------------------------------------------------
3009
3010 onReady: function()
3011 {
3012 this.lostFocus = true;
3013 if ( ! this.pop )
3014 this.upd(null);
3015 else
3016 {
3017 if ( this.div.parent() != document.body )
3018 this.div.appendTo( document.body );
3019 }
3020 },
3021
3022 //---------------------------------------------------------------------
3023 // .pos() positions the picker, such as when it is displayed or
3024 // when the window is resized.
3025 //---------------------------------------------------------------------
3026
3027 pos: function(event) // note: event is ignored but this is a handler
3028 {
3029 if ( this.pop )
3030 {
3031 var off = this.inp.offset();
3032 var bodyWidth = $(document.body).outerWidth(true);
3033 var pickerWidth = this.div.outerWidth(true);
3034 var left = off.left;
3035 if ( left + pickerWidth > bodyWidth - 20 )
3036 left = bodyWidth - ( pickerWidth + 20 );
3037 var top = off.top - this.div.outerHeight(true);
3038 if ( top < 0 )
3039 top = off.top + this.inp.outerHeight(true);
3040 this.div.css( { top: String(top)+'px', left: String(left<0?0:left)+'px' } );
3041 }
3042
3043 var wOff = this.div.offset();
3044
3045 if ( this.oDiv && this.oDiv.is(":visible") )
3046 {
3047 var oOff = this.oLab.offset();
3048 if ( this.div.css('position') == 'absolute' )
3049 {
3050 oOff.top -= wOff.top;
3051 oOff.left = oOff.left - wOff.left;
3052 wOff = { top: 0, left: 0 };
3053 }
3054 var oW = this.oDiv.AnyTime_width(true);
3055 var wW = this.div.AnyTime_width(true);
3056 if ( oOff.left + oW > wOff.left + wW )
3057 {
3058 oOff.left = (wOff.left+wW)-oW;
3059 if ( oOff.left < 2 )
3060 oOff.left = 2;
3061 }
3062
3063 var oH = this.oDiv.AnyTime_height(true);
3064 var wH = this.div.AnyTime_height(true);
3065 oOff.top += this.oLab.AnyTime_height(true);
3066 if ( oOff.top + oH > wOff.top + wH )
3067 oOff.top = oOff.top - oH;
3068 if ( oOff.top < wOff.top )
3069 oOff.top = wOff.top;
3070
3071 this.oDiv.css( { top: oOff.top+'px', left: oOff.left+'px' } ) ;
3072 }
3073
3074 else if ( this.yDiv && this.yDiv.is(":visible") )
3075 {
3076 var yOff = this.yLab.offset();
3077 if ( this.div.css('position') == 'absolute' )
3078 {
3079 yOff.top -= wOff.top;
3080 yOff.left = yOff.left - wOff.left;
3081 wOff = { top: 0, left: 0 };
3082 }
3083 yOff.left += ( (this.yLab.outerWidth(true)-this.yDiv.outerWidth(true)) / 2 );
3084 this.yDiv.css( { top: yOff.top+'px', left: yOff.left+'px' } ) ;
3085 }
3086
3087 if ( this.cloak )
3088 this.cloak.css( {
3089 top: wOff.top+'px',
3090 left: wOff.left+'px',
3091 height: String(this.div.outerHeight(true)-2)+'px',
3092 width: String(this.div.outerWidth(!$.browser.safari)-2)+'px'
3093 } );
3094
3095 }, // .pos()
3096
3097 //---------------------------------------------------------------------
3098 // .set() changes the current time. It returns true if the new
3099 // time is within the allowed range (if any).
3100 //---------------------------------------------------------------------
3101
3102 set: function(newTime)
3103 {
3104 var t = newTime.getTime();
3105 if ( this.earliest && ( t < this.earliest ) )
3106 this.time = new Date(this.earliest);
3107 else if ( this.latest && ( t > this.latest ) )
3108 this.time = new Date(this.latest);
3109 else
3110 this.time = newTime;
3111 },
3112
3113 //---------------------------------------------------------------------
3114 // .showPkr() displays the picker and sets the focus psuedo-
3115 // element. The current value in the input field is used to initialize
3116 // the picker.
3117 //---------------------------------------------------------------------
3118
3119 showPkr: function(event)
3120 {
3121 try
3122 {
3123 this.time = this.conv.parse(this.inp.val());
3124 this.offMin = this.conv.getUtcParseOffsetCaptured();
3125 this.offSI = this.conv.getUtcParseOffsetSubIndex();
3126 }
3127 catch ( e )
3128 {
3129 this.time = new Date();
3130 }
3131 this.set(this.time);
3132 this.upd(null);
3133
3134 fBtn = null;
3135 var cb = '.AnyTime-cur-btn:first';
3136 if ( this.dDoM )
3137 fBtn = this.dDoM.find(cb);
3138 else if ( this.yCur )
3139 fBtn = this.yCur;
3140 else if ( this.dMo )
3141 fBtn = this.dMo.find(cb);
3142 else if ( this.dH )
3143 fBtn = this.dH.find(cb);
3144 else if ( this.dM )
3145 fBtn = this.dM.find(cb);
3146 else if ( this.dS )
3147 fBtn = this.dS.find(cb);
3148
3149 this.setFocus(fBtn);
3150 this.pos(event);
3151
3152 // IE6 doesn't float popups over <select> elements unless an
3153 // <iframe> is inserted between them! So after the picker is
3154 // made visible, move the <iframe> behind it.
3155
3156 if ( this.pop && __iframe )
3157 setTimeout(
3158 function()
3159 {
3160 var pos = _this.div.offset();
3161 __iframe.css( {
3162 height: String(_this.div.outerHeight(true)) + 'px',
3163 left: String(pos.left) + 'px',
3164 position: 'absolute',
3165 top: String(pos.top) + 'px',
3166 width: String(_this.div.outerWidth(true)) + 'px'
3167 } );
3168 __iframe.show();
3169 }, 300 );
3170
3171 }, // .showPkr()
3172
3173 //---------------------------------------------------------------------
3174 // .upd() updates the picker's appearance. It is called after
3175 // most events to make the picker reflect the currently-selected
3176 // values. fBtn is the psuedo-button to be given focus.
3177 //---------------------------------------------------------------------
3178
3179 upd: function(fBtn)
3180 {
3181 var cmpLo = new Date(this.time.getTime());
3182 cmpLo.setMonth(0,1);
3183 cmpLo.setHours(0,0,0,0);
3184 var cmpHi = new Date(this.time.getTime());
3185 cmpHi.setMonth(11,31);
3186 cmpHi.setHours(23,59,59,999);
3187
3188 // Update year.
3189
3190 var current = this.time.getFullYear();
3191 if ( this.earliest && this.yPast )
3192 {
3193 cmpHi.setYear(current-2);
3194 if ( cmpHi.getTime() < this.earliest )
3195 this.yPast.addClass('AnyTime-out-btn ui-state-disabled');
3196 else
3197 this.yPast.removeClass('AnyTime-out-btn ui-state-disabled');
3198 }
3199 if ( this.yPrior )
3200 {
3201 this.yPrior.text(AnyTime.pad((current==1)?(-1):(current-1),4));
3202 if ( this.earliest )
3203 {
3204 cmpHi.setYear(current-1);
3205 if ( cmpHi.getTime() < this.earliest )
3206 this.yPrior.addClass('AnyTime-out-btn ui-state-disabled');
3207 else
3208 this.yPrior.removeClass('AnyTime-out-btn ui-state-disabled');
3209 }
3210 }
3211 if ( this.yCur )
3212 this.yCur.text(AnyTime.pad(current,4));
3213 if ( this.yNext )
3214 {
3215 this.yNext.text(AnyTime.pad((current==-1)?1:(current+1),4));
3216 if ( this.latest )
3217 {
3218 cmpLo.setYear(current+1);
3219 if ( cmpLo.getTime() > this.latest )
3220 this.yNext.addClass('AnyTime-out-btn ui-state-disabled');
3221 else
3222 this.yNext.removeClass('AnyTime-out-btn ui-state-disabled');
3223 }
3224 }
3225 if ( this.latest && this.yAhead )
3226 {
3227 cmpLo.setYear(current+2);
3228 if ( cmpLo.getTime() > this.latest )
3229 this.yAhead.addClass('AnyTime-out-btn ui-state-disabled');
3230 else
3231 this.yAhead.removeClass('AnyTime-out-btn ui-state-disabled');
3232 }
3233
3234 // Update month.
3235
3236 cmpLo.setFullYear( this.time.getFullYear() );
3237 cmpHi.setFullYear( this.time.getFullYear() );
3238 var i = 0;
3239 current = this.time.getMonth();
3240 $('#'+this.id+' .AnyTime-mon-btn').each(
3241 function()
3242 {
3243 cmpLo.setMonth(i);
3244 cmpHi.setDate(1);
3245 cmpHi.setMonth(i+1);
3246 cmpHi.setDate(0);
3247 $(this).AnyTime_current( i == current,
3248 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3249 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3250 i++;
3251 } );
3252
3253 // Update days.
3254
3255 cmpLo.setFullYear( this.time.getFullYear() );
3256 cmpHi.setFullYear( this.time.getFullYear() );
3257 cmpLo.setMonth( this.time.getMonth() );
3258 cmpHi.setMonth( this.time.getMonth(), 1 );
3259 current = this.time.getDate();
3260 var currentMonth = this.time.getMonth();
3261 var dow1 = cmpLo.getDay();
3262 if ( this.fDOW > dow1 )
3263 dow1 += 7;
3264 var wom = 0, dow=0;
3265 $('#'+this.id+' .AnyTime-wk').each(
3266 function()
3267 {
3268 dow = _this.fDOW;
3269 $(this).children().each(
3270 function()
3271 {
3272 if ( dow - _this.fDOW < 7 )
3273 {
3274 var td = $(this);
3275 if ( ((wom==0)&&(dow<dow1)) || (cmpLo.getMonth()!=currentMonth) )
3276 {
3277 td.html('&#160;');
3278 td.removeClass('AnyTime-dom-btn-filled AnyTime-cur-btn ui-state-default ui-state-highlight');
3279 td.addClass('AnyTime-dom-btn-empty');
3280 if ( wom ) // not first week
3281 {
3282 if ( ( cmpLo.getDate() == 1 ) && ( dow != 0 ) )
3283 td.addClass('AnyTime-dom-btn-empty-after-filled');
3284 else
3285 td.removeClass('AnyTime-dom-btn-empty-after-filled');
3286 if ( cmpLo.getDate() <= 7 )
3287 td.addClass('AnyTime-dom-btn-empty-below-filled');
3288 else
3289 td.removeClass('AnyTime-dom-btn-empty-below-filled');
3290 cmpLo.setDate(cmpLo.getDate()+1);
3291 cmpHi.setDate(cmpHi.getDate()+1);
3292 }
3293 else // first week
3294 {
3295 td.addClass('AnyTime-dom-btn-empty-above-filled');
3296 if ( dow == dow1 - 1 )
3297 td.addClass('AnyTime-dom-btn-empty-before-filled');
3298 else
3299 td.removeClass('AnyTime-dom-btn-empty-before-filled');
3300 }
3301 td.addClass('ui-state-default ui-state-disabled');
3302 }
3303 else
3304 {
3305 i = cmpLo.getDate();
3306 td.text(i);
3307 td.removeClass('AnyTime-dom-btn-empty AnyTime-dom-btn-empty-above-filled AnyTime-dom-btn-empty-before-filled '+
3308 'AnyTime-dom-btn-empty-after-filled AnyTime-dom-btn-empty-below-filled ' +
3309 'ui-state-default ui-state-disabled');
3310 td.addClass('AnyTime-dom-btn-filled ui-state-default');
3311 td.AnyTime_current( i == current,
3312 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3313 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3314 cmpLo.setDate(i+1);
3315 cmpHi.setDate(i+1);
3316 }
3317 }
3318 dow++;
3319 } );
3320 wom++;
3321 } );
3322
3323 // Update hour.
3324
3325 cmpLo.setFullYear( this.time.getFullYear() );
3326 cmpHi.setFullYear( this.time.getFullYear() );
3327 cmpLo.setMonth( this.time.getMonth(), this.time.getDate() );
3328 cmpHi.setMonth( this.time.getMonth(), this.time.getDate() );
3329 var not12 = ! this.twelveHr;
3330 var hr = this.time.getHours();
3331 $('#'+this.id+' .AnyTime-hr-btn').each(
3332 function()
3333 {
3334 var html = this.innerHTML;
3335 var i;
3336 if ( not12 )
3337 i = Number(html);
3338 else
3339 {
3340 i = Number(html.substring(0,html.length-2) );
3341 if ( html.charAt(html.length-2) == 'a' )
3342 {
3343 if ( i == 12 )
3344 i = 0;
3345 }
3346 else if ( i < 12 )
3347 i += 12;
3348 }
3349 cmpLo.setHours(i);
3350 cmpHi.setHours(i);
3351 $(this).AnyTime_current( hr == i,
3352 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3353 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3354 if ( i < 23 )
3355 cmpLo.setHours( cmpLo.getHours()+1 );
3356 } );
3357
3358 // Update minute.
3359
3360 cmpLo.setHours( this.time.getHours() );
3361 cmpHi.setHours( this.time.getHours() );
3362 var units = this.time.getMinutes();
3363 var tens = String(Math.floor(units/10));
3364 var ones = String(units % 10);
3365 $('#'+this.id+' .AnyTime-min-ten-btn:not(.AnyTime-min-ten-btn-empty)').each(
3366 function()
3367 {
3368 $(this).AnyTime_current( this.innerHTML == tens,
3369 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3370 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3371 if ( cmpLo.getMinutes() < 50 )
3372 {
3373 cmpLo.setMinutes( cmpLo.getMinutes()+10 );
3374 cmpHi.setMinutes( cmpHi.getMinutes()+10 );
3375 }
3376 } );
3377 cmpLo.setMinutes( Math.floor(this.time.getMinutes()/10)*10 );
3378 cmpHi.setMinutes( Math.floor(this.time.getMinutes()/10)*10 );
3379 $('#'+this.id+' .AnyTime-min-one-btn:not(.AnyTime-min-one-btn-empty)').each(
3380 function()
3381 {
3382 $(this).AnyTime_current( this.innerHTML == ones,
3383 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3384 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3385 cmpLo.setMinutes( cmpLo.getMinutes()+1 );
3386 cmpHi.setMinutes( cmpHi.getMinutes()+1 );
3387 } );
3388
3389 // Update second.
3390
3391 cmpLo.setMinutes( this.time.getMinutes() );
3392 cmpHi.setMinutes( this.time.getMinutes() );
3393 units = this.time.getSeconds();
3394 tens = String(Math.floor(units/10));
3395 ones = String(units % 10);
3396 $('#'+this.id+' .AnyTime-sec-ten-btn:not(.AnyTime-sec-ten-btn-empty)').each(
3397 function()
3398 {
3399 $(this).AnyTime_current( this.innerHTML == tens,
3400 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3401 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3402 if ( cmpLo.getSeconds() < 50 )
3403 {
3404 cmpLo.setSeconds( cmpLo.getSeconds()+10 );
3405 cmpHi.setSeconds( cmpHi.getSeconds()+10 );
3406 }
3407 } );
3408 cmpLo.setSeconds( Math.floor(this.time.getSeconds()/10)*10 );
3409 cmpHi.setSeconds( Math.floor(this.time.getSeconds()/10)*10 );
3410 $('#'+this.id+' .AnyTime-sec-one-btn:not(.AnyTime-sec-one-btn-empty)').each(
3411 function()
3412 {
3413 $(this).AnyTime_current( this.innerHTML == ones,
3414 ((!_this.earliest)||(cmpHi.getTime()>=_this.earliest)) &&
3415 ((!_this.latest)||(cmpLo.getTime()<=_this.latest)) );
3416 cmpLo.setSeconds( cmpLo.getSeconds()+1 );
3417 cmpHi.setSeconds( cmpHi.getSeconds()+1 );
3418 } );
3419
3420 // Update offset (time zone).
3421
3422 if ( this.oConv )
3423 {
3424 this.oConv.setUtcFormatOffsetAlleged(this.offMin);
3425 this.oConv.setUtcFormatOffsetSubIndex(this.offSI);
3426 var tzs = this.oConv.format(this.time);
3427 this.oCur.html( tzs );
3428 }
3429
3430 // Set the focus element, then size the picker according to its
3431 // components, show the changes, and invoke Ajax if desired.
3432
3433 if ( fBtn )
3434 this.setFocus(fBtn);
3435
3436 this.conv.setUtcFormatOffsetAlleged(this.offMin);
3437 this.conv.setUtcFormatOffsetSubIndex(this.offSI);
3438 this.inp.val(this.conv.format(this.time)).change();
3439 this.div.show();
3440
3441 var d, totH = 0, totW = 0, dYW = 0, dMoW = 0, dDoMW = 0;
3442 if ( this.dY )
3443 {
3444 totW = dYW = this.dY.outerWidth(true);
3445 totH = this.yLab.AnyTime_height(true) + this.dY.AnyTime_height(true);
3446 }
3447 if ( this.dMo )
3448 {
3449 dMoW = this.dMo.outerWidth(true);
3450 if ( dMoW > totW )
3451 totW = dMoW;
3452 totH += this.hMo.AnyTime_height(true) + this.dMo.AnyTime_height(true);
3453 }
3454 if ( this.dDoM )
3455 {
3456 dDoMW = this.dDoM.outerWidth(true);
3457 if ( dDoMW > totW )
3458 totW = dDoMW;
3459 if ( __msie6 || __msie7 )
3460 {
3461 if ( dMoW > dDoMW )
3462 this.dDoM.css('width',String(dMoW)+'px');
3463 else if ( dYW > dDoMW )
3464 this.dDoM.css('width',String(dYW)+'px');
3465 }
3466 totH += this.hDoM.AnyTime_height(true) + this.dDoM.AnyTime_height(true);
3467 }
3468 if ( this.dD )
3469 {
3470 this.dD.css( { width:String(totW)+'px', height:String(totH)+'px' } );
3471 totW += this.dMinW;
3472 totH += this.dMinH;
3473 }
3474
3475 var w = 0, h = 0, timeH = 0, timeW = 0;
3476 if ( this.dH )
3477 {
3478 w = this.dH.outerWidth(true);
3479 timeW += w + 1;
3480 h = this.dH.AnyTime_height(true);
3481 if ( h > timeH )
3482 timeH = h;
3483 }
3484 if ( this.dM )
3485 {
3486 w = this.dM.outerWidth(true);
3487 timeW += w + 1;
3488 h = this.dM.AnyTime_height(true);
3489 if ( h > timeH )
3490 timeH = h;
3491 }
3492 if ( this.dS )
3493 {
3494 w = this.dS.outerWidth(true);
3495 timeW += w + 1;
3496 h = this.dS.AnyTime_height(true);
3497 if ( h > timeH )
3498 timeH = h;
3499 }
3500 if ( this.dO )
3501 {
3502 w = this.oMinW;
3503 if ( timeW < w+1 )
3504 timeW = w+1;
3505 timeH += this.dO.AnyTime_height(true);
3506 }
3507 if ( this.dT )
3508 {
3509 this.dT.css( { width:String(timeW)+'px', height:String(timeH)+'px' } );
3510 timeW += this.tMinW + 1;
3511 timeH += this.tMinH;
3512 totW += timeW;
3513 if ( timeH > totH )
3514 totH = timeH;
3515 if ( this.dO ) // stretch offset button if possible
3516 {
3517 var dOW = this.dT.width()-(this.oMinW+1);
3518 this.dO.css({width:String(dOW)+"px"});
3519 this.oCur.css({width:String(dOW-(this.oListMinW+4))+"px"});
3520 }
3521 }
3522
3523 this.dB.css({height:String(totH)+'px',width:String(totW)+'px'});
3524
3525 totH += this.bMinH;
3526 totW += this.bMinW;
3527 totH += this.hTitle.AnyTime_height(true) + this.wMinH;
3528 totW += this.wMinW;
3529 if ( this.hTitle.outerWidth(true) > totW )
3530 totW = this.hTitle.outerWidth(true); // IE quirk
3531 this.div.css({height:String(totH)+'px',width:String(totW)+'px'});
3532
3533 if ( ! this.pop )
3534 this.ajax();
3535
3536 }, // .upd()
3537
3538 //---------------------------------------------------------------------
3539 // .updODiv() updates the UTC offset selector's appearance. It is
3540 // called after most events to make the picker reflect the currently-
3541 // selected values. fBtn is the psuedo-button to be given focus.
3542 //---------------------------------------------------------------------
3543
3544 updODiv: function(fBtn)
3545 {
3546 var cur, matched = false, def = null;
3547 this.oDiv.find('.AnyTime-off-off-btn').each(
3548 function()
3549 {
3550 if ( this.AnyTime_offMin == _this.offMin )
3551 {
3552 if ( this.AnyTime_offSI == _this.offSI )
3553 $(this).AnyTime_current(matched=true,true);
3554 else
3555 {
3556 $(this).AnyTime_current(false,true);
3557 if ( def == null )
3558 def = $(this);
3559 }
3560 }
3561 else
3562 $(this).AnyTime_current(false,true);
3563 } );
3564 if ( ( ! matched ) && ( def != null ) )
3565 def.AnyTime_current(true,true);
3566
3567 // Show change
3568
3569 this.conv.setUtcFormatOffsetAlleged(this.offMin);
3570 this.conv.setUtcFormatOffsetSubIndex(this.offSI);
3571 this.inp.val(this.conv.format(this.time)).change();
3572 this.upd(fBtn);
3573
3574 }, // .updODiv()
3575
3576 //---------------------------------------------------------------------
3577 // .updYDiv() updates the year selector's appearance. It is
3578 // called after most events to make the picker reflect the currently-
3579 // selected values. fBtn is the psuedo-button to be given focus.
3580 //---------------------------------------------------------------------
3581
3582 updYDiv: function(fBtn)
3583 {
3584 var i, legal;
3585 var era = 1;
3586 var yearValue = this.time.getFullYear();
3587 if ( yearValue < 0 )
3588 {
3589 era = (-1);
3590 yearValue = 0 - yearValue;
3591 }
3592 yearValue = AnyTime.pad( yearValue, 4 );
3593 var eY = _this.earliest && new Date(_this.earliest).getFullYear();
3594 var lY = _this.latest && new Date(_this.latest).getFullYear();
3595
3596 i = 0;
3597 this.yDiv.find('.AnyTime-mil-btn').each(
3598 function()
3599 {
3600 legal = ( ((!_this.earliest)||(era*(i+(era<0?0:999))>=eY)) && ((!_this.latest)||(era*(i+(era>0?0:999))<=lY)) );
3601 $(this).AnyTime_current( this.innerHTML == yearValue.substring(0,1), legal );
3602 i += 1000;
3603 } );
3604
3605 i = (Math.floor(yearValue/1000)*1000);
3606 this.yDiv.find('.AnyTime-cent-btn').each(
3607 function()
3608 {
3609 legal = ( ((!_this.earliest)||(era*(i+(era<0?0:99))>=eY)) && ((!_this.latest)||(era*(i+(era>0?0:99))<=lY)) );
3610 $(this).AnyTime_current( this.innerHTML == yearValue.substring(1,2), legal );
3611 i += 100;
3612 } );
3613
3614 i = (Math.floor(yearValue/100)*100);
3615 this.yDiv.find('.AnyTime-dec-btn').each(
3616 function()
3617 {
3618 legal = ( ((!_this.earliest)||(era*(i+(era<0?0:9))>=eY)) && ((!_this.latest)||(era*(i+(era>0?0:9))<=lY)) );
3619 $(this).AnyTime_current( this.innerHTML == yearValue.substring(2,3), legal );
3620 i += 10;
3621 } );
3622
3623 i = (Math.floor(yearValue/10)*10);
3624 this.yDiv.find('.AnyTime-yr-btn').each(
3625 function()
3626 {
3627 legal = ( ((!_this.earliest)||(era*i>=eY)) && ((!_this.latest)||(era*i<=lY)) );
3628 $(this).AnyTime_current( this.innerHTML == yearValue.substring(3), legal );
3629 i += 1;
3630 } );
3631
3632 this.yDiv.find('.AnyTime-bce-btn').each(
3633 function()
3634 {
3635 $(this).AnyTime_current( era < 0, (!_this.earliest) || ( _this.earliest < 0 ) );
3636 } );
3637 this.yDiv.find('.AnyTime-ce-btn').each(
3638 function()
3639 {
3640 $(this).AnyTime_current( era > 0, (!_this.latest) || ( _this.latest > 0 ) );
3641 } );
3642
3643 // Show change
3644
3645 this.conv.setUtcFormatOffsetAlleged(this.offMin);
3646 this.conv.setUtcFormatOffsetSubIndex(this.offSI);
3647 this.inp.val(this.conv.format(this.time)).change();
3648 this.upd(fBtn);
3649
3650 } // .updYDiv()
3651
3652 }; // __pickers[id] = ...
3653 __pickers[id].initialize(id);
3654
3655 } // AnyTime.picker =
3656
3657 })(jQuery); // function($)...