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