1;(function(){ 2 3if (BX.date) 4 return; 5 6BX.date = {}; 7 8 9BX.date.format = function(format, timestamp, now, utc) 10{ 11 /* 12 PHP to Javascript: 13 time() = new Date() 14 mktime(...) = new Date(...) 15 gmmktime(...) = new Date(Date.UTC(...)) 16 mktime(0,0,0, 1, 1, 1970) != 0 new Date(1970,0,1).getTime() != 0 17 gmmktime(0,0,0, 1, 1, 1970) == 0 new Date(Date.UTC(1970,0,1)).getTime() == 0 18 date("d.m.Y H:i:s") = BX.date.format("d.m.Y H:i:s") 19 gmdate("d.m.Y H:i:s") = BX.date.format("d.m.Y H:i:s", null, null, true); 20 */ 21 var date = BX.type.isDate(timestamp) ? new Date(timestamp.getTime()) : BX.type.isNumber(timestamp) ? new Date(timestamp * 1000) : new Date(); 22 var nowDate = BX.type.isDate(now) ? new Date(now.getTime()) : BX.type.isNumber(now) ? new Date(now * 1000) : new Date(); 23 var isUTC = !!utc; 24 25 if (BX.type.isArray(format)) 26 return _formatDateInterval(format, date, nowDate, isUTC); 27 else if (!BX.type.isNotEmptyString(format)) 28 return ""; 29 30 var formatRegex = /\\?(sago|iago|isago|Hago|dago|mago|Yago|sdiff|idiff|Hdiff|ddiff|mdiff|Ydiff|yesterday|today|tommorow|[a-z])/gi; 31 32 var dateFormats = { 33 d : function() { 34 // Day of the month 01 to 31 35 return BX.util.str_pad_left(getDate(date).toString(), 2, "0"); 36 }, 37 38 D : function() { 39 //Mon through Sun 40 return BX.message("DOW_" + getDay(date)); 41 }, 42 43 j : function() { 44 //Day of the month 1 to 31 45 return getDate(date); 46 }, 47 48 l : function() { 49 //Sunday through Saturday 50 return BX.message("DAY_OF_WEEK_" + getDay(date)); 51 }, 52 53 N : function() { 54 //1 (for Monday) through 7 (for Sunday) 55 return getDay(date) || 7; 56 }, 57 58 S : function() { 59 //st, nd, rd or th. Works well with j 60 if (getDate(date) % 10 == 1 && getDate(date) != 11) 61 return "st"; 62 else if (getDate(date) % 10 == 2 && getDate(date) != 12) 63 return "nd"; 64 else if (getDate(date) % 10 == 3 && getDate(date) != 13) 65 return "rd"; 66 else 67 return "th"; 68 }, 69 70 w : function() { 71 //0 (for Sunday) through 6 (for Saturday) 72 return getDay(date); 73 }, 74 75 z : function() { 76 //0 through 365 77 var firstDay = new Date(getFullYear(date), 0, 1); 78 var currentDay = new Date(getFullYear(date), getMonth(date), getDate(date)); 79 return Math.ceil( (currentDay - firstDay) / (24 * 3600 * 1000) ); 80 }, 81 82 W : function() { 83 //ISO-8601 week number of year 84 var newDate = new Date(date.getTime()); 85 var dayNumber = (getDay(date) + 6) % 7; 86 setDate(newDate, getDate(newDate) - dayNumber + 3); 87 var firstThursday = newDate.getTime(); 88 setMonth(newDate, 0, 1); 89 if (getDay(newDate) != 4) 90 setMonth(newDate, 0, 1 + ((4 - getDay(newDate)) + 7) % 7); 91 var weekNumber = 1 + Math.ceil((firstThursday - newDate) / (7 * 24 * 3600 * 1000)); 92 return BX.util.str_pad_left(weekNumber.toString(), 2, "0"); 93 }, 94 95 F : function() { 96 //January through December 97 return BX.message("MONTH_" + (getMonth(date) + 1) + "_S"); 98 }, 99 100 f : function() { 101 //January through December 102 return BX.message("MONTH_" + (getMonth(date) + 1)); 103 }, 104 105 m : function() { 106 //Numeric representation of a month 01 through 12 107 return BX.util.str_pad_left((getMonth(date) + 1).toString(), 2, "0"); 108 }, 109 110 M : function() { 111 //A short textual representation of a month, three letters Jan through Dec 112 return BX.message("MON_" + (getMonth(date) + 1)); 113 }, 114 115 n : function() { 116 //Numeric representation of a month 1 through 12 117 return getMonth(date) + 1; 118 }, 119 120 t : function() { 121 //Number of days in the given month 28 through 31 122 var lastMonthDay = isUTC ? new Date(Date.UTC(getFullYear(date), getMonth(date) + 1, 0)) : new Date(getFullYear(date), getMonth(date) + 1, 0); 123 return getDate(lastMonthDay); 124 }, 125 126 L : function() { 127 //1 if it is a leap year, 0 otherwise. 128 var year = getFullYear(date); 129 return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ? 1 : 0); 130 }, 131 132 o : function() { 133 //ISO-8601 year number 134 var correctDate = new Date(date.getTime()); 135 setDate(correctDate, getDate(correctDate) - ((getDay(date) + 6) % 7) + 3); 136 return getFullYear(correctDate); 137 }, 138 139 Y : function() { 140 //A full numeric representation of a year, 4 digits 141 return getFullYear(date); 142 }, 143 144 y : function() { 145 //A two digit representation of a year 146 return getFullYear(date).toString().slice(2); 147 }, 148 149 a : function() { 150 //am or pm 151 return getHours(date) > 11 ? "pm" : "am"; 152 }, 153 154 A : function() { 155 //AM or PM 156 return getHours(date) > 11 ? "PM" : "AM"; 157 }, 158 159 B : function() { 160 //000 through 999 161 var swatch = ((date.getUTCHours() + 1) % 24) + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600; 162 return BX.util.str_pad_left(Math.floor(swatch * 1000 / 24).toString(), 3, "0"); 163 }, 164 165 g : function() { 166 //12-hour format of an hour without leading zeros 1 through 12 167 return getHours(date) % 12 || 12; 168 }, 169 170 G : function() { 171 //24-hour format of an hour without leading zeros 0 through 23 172 return getHours(date); 173 }, 174 175 h : function() { 176 //12-hour format of an hour with leading zeros 01 through 12 177 return BX.util.str_pad_left((getHours(date) % 12 || 12).toString(), 2, "0"); 178 }, 179 180 H : function() { 181 //24-hour format of an hour with leading zeros 00 through 23 182 return BX.util.str_pad_left(getHours(date).toString(), 2, "0"); 183 }, 184 185 i : function() { 186 //Minutes with leading zeros 00 to 59 187 return BX.util.str_pad_left(getMinutes(date).toString(), 2, "0"); 188 }, 189 190 s : function() { 191 //Seconds, with leading zeros 00 through 59 192 return BX.util.str_pad_left(getSeconds(date).toString(), 2, "0"); 193 }, 194 195 u : function() { 196 //Microseconds 197 return BX.util.str_pad_left((getMilliseconds(date) * 1000).toString(), 6, "0"); 198 }, 199 200 e : function() { 201 if (isUTC) 202 return "UTC"; 203 return ""; 204 }, 205 206 I : function() { 207 if (isUTC) 208 return 0; 209 210 //Whether or not the date is in daylight saving time 1 if Daylight Saving Time, 0 otherwise 211 var firstJanuary = new Date(getFullYear(date), 0, 1); 212 var firstJanuaryUTC = Date.UTC(getFullYear(date), 0, 1); 213 var firstJuly = new Date(getFullYear(date), 6, 0); 214 var firstJulyUTC = Date.UTC(getFullYear(date), 6, 0); 215 return 0 + ((firstJanuary - firstJanuaryUTC) !== (firstJuly - firstJulyUTC)); 216 }, 217 218 O : function() { 219 if (isUTC) 220 return "+0000"; 221 222 //Difference to Greenwich time (GMT) in hours +0200 223 var timezoneOffset = date.getTimezoneOffset(); 224 var timezoneOffsetAbs = Math.abs(timezoneOffset); 225 return (timezoneOffset > 0 ? "-" : "+") + BX.util.str_pad_left((Math.floor(timezoneOffsetAbs / 60) * 100 + timezoneOffsetAbs % 60).toString(), 4, "0"); 226 }, 227 228 P : function() { 229 if (isUTC) 230 return "+00:00"; 231 232 //Difference to Greenwich time (GMT) with colon between hours and minutes +02:00 233 var difference = this.O(); 234 return difference.substr(0, 3) + ":" + difference.substr(3); 235 }, 236 237 Z : function() { 238 if (isUTC) 239 return 0; 240 //Timezone offset in seconds. The offset for timezones west of UTC is always negative, 241 //and for those east of UTC is always positive. 242 return -date.getTimezoneOffset() * 60; 243 }, 244 245 c : function() { 246 //ISO 8601 date 247 return "Y-m-d\\TH:i:sP".replace(formatRegex, _replaceDateFormat); 248 }, 249 250 r : function() { 251 //RFC 2822 formatted date 252 return "D, d M Y H:i:s O".replace(formatRegex, _replaceDateFormat); 253 }, 254 255 U : function() { 256 //Seconds since the Unix Epoch 257 return Math.floor(date.getTime() / 1000); 258 }, 259 260 sago : function() { 261 return _formatDateMessage(intval((nowDate - date) / 1000), { 262 "0" : "FD_SECOND_AGO_0", 263 "1" : "FD_SECOND_AGO_1", 264 "10_20" : "FD_SECOND_AGO_10_20", 265 "MOD_1" : "FD_SECOND_AGO_MOD_1", 266 "MOD_2_4" : "FD_SECOND_AGO_MOD_2_4", 267 "MOD_OTHER" : "FD_SECOND_AGO_MOD_OTHER" 268 }); 269 }, 270 271 sdiff : function() { 272 return _formatDateMessage(intval((nowDate - date) / 1000), { 273 "0" : "FD_SECOND_DIFF_0", 274 "1" : "FD_SECOND_DIFF_1", 275 "10_20" : "FD_SECOND_DIFF_10_20", 276 "MOD_1" : "FD_SECOND_DIFF_MOD_1", 277 "MOD_2_4" : "FD_SECOND_DIFF_MOD_2_4", 278 "MOD_OTHER" : "FD_SECOND_DIFF_MOD_OTHER" 279 }); 280 }, 281 282 iago : function() { 283 return _formatDateMessage(intval((nowDate - date) / 60 / 1000), { 284 "0" : "FD_MINUTE_AGO_0", 285 "1" : "FD_MINUTE_AGO_1", 286 "10_20" : "FD_MINUTE_AGO_10_20", 287 "MOD_1" : "FD_MINUTE_AGO_MOD_1", 288 "MOD_2_4" : "FD_MINUTE_AGO_MOD_2_4", 289 "MOD_OTHER" : "FD_MINUTE_AGO_MOD_OTHER" 290 }); 291 }, 292 293 idiff : function() { 294 return _formatDateMessage(intval((nowDate - date) / 60 / 1000), { 295 "0" : "FD_MINUTE_DIFF_0", 296 "1" : "FD_MINUTE_DIFF_1", 297 "10_20" : "FD_MINUTE_DIFF_10_20", 298 "MOD_1" : "FD_MINUTE_DIFF_MOD_1", 299 "MOD_2_4" : "FD_MINUTE_DIFF_MOD_2_4", 300 "MOD_OTHER" : "FD_MINUTE_DIFF_MOD_OTHER" 301 }); 302 }, 303 304 isago : function() { 305 var minutesAgo = intval((nowDate - date) / 60 / 1000); 306 var result = _formatDateMessage(minutesAgo, { 307 "0" : "FD_MINUTE_0", 308 "1" : "FD_MINUTE_1", 309 "10_20" : "FD_MINUTE_10_20", 310 "MOD_1" : "FD_MINUTE_MOD_1", 311 "MOD_2_4" : "FD_MINUTE_MOD_2_4", 312 "MOD_OTHER" : "FD_MINUTE_MOD_OTHER" 313 }); 314 315 result += " ";
316 317 var secondsAgo = intval((nowDate - date) / 1000) - (minutesAgo * 60); 318 result += _formatDateMessage(secondsAgo, { 319 "0" : "FD_SECOND_AGO_0", 320 "1" : "FD_SECOND_AGO_1", 321 "10_20" : "FD_SECOND_AGO_10_20", 322 "MOD_1" : "FD_SECOND_AGO_MOD_1", 323 "MOD_2_4" : "FD_SECOND_AGO_MOD_2_4", 324 "MOD_OTHER" : "FD_SECOND_AGO_MOD_OTHER" 325 }); 326 return result; 327 }, 328 329 Hago : function() { 330 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 1000), { 331 "0" : "FD_HOUR_AGO_0", 332 "1" : "FD_HOUR_AGO_1", 333 "10_20" : "FD_HOUR_AGO_10_20", 334 "MOD_1" : "FD_HOUR_AGO_MOD_1", 335 "MOD_2_4" : "FD_HOUR_AGO_MOD_2_4", 336 "MOD_OTHER" : "FD_HOUR_AGO_MOD_OTHER" 337 }); 338 }, 339 340 Hdiff : function() { 341 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 1000), { 342 "0" : "FD_HOUR_DIFF_0", 343 "1" : "FD_HOUR_DIFF_1", 344 "10_20" : "FD_HOUR_DIFF_10_20", 345 "MOD_1" : "FD_HOUR_DIFF_MOD_1", 346 "MOD_2_4" : "FD_HOUR_DIFF_MOD_2_4", 347 "MOD_OTHER" : "FD_HOUR_DIFF_MOD_OTHER" 348 }); 349 }, 350 351 yesterday : function() { 352 return BX.message("FD_YESTERDAY"); 353 }, 354 355 today : function() { 356 return BX.message("FD_TODAY"); 357 }, 358 359 tommorow : function() { 360 return BX.message("FD_TOMORROW"); 361 }, 362 363 dago : function() { 364 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 1000), { 365 "0" : "FD_DAY_AGO_0", 366 "1" : "FD_DAY_AGO_1", 367 "10_20" : "FD_DAY_AGO_10_20", 368 "MOD_1" : "FD_DAY_AGO_MOD_1", 369 "MOD_2_4" : "FD_DAY_AGO_MOD_2_4", 370 "MOD_OTHER" : "FD_DAY_AGO_MOD_OTHER" 371 }); 372 }, 373 374 ddiff : function() { 375 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 1000), { 376 "0" : "FD_DAY_DIFF_0", 377 "1" : "FD_DAY_DIFF_1", 378 "10_20" : "FD_DAY_DIFF_10_20", 379 "MOD_1" : "FD_DAY_DIFF_MOD_1", 380 "MOD_2_4" : "FD_DAY_DIFF_MOD_2_4", 381 "MOD_OTHER" : "FD_DAY_DIFF_MOD_OTHER" 382 }); 383 }, 384 385 mago : function() { 386 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 31 / 1000), { 387 "0" : "FD_MONTH_AGO_0", 388 "1" : "FD_MONTH_AGO_1", 389 "10_20" : "FD_MONTH_AGO_10_20", 390 "MOD_1" : "FD_MONTH_AGO_MOD_1", 391 "MOD_2_4" : "FD_MONTH_AGO_MOD_2_4", 392 "MOD_OTHER" : "FD_MONTH_AGO_MOD_OTHER" 393 }); 394 }, 395 396 mdiff : function() { 397 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 31 / 1000), { 398 "0" : "FD_MONTH_DIFF_0", 399 "1" : "FD_MONTH_DIFF_1", 400 "10_20" : "FD_MONTH_DIFF_10_20", 401 "MOD_1" : "FD_MONTH_DIFF_MOD_1", 402 "MOD_2_4" : "FD_MONTH_DIFF_MOD_2_4", 403 "MOD_OTHER" : "FD_MONTH_DIFF_MOD_OTHER" 404 }); 405 }, 406 407 Yago : function() { 408 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 365 / 1000), { 409 "0" : "FD_YEARS_AGO_0", 410 "1" : "FD_YEARS_AGO_1", 411 "10_20" : "FD_YEARS_AGO_10_20", 412 "MOD_1" : "FD_YEARS_AGO_MOD_1", 413 "MOD_2_4" : "FD_YEARS_AGO_MOD_2_4", 414 "MOD_OTHER" : "FD_YEARS_AGO_MOD_OTHER" 415 }); 416 }, 417 418 Ydiff : function() { 419 return _formatDateMessage(intval((nowDate - date) / 60 / 60 / 24 / 365 / 1000), { 420 "0" : "FD_YEARS_DIFF_0", 421 "1" : "FD_YEARS_DIFF_1", 422 "10_20" : "FD_YEARS_DIFF_10_20", 423 "MOD_1" : "FD_YEARS_DIFF_MOD_1", 424 "MOD_2_4" : "FD_YEARS_DIFF_MOD_2_4", 425 "MOD_OTHER" : "FD_YEARS_DIFF_MOD_OTHER" 426 }); 427 }, 428 429 x : function() { 430 return BX.date.format([ 431 ["tommorow", "tommorow, H:i"], 432 ["-", BX.date.convertBitrixFormat(BX.message("FORMAT_DATETIME")).replace(/:s$/g, "")], 433 ["s", "sago"], 434 ["i", "iago"], 435 ["today", "today, H:i"], 436 ["yesterday", "yesterday, H:i"], 437 ["", BX.date.convertBitrixFormat(BX.message("FORMAT_DATETIME")).replace(/:s$/g, "")] 438 ], date, nowDate, isUTC); 439 }, 440 441 X : function() { 442 var day = BX.date.format([ 443 ["tommorow", "tommorow"], 444 ["-", BX.date.convertBitrixFormat(BX.message("FORMAT_DATE"))], 445 ["today", "today"], 446 ["yesterday", "yesterday"], 447 ["", BX.date.convertBitrixFormat(BX.message("FORMAT_DATE"))] 448 ], date, nowDate, isUTC); 449 450 var time = BX.date.format([ 451 ["tommorow", "H:i"], 452 ["today", "H:i"], 453 ["yesterday", "H:i"], 454 ["", ""] 455 ], date, nowDate, isUTC); 456 457 if (time.length > 0) 458 return BX.message("FD_DAY_AT_TIME").replace(/#DAY#/g, day).replace(/#TIME#/g, time); 459 else 460 return day; 461 }, 462 463 Q : function() { 464 var daysAgo = intval((nowDate - date) / 60 / 60 / 24 / 1000); 465 if(daysAgo == 0) 466 return BX.message("FD_DAY_DIFF_1").replace(/#VALUE#/g, 1); 467 else 468 return BX.date.format([ ["d", "ddiff"], ["m", "mdiff"], ["", "Ydiff"] ], date, nowDate); 469 } 470 }; 471 472 var cutZeroTime = false;
473 if (format[0] && format[0] == "^") 474 { 475 cutZeroTime = true; 476 format = format.substr(1); 477 } 478 479 var result = format.replace(formatRegex, _replaceDateFormat); 480 481 if (cutZeroTime) 482 { 483 /* 15.04.12 13:00:00 => 15.04.12 13:00 484 00:01:00 => 00:01 485 4 may 00:00:00 => 4 may 486 01-01-12 00:00 => 01-01-12 487 */ 488 489 result = result.replace(/\s*00:00:00\s*/g, ""). 490 replace(/(\d\d:\d\d)(:00)/g, "$1"). 491 replace(/(\s*00:00\s*)(?!:)/g, ""); 492 } 493 494 return result; 495 496 function _formatDateInterval(formats, date, nowDate, isUTC) 497 { 498 var secondsAgo = intval((nowDate - date) / 1000); 499 for (var i = 0; i < formats.length; i++) 500 { 501 var formatInterval = formats[i][0]; 502 var formatValue = formats[i][1]; 503 var match = null; 504 if (formatInterval == "s") 505 { 506 if (secondsAgo < 60) 507 return BX.date.format(formatValue, date, nowDate, isUTC); 508 } 509 else if ((match = /^s(\d+)/.exec(formatInterval)) != null) 510 { 511 if (secondsAgo < match[1]) 512 return BX.date.format(formatValue, date, nowDate, isUTC); 513 } 514 else if (formatInterval == "i") 515 { 516 if (secondsAgo < 60 * 60) 517 return BX.date.format(formatValue, date, nowDate, isUTC); 518 } 519 else if ((match = /^i(\d+)/.exec(formatInterval)) != null) 520 { 521 if (secondsAgo < match[1]*60) 522 return BX.date.format(formatValue, date, nowDate, isUTC); 523 } 524 else if (formatInterval == "H") 525 { 526 if (secondsAgo < 24 * 60 * 60) 527 return BX.date.format(formatValue, date, nowDate, isUTC); 528 } 529 else if ((match = /^H(\d+)/.exec(formatInterval)) != null) 530 { 531 if (secondsAgo < match[1] * 60 * 60) 532 return BX.date.format(formatValue, date, nowDate, isUTC); 533 } 534 else if (formatInterval == "d") 535 { 536 if (secondsAgo < 31 *24 * 60 * 60) 537 return BX.date.format(formatValue, date, nowDate, isUTC); 538 } 539 else if ((match = /^d(\d+)/.exec(formatInterval)) != null) 540 { 541 if (secondsAgo < match[1] * 60 * 60) 542 return BX.date.format(formatValue, date, nowDate, isUTC); 543 } 544 else if (formatInterval == "m") 545 { 546 if (secondsAgo < 365 * 24 * 60 * 60) 547 return BX.date.format(formatValue, date, nowDate, isUTC); 548 } 549 else if ((match = /^m(\d+)/.exec(formatInterval)) != null) 550 { 551 if (secondsAgo < match[1] * 31 * 24 * 60 * 60) 552 return BX.date.format(formatValue, date, nowDate, isUTC); 553 } 554 else if (formatInterval == "today") 555 { 556 var year = getFullYear(nowDate), month = getMonth(nowDate), day = getDate(nowDate); 557 var todayStart = isUTC ? new Date(Date.UTC(year, month, day, 0, 0, 0, 0)) : new Date(year, month, day, 0, 0, 0, 0); 558 var todayEnd = isUTC ? new Date(Date.UTC(year, month, day+1, 0, 0, 0, 0)) : new Date(year, month, day+1, 0, 0, 0, 0); 559 if (date >= todayStart && date < todayEnd) 560 return BX.date.format(formatValue, date, nowDate, isUTC); 561 } 562 else if (formatInterval == "yesterday") 563 { 564 year = getFullYear(nowDate); month = getMonth(nowDate); day = getDate(nowDate); 565 var yesterdayStart = isUTC ? new Date(Date.UTC(year, month, day-1, 0, 0, 0, 0)) : new Date(year, month, day-1, 0, 0, 0, 0); 566 var yesterdayEnd = isUTC ? new Date(Date.UTC(year, month, day, 0, 0, 0, 0)) : new Date(year, month, day, 0, 0, 0, 0); 567 if (date >= yesterdayStart && date < yesterdayEnd) 568 return BX.date.format(formatValue, date, nowDate, isUTC); 569 } 570 else if (formatInterval == "tommorow") 571 { 572 year = getFullYear(nowDate); month = getMonth(nowDate); day = getDate(nowDate); 573 var tommorowStart = isUTC ? new Date(Date.UTC(year, month, day+1, 0, 0, 0, 0)) : new Date(year, month, day+1, 0, 0, 0, 0); 574 var tommorowEnd = isUTC ? new Date(Date.UTC(year, month, day+2, 0, 0, 0, 0)) : new Date(year, month, day+2, 0, 0, 0, 0); 575 if (date >= tommorowStart && date < tommorowEnd) 576 return BX.date.format(formatValue, date, nowDate, isUTC); 577 } 578 else if (formatInterval == "-") 579 { 580 if (secondsAgo < 0) 581 return BX.date.format(formatValue, date, nowDate, isUTC); 582 } 583 } 584 585 return formats.length > 0 ? BX.date.format(formats.pop()[1], date, nowDate, isUTC) : ""; 586 } 587 588 589 function getFullYear(date) { return isUTC ? date.getUTCFullYear() : date.getFullYear(); } 590 function getDate(date) { return isUTC ? date.getUTCDate() : date.getDate(); } 591 function getMonth(date) { return isUTC ? date.getUTCMonth() : date.getMonth(); } 592 function getHours(date) { return isUTC ? date.getUTCHours() : date.getHours(); } 593 function getMinutes(date) { return isUTC ? date.getUTCMinutes() : date.getMinutes(); } 594 function getSeconds(date) { return isUTC ? date.getUTCSeconds() : date.getSeconds(); } 595 function getMilliseconds(date) { return isUTC ? date.getUTCMilliseconds() : date.getMilliseconds(); } 596 function getDay(date) { return isUTC ? date.getUTCDay() : date.getDay(); } 597 function setDate(date, dayValue) { return isUTC ? date.setUTCDate(dayValue) : date.setDate(dayValue); } 598 function setMonth(date, monthValue, dayValue) { return isUTC ? date.setUTCMonth(monthValue, dayValue) : date.setMonth(monthValue, dayValue); } 599 600 function _formatDateMessage(value, messages) 601 { 602 var val = value < 100 ? Math.abs(value) : Math.abs(value % 100); 603 var dec = val % 10; 604 var message = ""; 605 606 if(val == 0) 607 message = BX.message(messages["0"]); 608 else if (val == 1) 609 message = BX.message(messages["1"]); 610 else if (val >= 10 && val <= 20) 611 message = BX.message(messages["10_20"]); 612 else if (dec == 1) 613 message = BX.message(messages["MOD_1"]); 614 else if (2 <= dec && dec <= 4) 615 message = BX.message(messages["MOD_2_4"]); 616 else 617 message = BX.message(messages["MOD_OTHER"]); 618 619 return message.replace(/#VALUE#/g, value); 620 } 621 622 function _replaceDateFormat(match, matchFull) 623 { 624 if (dateFormats[match]) 625 return dateFormats[match](); 626 else 627 return matchFull; 628 } 629 630 function intval(number) 631 { 632 return number >= 0 ? Math.floor(number) : Math.ceil(number); 633 } 634}; 635 636BX.date.convertBitrixFormat = function(format) 637{ 638 if (!BX.type.isNotEmptyString(format)) 639 return ""; 640 641 return format.replace("YYYY", "Y") // 1999 642 .replace("MMMM", "F") // January - December 643 .replace("MM", "m") // 01 - 12 644 .replace("M", "M") // Jan - Dec 645 .replace("DD", "d") // 01 - 31 646 .replace("G", "g") // 1 - 12
647 .replace(/GG/i, "G") // 0 - 23 648 .replace("H", "h") // 01 - 12 649 .replace(/HH/i, "H") // 00 - 24 650 .replace("MI", "i") // 00 - 59 651 .replace("SS", "s") // 00 - 59 652 .replace("TT", "A") // AM - PM 653 .replace("T", "a"); // am - pm 654}; 655 656BX.date.convertToUTC = function(date) 657{ 658 if (!BX.type.isDate(date)) 659 return null; 660 return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())); 661}; 662 663/* 664 function creates and returns Javascript Date() object from server timestamp regardless of local browser (system) timezone. 665 For example can be used to convert timestamp from some exact date on server to the JS Date object with the same value. 666 667 params: { 668 timestamp: timestamp in seconds 669 } 670 */ 671BX.date.getNewDate = function(timestamp) 672{ 673 return new Date(BX.date.getBrowserTimestamp(timestamp)); 674}; 675 676/* 677 function transforms server timestamp (in sec) to javascript timestamp (calculated depend on local browser timezone offset). Returns timestamp in milliseconds. 678 Also see BX.date.getNewDate description. 679 680 params: { 681 timestamp: timestamp in seconds 682 } 683 */ 684BX.date.getBrowserTimestamp = function(timestamp) 685{ 686 timestamp = parseInt(timestamp, 10); 687 var browserOffset = new Date(timestamp * 1000).getTimezoneOffset() * 60; 688 return (parseInt(timestamp, 10) + parseInt(BX.message('SERVER_TZ_OFFSET')) + browserOffset) * 1000; 689}; 690 691/* 692 function transforms local browser timestamp (in ms) to server timestamp (calculated depend on local browser timezone offset). Returns timestamp in seconds. 693 694 params: { 695 timestamp: timestamp in milliseconds 696 } 697 */ 698BX.date.getServerTimestamp = function(timestamp) 699{ 700 timestamp = parseInt(timestamp, 10); 701 var browserOffset = new Date(timestamp).getTimezoneOffset() * 60; 702 return Math.round(timestamp / 1000 - (parseInt(BX.message('SERVER_TZ_OFFSET'), 10) + parseInt(browserOffset, 10))); 703}; 704 705/************************************** calendar class **********************************/ 706 707var obCalendarSingleton = null; 708 709/* 710params: { 711 node: bind element || document.body 712 713 value - start value in site format (using 'field' param if 'value' does not exist) 714 callback - date check handler. can return false to prevent calendar closing. 715 callback_after - another handler, called after date picking 716 717 field - field to read/write data 718 719 bTime = true - whether to enable time control 720 bHideTime = false - whether to hide time control by default 721 722 currentTime - current UTC time() 723 724} 725*/ 726 727 728BX.calendar = function(params) 729{ 730 return BX.calendar.get().Show(params); 731}; 732 733BX.calendar.get = function() 734{ 735 if (!obCalendarSingleton) 736 obCalendarSingleton = new BX.JCCalendar(); 737 738 return obCalendarSingleton; 739}; 740 741// simple func for compatibility with the oldies 742BX.calendar.InsertDaysBack = function(input, days) 743{ 744 if (days != '') 745 { 746 var d = new Date(); 747 if(days > 0) 748 { 749 d.setTime(d.valueOf() - days*86400000); 750 } 751 752 input.value = BX.date.format(BX.date.convertBitrixFormat(BX.message('FORMAT_DATE')), d, null); 753 } 754 else 755 { 756 input.value = ''; 757 } 758}; 759 760BX.calendar.ValueToString = function(value, bTime, bUTC) 761{ 762 return BX.date.format( 763 BX.date.convertBitrixFormat(BX.message(bTime ? 'FORMAT_DATETIME' : 'FORMAT_DATE')), 764 value, 765 null, 766 !!bUTC 767 ); 768}; 769 770 771BX.CalendarPeriod = 772{ 773 Init: function(inputFrom, inputTo, selPeriod) 774 { 775 if((inputFrom.value != "" || inputTo.value != "") && selPeriod.value == "") 776 selPeriod.value = "interval"; 777 778 selPeriod.onchange(); 779 }, 780 781 ChangeDirectOpts: function(peroidValue, selPParent) // "week" || "others" 782 { 783 var selDirect = BX.findChild(selPParent, {'className':'adm-select adm-calendar-direction'}, true); 784 785 if(peroidValue == "week") 786 { 787 selDirect.options[0].text = BX.message('JSADM_CALEND_PREV_WEEK'); 788 selDirect.options[1].text = BX.message('JSADM_CALEND_CURR_WEEK'); 789 selDirect.options[2].text = BX.message('JSADM_CALEND_NEXT_WEEK'); 790 } 791 else 792 { 793 selDirect.options[0].text = BX.message('JSADM_CALEND_PREV'); 794 selDirect.options[1].text = BX.message('JSADM_CALEND_CURR'); 795 selDirect.options[2].text = BX.message('JSADM_CALEND_NEXT'); 796 } 797 }, 798 799 SaveAndClearInput: function(oInput) 800 { 801 if(!window.SavedPeriodValues) 802 window.SavedPeriodValues = {}; 803 804 window.SavedPeriodValues[oInput.id] = oInput.value; 805 oInput.value=""; 806 }, 807 808 RestoreInput: function(oInput) 809 { 810 if(!window.SavedPeriodValues || !window.SavedPeriodValues[oInput.id]) 811 return; 812 813 oInput.value = window.SavedPeriodValues[oInput.id]; 814 delete(window.SavedPeriodValues[oInput.id]); 815 }, 816 817 OnChangeP: function(sel) 818 { 819 var selPParent = sel.parentNode.parentNode; 820 var bShowFrom, bShowTo, bShowDirect, bShowSeparate; 821 bShowFrom = bShowTo = bShowDirect = bShowSeparate = false;
822 823 var inputFromWrap = BX.findChild(selPParent, {'className':'adm-input-wrap adm-calendar-inp adm-calendar-first'}); 824 var inputToWrap = BX.findChild(selPParent, {'className':'adm-input-wrap adm-calendar-second'}); 825 var selDirectWrap = BX.findChild(selPParent, {'className':'adm-select-wrap adm-calendar-direction'}); 826 var separator = BX.findChild(selPParent, {'className':'adm-calendar-separate'}); 827 var inputFrom = BX.findChild(selPParent, {'className':'adm-input adm-calendar-from'},true); 828 var inputTo = BX.findChild(selPParent, {'className':'adm-input adm-calendar-to'},true); 829 830 // define who must be shown 831 switch (sel.value) 832 { 833 case "day": 834 case "week": 835 case "month": 836 case "quarter": 837 case "year": 838 bShowDirect=true; 839 BX.CalendarPeriod.OnChangeD(selDirectWrap.children[0]); 840 break; 841 842 case "before": 843 bShowTo = true; 844 break; 845 846 case "after": 847 bShowFrom = true; 848 break; 849 850 case "exact": 851 bShowFrom= true; 852 break; 853 854 case "interval": 855 bShowFrom = bShowTo = bShowSeparate = true; 856 BX.CalendarPeriod.RestoreInput(inputFrom); 857 BX.CalendarPeriod.RestoreInput(inputTo); 858 859 break; 860 861 case "": 862 BX.CalendarPeriod.SaveAndClearInput(inputFrom); 863 BX.CalendarPeriod.SaveAndClearInput(inputTo); 864 break; 865 866 default: 867 break; 868 869 } 870 871 BX.CalendarPeriod.ChangeDirectOpts(sel.value, selPParent); 872 873 inputFromWrap.style.display = (bShowFrom? 'inline-block':'none'); 874 inputToWrap.style.display = (bShowTo? 'inline-block':'none'); 875 selDirectWrap.style.display = (bShowDirect? 'inline-block':'none'); 876 separator.style.display = (bShowSeparate? 'inline-block':'none'); 877 }, 878 879 880 OnChangeD: function(sel) 881 { 882 var selPParent = sel.parentNode.parentNode; 883 var inputFrom = BX.findChild(selPParent, {'className':'adm-input adm-calendar-from'},true); 884 var inputTo = BX.findChild(selPParent, {'className':'adm-input adm-calendar-to'},true); 885 var selPeriod = BX.findChild(selPParent, {'className':'adm-select adm-calendar-period'},true); 886 887 var offset=0; 888 889 switch (sel.value) 890 { 891 case "previous": 892 offset = -1; 893 break; 894 895 case "next": 896 offset = 1; 897 break; 898 899 case "current": 900 default: 901 break; 902 903 } 904 905 var from = false; 906 var to = false; 907 908 var today = new Date(); 909 var year = today.getFullYear(); 910 var month = today.getMonth(); 911 var day = today.getDate(); 912 var dayW = today.getDay(); 913 914 if (dayW == 0) 915 dayW = 7; 916 917 switch (selPeriod.value) 918 { 919 case "day": 920 from = new Date(year, month, day+offset, 0, 0, 0); 921 to = new Date(year, month, day+offset, 23, 59, 59); 922 break; 923 924 case "week": 925 from = new Date(year, month, day-dayW+1+offset*7, 0, 0, 0); 926 to = new Date(year, month, day+(7-dayW)+offset*7, 23, 59, 59); 927 break; 928 929 case "month": 930 from = new Date(year, month+offset, 1, 0, 0, 0); 931 to = new Date(year, month+1+offset, 0, 23, 59, 59); 932 break; 933 934 case "quarter": 935 var quarterNum = Math.floor((month/3))+offset; 936 from = new Date(year, 3*(quarterNum), 1, 0, 0, 0); 937 to = new Date(year, 3*(quarterNum+1), 0, 23, 59, 59); 938 break; 939 940 case "year": 941 from = new Date(year+offset, 0, 1, 0, 0, 0); 942 to = new Date(year+1+offset, 0, 0, 23, 59, 59); 943 break; 944 945 default: 946 break; 947 } 948 949 var format = window[inputFrom.name+"_bTime"] ? BX.message('FORMAT_DATETIME') : BX.message('FORMAT_DATE'); 950 951 if(from) 952 { 953 inputFrom.value = BX.formatDate(from, format); 954 BX.addClass(inputFrom,"adm-calendar-inp-setted"); 955 } 956 957 if(to) 958 { 959 inputTo.value = BX.formatDate(to, format); 960 BX.addClass(inputTo,"adm-calendar-inp-setted"); 961 } 962 } 963}; 964 965 966BX.JCCalendar = function() 967{ 968 this.params = {}; 969 970 this.bAmPm = BX.isAmPmMode(); 971 972 this.popup = null; 973 this.popup_month = null; 974 this.popup_year = null; 975 976 this.value = null; 977 978 this.control_id = Math.random(); 979 980 this._layers = {}; 981 this._current_layer = null; 982 983 this.DIV = null; 984 this.PARTS = {}; 985 986 this.weekStart = 0; 987 this.numRows = 6; 988 989 this._create = function(params) 990 { 991 this.popup = new BX.PopupWindow('calendar_popup_' + this.control_id, params.node, { 992 closeByEsc: true, 993 autoHide: false, 994 content: this._get_content(), 995 zIndex: 3000, 996 bindOptions: {forceBindPosition: true} 997 }); 998 999 BX.bind(this.popup.popupContainer, 'click', this.popup.cancelBubble); 1000 }; 1001 1002 this._auto_hide_disable = function() 1003 { 1004 BX.unbind(document, 'click', BX.proxy(this._auto_hide, this)); 1005 }; 1006 1007 this._auto_hide_enable = function() 1008 { 1009 BX.bind(document, 'click', BX.proxy(this._auto_hide, this)); 1010 }; 1011 1012 this._auto_hide = function(e) 1013 { 1014 this._auto_hide_disable(); 1015 this.popup.close(); 1016 }; 1017 1018 this._get_content = function() 1019 { 1020 var _layer_onclick = BX.delegate(function(e) { 1021 e = e||window.event; 1022 this.SetDate(new Date(parseInt(BX.proxy_context.getAttribute('data-date'))), e.type=='dblclick') 1023 }, this); 1024 1025 this.DIV = BX.create('DIV', { 1026 props: {className: 'bx-calendar'}, 1027 children: [ 1028 BX.create('DIV', { 1029 props: { 1030 className: 'bx-calendar-header' 1031 }, 1032 children: [ 1033 BX.create('A', { 1034 attrs: {href: 'javascript:void(0)'}, 1035 props: {className: 'bx-calendar-left-arrow'}, 1036 events: {click: BX.proxy(this._prev, this)} 1037 }), 1038 1039 BX.create('SPAN', { 1040 props: {className: 'bx-calendar-header-content'}, 1041 children: [ 1042 (this.PARTS.MONTH = BX.create('A', { 1043 attrs: {href: 'javascript:void(0)'}, 1044 props: {className: 'bx-calendar-top-month'}, 1045 events: {click: BX.proxy(this._menu_month, this)} 1046 })), 1047 1048 (this.PARTS.YEAR = BX.create('A', { 1049 attrs: {href: 'javascript:void(0)'}, 1050 props: {className: 'bx-calendar-top-year'}, 1051 events: {click: BX.proxy(this._menu_year, this)} 1052 })) 1053 ] 1054 }), 1055 1056 BX.create('A', { 1057 attrs: {href: 'javascript:void(0)'}, 1058 props: {className: 'bx-calendar-right-arrow'}, 1059 events: {click: BX.proxy(this._next, this)} 1060 }) 1061 ] 1062 }), 1063 1064 (this.PARTS.WEEK = BX.create('DIV', { 1065 props: { 1066 className: 'bx-calendar-name-day-wrap' 1067 } 1068 })), 1069 1070 (this.PARTS.LAYERS = BX.create('DIV', { 1071 props: { 1072 className: 'bx-calendar-cell-block' 1073 }, 1074 events: { 1075 click: BX.delegateEvent({className: 'bx-calendar-cell'}, _layer_onclick), 1076 dblclick: BX.delegateEvent({className: 'bx-calendar-cell'}, _layer_onclick) 1077 } 1078 })), 1079 1080 (this.PARTS.TIME = BX.create('DIV', { 1081 props: { 1082 className: 'bx-calendar-set-time-wrap' 1083 }, 1084 events: { 1085 click: BX.delegateEvent( 1086 {attr: 'data-action'}, 1087 BX.delegate(this._time_actions, this) 1088 ) 1089 }, 1090 html: '<a href="javascript:void(0)" data-action="time_show" class="bx-calendar-set-time"><i></i>'+BX.message('CAL_TIME_SET')+'</a><div class="bx-calendar-form-block"><span class="bx-calendar-form-text">'+BX.message('CAL_TIME')+'</span><span class="bx-calendar-form"><input type="text" class="bx-calendar-form-input" maxwidth="2" onkeyup="BX.calendar.get()._check_time()" /><span class="bx-calendar-form-separator"></span><input type="text" class="bx-calendar-form-input" maxwidth="2" onkeyup="BX.calendar.get()._check_time()" />'+(this.bAmPm?'<span class="bx-calendar-AM-PM-block"><span class="bx-calendar-AM-PM-text" data-action="time_ampm"></span><span class="bx-calendar-form-arrow-r"><a href="javascript:void(0)" class="bx-calendar-form-arrow-top" data-action="time_ampm_up"><i></i></a><a href="javascript:void(0)" class="bx-calendar-form-arrow-bottom" data-action="time_ampm_down"><i></i></a></span></span>':'')+'</span><a href="javascript:void(0)" data-action="time_hide" class="bx-calendar-form-close"><i></i></a></div>' 1091 })), 1092 1093 BX.create('DIV', { 1094 props: {className: 'bx-calendar-button-block'}, 1095 events: { 1096 click: BX.delegateEvent( 1097 {attr: 'data-action'}, 1098 BX.delegate(this._button_actions, this) 1099 ) 1100 }, 1101 html: '<a href="javascript:void(0)" class="bx-calendar-button bx-calendar-button-select" data-action="submit"><span class="bx-calendar-button-left"></span><span class="bx-calendar-button-text">'+BX.message('CAL_BUTTON')+'</span><span class="bx-calendar-button-right"></span></a><a href="javascript:void(0)" class="bx-calendar-button bx-calendar-button-cancel" data-action="cancel"><span class="bx-calendar-button-left"></span><span class="bx-calendar-button-text">'+BX.message('JS_CORE_WINDOW_CLOSE')+'</span><span class="bx-calendar-button-right"></span></a>' 1102 }) 1103 ] 1104 }); 1105 1106 this.PARTS.TIME_INPUT_H = BX.findChild(this.PARTS.TIME, {tag: 'INPUT'}, true); 1107 this.PARTS.TIME_INPUT_M = this.PARTS.TIME_INPUT_H.nextSibling.nextSibling; 1108 1109 if (this.bAmPm) 1110 this.PARTS.TIME_AMPM = this.PARTS.TIME_INPUT_M.nextSibling.firstChild; 1111 1112 var spinner = (new BX.JCSpinner({
1113 input: this.PARTS.TIME_INPUT_H, 1114 callback_change: BX.proxy(this._check_time, this), 1115 bSaveValue: false 1116 })).Show(); 1117 spinner.className = 'bx-calendar-form-arrow-l'; 1118 this.PARTS.TIME_INPUT_H.parentNode.insertBefore(spinner, this.PARTS.TIME_INPUT_H); 1119 1120 spinner = (new BX.JCSpinner({ 1121 input: this.PARTS.TIME_INPUT_M, 1122 callback_change: BX.proxy(this._check_time, this), 1123 bSaveValue: true 1124 })).Show(); 1125 spinner.className = 'bx-calendar-form-arrow-r'; 1126 if (!this.PARTS.TIME_INPUT_M.nextSibling) 1127 this.PARTS.TIME_INPUT_M.parentNode.appendChild(spinner); 1128 else 1129 this.PARTS.TIME_INPUT_M.parentNode.insertBefore(spinner, this.PARTS.TIME_INPUT_M.nextSibling); 1130 1131 for (var i = 0; i < 7; i++) 1132 { 1133 this.PARTS.WEEK.appendChild(BX.create('SPAN', { 1134 props: { 1135 className: 'bx-calendar-name-day' 1136 }, 1137 text: BX.message('DOW_' + ((i + this.weekStart) % 7)) 1138 })); 1139 } 1140 1141 return this.DIV; 1142 }; 1143 1144 this._time_actions = function() 1145 { 1146 switch (BX.proxy_context.getAttribute('data-action')) 1147 { 1148 case 'time_show': 1149 BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1150 this.popup.adjustPosition(); 1151 break; 1152 case 'time_hide': 1153 BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1154 this.popup.adjustPosition(); 1155 break; 1156 case 'time_ampm': 1157 this.PARTS.TIME_AMPM.innerHTML = this.PARTS.TIME_AMPM.innerHTML == 'AM' ? 'PM' : 'AM'; 1158 break; 1159 case 'time_ampm_up': 1160 this._check_time({bSaveValue: false}, null, 12); 1161 return; 1162 break; 1163 case 'time_ampm_down': 1164 this._check_time({bSaveValue: false}, null, -12); 1165 return; 1166 break; 1167 } 1168 1169 this._check_time(); 1170 }; 1171 1172 this._button_actions = function() 1173 { 1174 switch (BX.proxy_context.getAttribute('data-action')) 1175 { 1176 case 'submit': 1177 this.SaveValue(); 1178 break; 1179 case 'cancel': 1180 this.Close(); 1181 break; 1182 } 1183 }; 1184 1185 this._check_time = function(params, value, direction) 1186 { 1187 var h = parseInt(this.PARTS.TIME_INPUT_H.value.substring(0,5),10)||0, 1188 m = parseInt(this.PARTS.TIME_INPUT_M.value.substring(0,5),10)||0, 1189 bChanged = false; 1190 1191 if (!!params && !params.bSaveValue) 1192 { 1193 this.value.setUTCHours(this.value.getUTCHours() + direction); 1194 } 1195 else if (!isNaN(h)) 1196 { 1197 if (this.bAmPm) 1198 { 1199 if (h != 12 && this.PARTS.TIME_AMPM.innerHTML == 'PM') 1200 { 1201 h += 12; 1202 } 1203 } 1204 1205 bChanged = true; 1206 this.value.setUTCHours(h % 24); 1207 } 1208 1209 if (!isNaN(m)) 1210 { 1211 bChanged = true; 1212 this.value.setUTCMinutes(m % 60); 1213 } 1214 1215 if (bChanged) 1216 { 1217 this.SetValue(this.value); 1218 } 1219 }; 1220 1221 this._set_layer = function() 1222 { 1223 var layerId = parseInt(this.value.getUTCFullYear() + '' + BX.util.str_pad_left(this.value.getUTCMonth()+'', 2, "0")); 1224 1225 if (!this._layers[layerId]) 1226 { 1227 this._layers[layerId] = this._create_layer(); 1228 this._layers[layerId].BXLAYERID = layerId; 1229 } 1230 1231 if (this._current_layer) 1232 { 1233 var v = new Date(this.value.valueOf()); 1234 v.setUTCHours(0); v.setUTCMinutes(0); 1235 1236 var cur_value = BX.findChild(this._layers[layerId], { 1237 tag: 'A', 1238 className: 'bx-calendar-active' 1239 }, true), 1240 new_value = BX.findChild(this._layers[layerId], { 1241 tag: 'A', 1242 attr: { 1243 'data-date' : v.valueOf() + '' 1244 } 1245 }, true); 1246 1247 if (cur_value) 1248 { 1249 BX.removeClass(cur_value, 'bx-calendar-active'); 1250 } 1251 1252 if (new_value) 1253 { 1254 BX.addClass(new_value, 'bx-calendar-active'); 1255 } 1256 1257 this._replace_layer(this._current_layer, this._layers[layerId]); 1258 } 1259 else 1260 { 1261 this.PARTS.LAYERS.appendChild(this._layers[layerId]); 1262 } 1263 1264 this._current_layer = this._layers[layerId]; 1265 }; 1266 1267 this._replace_layer = function(old_layer, new_layer) 1268 { 1269 if (old_layer != new_layer) 1270 { 1271 if (!BX.browser.IsIE() || BX.browser.IsDoctype()) 1272 { 1273 var dir = old_layer.BXLAYERID > new_layer.BXLAYERID ? 1 : -1; 1274 1275 var old_top = 0; 1276 var new_top = -dir * old_layer.offsetHeight; 1277 1278 old_layer.style.position = 'relative'; 1279 old_layer.style.top = "0px"; 1280 old_layer.style.zIndex = 5; 1281 1282 new_layer.style.position = 'absolute'; 1283 new_layer.style.top = new_top + 'px'; 1284 new_layer.style.zIndex = 6; 1285 1286 this.PARTS.LAYERS.appendChild(new_layer); 1287 1288 var delta = 15; 1289 1290 var f; 1291 (f = function() { 1292 new_top += dir * delta; 1293 old_top += dir * delta; 1294 1295 if (dir * new_top < 0) 1296 { 1297 old_layer.style.top = old_top + 'px'; 1298 new_layer.style.top = new_top + 'px'; 1299 setTimeout(f, 10); 1300 } 1301 else 1302 { 1303 old_layer.parentNode.removeChild(old_layer); 1304 1305 new_layer.style.top = "0px"; 1306 new_layer.style.position = 'static'; 1307 new_layer.style.zIndex = 0; 1308 } 1309 })(); 1310 } 1311 else 1312 {
1313 this.PARTS.LAYERS.replaceChild(new_layer, old_layer); 1314 } 1315 } 1316 }; 1317 1318 this._create_layer = function() 1319 { 1320 var l = BX.create('DIV', { 1321 props: { 1322 className: 'bx-calendar-layer' 1323 } 1324 }); 1325 1326 var month_start = new Date(this.value); 1327 month_start.setUTCHours(0); 1328 month_start.setUTCMinutes(0); 1329 1330 month_start.setUTCDate(1); 1331 1332 if (month_start.getUTCDay() != this.weekStart) 1333 { 1334 var d = month_start.getUTCDay() - this.weekStart; 1335 d += d < 0 ? 7 : 0; 1336 month_start.setUTCDate(month_start.getUTCDate()-d); 1337 } 1338 1339 var cur_month = this.value.getUTCMonth(), 1340 cur_day = this.value.getUTCDate(), 1341 s = ''; 1342 for (var i = 0; i < this.numRows; i++) 1343 { 1344 s += '<div class="bx-calendar-range' 1345 +(i == this.numRows-1 ? ' bx-calendar-range-noline' : '') 1346 +'">'; 1347 1348 for (var j = 0; j < 7; j++) 1349 { 1350 d = month_start.getUTCDate(); 1351 var wd = month_start.getUTCDay(); 1352 var className = 'bx-calendar-cell'; 1353 1354 if (cur_month != month_start.getUTCMonth()) 1355 className += ' bx-calendar-date-hidden'; 1356 else if (cur_day == d) 1357 className += ' bx-calendar-active'; 1358 1359 1360 if (wd == 0 || wd == 6) 1361 className += ' bx-calendar-weekend'; 1362 1363 s += '<a href="javascript:void(0)" class="'+className+'" data-date="' + month_start.valueOf() + '">' + d + '</a>'; 1364 1365 month_start.setUTCDate(month_start.getUTCDate()+1); 1366 } 1367 s += '</div>'; 1368 } 1369 1370 l.innerHTML = s; 1371 1372 return l; 1373 }; 1374 1375 this._prev = function() 1376 { 1377 this.SetMonth(this.value.getUTCMonth()-1); 1378 }; 1379 1380 this._next = function() 1381 { 1382 this.SetMonth(this.value.getUTCMonth()+1); 1383 }; 1384 1385 this._menu_month_content = function() 1386 { 1387 var months = '', cur_month = this.value.getMonth(), i; 1388 for (i=0; i<12; i++) 1389 { 1390 months += '<a href="javascript:void(0)" class="bx-calendar-month'+(i == cur_month ? ' bx-calendar-month-active' : '')+'" onclick="BX.calendar.get().SetMonth('+i+')">'+BX.message('MONTH_' + (i+1))+'</a>'; 1391 } 1392 1393 return '<div class="bx-calendar-month-popup"><div class="bx-calendar-month-title" onclick="BX.calendar.get().popup_month.close();">'+BX.message('MONTH_' + (this.value.getUTCMonth()+1))+'</div><div class="bx-calendar-month-content">'+months+'</div></div>'; 1394 }; 1395 1396 this._menu_month = function() 1397 { 1398 if (!this.popup_month) 1399 { 1400 this.popup_month = BX.PopupWindowManager.create( 1401 'calendar_popup_month_' + this.control_id, this.PARTS.MONTH, 1402 { 1403 content: this._menu_month_content(), 1404 zIndex: 3001, 1405 closeByEsc: true, 1406 autoHide: true, 1407 offsetTop: -29, 1408 offsetLeft: -1 1409 } 1410 ); 1411 1412 this.popup_month.BXMONTH = this.value.getUTCMonth(); 1413 } 1414 else if (this.popup_month.BXMONTH != this.value.getUTCMonth()) 1415 { 1416 this.popup_month.setContent(this._menu_month_content()); 1417 this.popup_month.BXMONTH = this.value.getUTCMonth(); 1418 } 1419 1420 this.popup_month.show(); 1421 }; 1422 1423 this._menu_year_content = function() 1424 { 1425 var s = '<div class="bx-calendar-year-popup"><div class="bx-calendar-year-title" onclick="BX.calendar.get().popup_year.close();">'+this.value.getUTCFullYear()+'</div><div class="bx-calendar-year-content" id="bx-calendar-year-content">'; 1426 1427 for (var i=-3; i <= 3; i++) 1428 { 1429 s += '<a href="javascript:void(0)" class="bx-calendar-year-number'+(i==0?' bx-calendar-year-active':'')+'" onclick="BX.calendar.get().SetYear('+(this.value.getUTCFullYear()-i)+')">'+(this.value.getUTCFullYear()-i)+'</a>'; 1430 } 1431 1432 s += '</div><input type="text" class="bx-calendar-year-input" onkeyup="if(this.value>=1900&&this.value<=2100)BX.calendar.get().SetYear(this.value);" maxlength="4" /></div>'; 1433 1434 return s; 1435 }; 1436 1437 this._menu_year = function() 1438 { 1439 if (!this.popup_year) 1440 { 1441 this.popup_year = BX.PopupWindowManager.create( 1442 'calendar_popup_year_' + this.control_id, this.PARTS.YEAR, 1443 { 1444 content: this._menu_year_content(), 1445 zIndex: 3001, 1446 closeByEsc: true, 1447 autoHide: true, 1448 offsetTop: -29, 1449 offsetLeft: -1 1450 } 1451 ); 1452 1453 this.popup_year.BXYEAR = this.value.getUTCFullYear(); 1454 } 1455 else if (this.popup_year.BXYEAR != this.value.getUTCFullYear()) 1456 { 1457 this.popup_year.setContent(this._menu_year_content()); 1458 this.popup_year.BXYEAR = this.value.getUTCFullYear(); 1459 } 1460 1461 this.popup_year.show(); 1462 }; 1463 1464 this._check_date = function(v) 1465 { 1466 var res = v; 1467 1468 if (BX.type.isString(v)) 1469 { 1470 res = BX.parseDate(v, true); 1471 } 1472 1473 if (!BX.type.isDate(res) || isNaN(res.valueOf())) 1474 { 1475 res = BX.date.convertToUTC(new Date()); 1476 if (this.params.bHideTime) 1477 { 1478 res.setUTCHours(0); 1479 res.setUTCMinutes(0); 1480 } 1481 } 1482 1483 res.setUTCMilliseconds(0); 1484 res.setUTCSeconds(0); 1485 1486 res.BXCHECKED = true; 1487 1488 return res; 1489 }; 1490}; 1491 1492BX.JCCalendar.prototype.Show = function(params) 1493{ 1494 if (!BX.isReady) 1495 { 1496 BX.ready(BX.delegate(function() {this.Show(params)}, this)); 1497 return; 1498 } 1499 1500 params.node = params.node||document.body; 1501 1502 if (BX.type.isNotEmptyString(params.node)) 1503 { 1504 var n = BX(params.node); 1505 if (!n) 1506 { 1507 n = document.getElementsByName(params.node); 1508 if (n && n.length > 0) 1509 { 1510 n = n[0] 1511 } 1512 } 1513 params.node = n; 1514 } 1515 1516 if (!params.node) 1517 return; 1518 1519 if (!!params.field) 1520 { 1521 if (BX.type.isString(params.field)) 1522 { 1523 n = BX(params.field); 1524 if (!!n) 1525 { 1526 params.field = n; 1527 } 1528 else 1529 {
1530 if (params.form) 1531 { 1532 if (BX.type.isString(params.form)) 1533 { 1534 params.form = document.forms[params.form]; 1535 } 1536 } 1537 1538 if (BX.type.isDomNode(params.form) && !!params.form[params.field]) 1539 { 1540 params.field = params.form[params.field]; 1541 } 1542 else 1543 { 1544 n = document.getElementsByName(params.field); 1545 if (n && n.length > 0) 1546 { 1547 n = n[0]; 1548 params.field = n; 1549 } 1550 } 1551 } 1552 1553 if (BX.type.isString(params.field)) 1554 { 1555 params.field = BX(params.field); 1556 } 1557 } 1558 } 1559 1560 var bShow = !this.popup || !this.popup.isShown() || this.params.node != params.node; 1561 1562 this.params = params; 1563 1564 this.params.bTime = typeof this.params.bTime == 'undefined' ? true : !!this.params.bTime; 1565 this.params.bHideTime = typeof this.params.bHideTime == 'undefined' ? true : !!this.params.bHideTime; 1566 1567 this.weekStart = parseInt(this.params.weekStart || this.params.weekStart || BX.message('WEEK_START')); 1568 if (isNaN(this.weekStart)) 1569 this.weekStart = 1; 1570 1571 if (!this.popup) 1572 { 1573 this._create(this.params); 1574 } 1575 else 1576 { 1577 this.popup.setBindElement(this.params.node); 1578 } 1579 1580 var bHideTime = !!this.params.bHideTime; 1581 if (this.params.value) 1582 { 1583 this.SetValue(this.params.value); 1584 bHideTime = this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0; 1585 } 1586 else if (this.params.field) 1587 { 1588 this.SetValue(this.params.field.value); 1589 bHideTime = this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0; 1590 } 1591 else if (!!this.params.currentTime) 1592 { 1593 this.SetValue(this.params.currentTime); 1594 } 1595 else 1596 { 1597 this.SetValue(); 1598 } 1599 1600 if (!!this.params.bTime) 1601 BX.removeClass(this.DIV, 'bx-calendar-time-disabled'); 1602 else 1603 BX.addClass(this.DIV, 'bx-calendar-time-disabled'); 1604 1605 if (!!bHideTime) 1606 BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1607 else 1608 BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1609 1610 if (bShow) 1611 { 1612 this._auto_hide_disable(); 1613 this.popup.show(); 1614 setTimeout(BX.proxy(this._auto_hide_enable, this), 0); 1615 } 1616 1617 this.params.bSetFocus = typeof this.params.bSetFocus == 'undefined' ? true : !!this.params.bSetFocus; 1618 if(this.params.bSetFocus) 1619 params.node.blur(); 1620 1621 return this; 1622}; 1623 1624BX.JCCalendar.prototype.SetDay = function(d) 1625{ 1626 this.value.setUTCDate(d); 1627 return this.SetValue(this.value); 1628}; 1629 1630BX.JCCalendar.prototype.SetMonth = function(m) 1631{ 1632 if (this.popup_month) 1633 this.popup_month.close(); 1634 1635 this.value.setUTCMonth(m); 1636 1637 if(m < 0) 1638 m += 12; 1639 else if (m >= 12) 1640 m -= 12; 1641 1642 while(this.value.getUTCMonth() > m) 1643 { 1644 this.value.setUTCDate(this.value.getUTCDate()-1); 1645 } 1646 1647 return this.SetValue(this.value); 1648}; 1649 1650BX.JCCalendar.prototype.SetYear = function(y) 1651{ 1652 if (this.popup_year) 1653 this.popup_year.close(); 1654 this.value.setUTCFullYear(y); 1655 return this.SetValue(this.value); 1656}; 1657 1658BX.JCCalendar.prototype.SetDate = function(v, bSet) 1659{ 1660 v = this._check_date(v); 1661 v.setUTCHours(this.value.getUTCHours()); 1662 v.setUTCMinutes(this.value.getUTCMinutes()); 1663 v.setUTCSeconds(this.value.getUTCSeconds()); 1664 1665 if (this.params.bTime && !bSet) 1666 { 1667 return this.SetValue(v); 1668 } 1669 else 1670 { 1671 this.SetValue(v); 1672 this.SaveValue(); 1673 } 1674}; 1675 1676BX.JCCalendar.prototype.SetValue = function(v) 1677{ 1678 this.value = (v && v.BXCHECKED) ? v : this._check_date(v); 1679 1680 this.PARTS.MONTH.innerHTML = BX.message('MONTH_' + (this.value.getUTCMonth()+1)); 1681 this.PARTS.YEAR.innerHTML = this.value.getUTCFullYear(); 1682 1683 if (!!this.params.bTime) 1684 { 1685 var h = this.value.getUTCHours(); 1686 if (this.bAmPm) 1687 { 1688 if (h >= 12) 1689 { 1690 this.PARTS.TIME_AMPM.innerHTML = 'PM'; 1691 1692 if (h != 12) 1693 h -= 12; 1694 } 1695 else 1696 { 1697 this.PARTS.TIME_AMPM.innerHTML = 'AM'; 1698 1699 if (h == 0) 1700 h = 12; 1701 } 1702 } 1703 1704 this.PARTS.TIME_INPUT_H.value = BX.util.str_pad_left(h.toString(), 2, "0"); 1705 this.PARTS.TIME_INPUT_M.value = BX.util.str_pad_left(this.value.getUTCMinutes().toString(), 2, "0"); 1706 } 1707 1708 this._set_layer(); 1709 1710 return this; 1711}; 1712 1713BX.JCCalendar.prototype.SaveValue = function() 1714{ 1715 if (this.popup_month) 1716 this.popup_month.close(); 1717 if (this.popup_year) 1718 this.popup_year.close(); 1719 1720 var bSetValue = true; 1721 if (!!this.params.callback) 1722 { 1723 var res = this.params.callback.apply(this, [new Date(this.value.valueOf()+this.value.getTimezoneOffset()*60000)]); 1724 if (res === false) 1725 bSetValue = false;
1726 } 1727 1728 if (bSetValue) 1729 { 1730 var bTime = !!this.params.bTime && BX.hasClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1731 1732 if (this.params.field) 1733 { 1734 this.params.field.value = BX.calendar.ValueToString(this.value, bTime, true); 1735 BX.fireEvent(this.params.field, 'change'); 1736 } 1737 1738 this.popup.close(); 1739 1740 if (!!this.params.callback_after) 1741 { 1742 this.params.callback_after.apply(this, [new Date(this.value.valueOf()+this.value.getTimezoneOffset()*60000), bTime]); 1743 } 1744 } 1745 1746 return this; 1747}; 1748 1749BX.JCCalendar.prototype.Close = function() 1750{ 1751 if (!!this.popup) 1752 this.popup.close(); 1753 1754 return this; 1755}; 1756 1757BX.JCSpinner = function(params) 1758{ 1759 params = params || {}; 1760 this.params = { 1761 input: params.input || null, 1762 1763 delta: params.delta || 1, 1764 1765 timeout_start: params.timeout_start || 1000, 1766 timeout_cont: params.timeout_cont || 150, 1767 1768 callback_start: params.callback_start || null, 1769 callback_change: params.callback_change || null, 1770 callback_finish: params.callback_finish || null, 1771 1772 bSaveValue: typeof params.bSaveValue == 'undefined' ? !!params.input : !!params.bSaveValue 1773 }; 1774 1775 this.mousedown = false; 1776 this.direction = 1; 1777}; 1778 1779BX.JCSpinner.prototype.Show = function() 1780{ 1781 this.node = BX.create('span', { 1782 events: { 1783 mousedown: BX.delegateEvent( 1784 {attr: 'data-dir'}, 1785 BX.delegate(this.Start, this) 1786 ) 1787 }, 1788 html: '<a href="javascript:void(0)" class="bx-calendar-form-arrow bx-calendar-form-arrow-top" data-dir="1"><i></i></a><a href="javascript:void(0)" class="bx-calendar-form-arrow bx-calendar-form-arrow-bottom" data-dir="-1"><i></i></a>' 1789 }); 1790 return this.node; 1791}; 1792 1793BX.JCSpinner.prototype.Start = function() 1794{ 1795 this.mousedown = true; 1796 this.direction = BX.proxy_context.getAttribute('data-dir') > 0 ? 1 : -1; 1797 BX.bind(document, "mouseup", BX.proxy(this.MouseUp, this)); 1798 this.ChangeValue(true); 1799}; 1800 1801BX.JCSpinner.prototype.ChangeValue = function(bFirst) 1802{ 1803 if(!this.mousedown) 1804 return; 1805 1806 if (this.params.input) 1807 { 1808 var v = parseInt(this.params.input.value, 10) + this.params.delta * this.direction; 1809 1810 if (this.params.bSaveValue) 1811 this.params.input.value = v; 1812 1813 if (!!bFirst && this.params.callback_start) 1814 this.params.callback_start(this.params, v, this.direction); 1815 1816 if (this.params.callback_change) 1817 this.params.callback_change(this.params, v, this.direction); 1818 1819 setTimeout( 1820 BX.proxy(this.ChangeValue, this), 1821 !!bFirst ? this.params.timeout_start : this.params.timeout_cont 1822 ); 1823 } 1824}; 1825 1826BX.JCSpinner.prototype.MouseUp = function() 1827{ 1828 this.mousedown = false; 1829 BX.unbind(document, "mouseup", BX.proxy(this.MouseUp, this)); 1830 1831 if (this.params.callback_finish) 1832 this.params.callback_finish(this.params, this.params.input.value); 1833}; 1834 1835/**************** compatibility hacks ***************************/ 1836 1837window.jsCalendar = { 1838 Show: function(obj, field, fieldFrom, fieldTo, bTime, serverTime, form_name, bHideTimebar) 1839 { 1840 return BX.calendar({ 1841 node: obj, field: field, form: form_name, bTime: !!bTime, currentTime: serverTime, bHideTimebar: !!bHideTimebar 1842 }); 1843 }, 1844 1845 ValueToString: BX.calendar.ValueToString 1846}; 1847 1848 1849/************ clock popup transferred from timeman **************/ 1850 1851BX.CClockSelector = function(params) 1852{ 1853 this.params = params; 1854 1855 this.params.popup_buttons = this.params.popup_buttons || [ 1856 new BX.PopupWindowButton({ 1857 text : BX.message('CAL_BUTTON'), 1858 className : "popup-window-button-create", 1859 events : {click : BX.proxy(this.setValue, this)} 1860 }) 1861 ]; 1862 1863 this.isReady = false; 1864 1865 this.WND = new BX.PopupWindow( 1866 this.params.popup_id || 'clock_selector_popup', 1867 this.params.node, 1868 this.params.popup_config || { 1869 titleBar: {content: BX.create('SPAN', {text: BX.message('CAL_TIME')})}, 1870 offsetLeft: -45, 1871 offsetTop: -135, 1872 autoHide: true, 1873 closeIcon: true, 1874 closeByEsc: true, 1875 zIndex: this.params.zIndex 1876 } 1877 ); 1878 1879 this.SHOW = false;
1880 BX.addCustomEvent(this.WND, "onPopupClose", BX.delegate(this.onPopupClose, this)); 1881 1882 this.obClocks = {}; 1883 this.CLOCK_ID = this.params.clock_id || 'clock_selector'; 1884}; 1885 1886BX.CClockSelector.prototype.Show = function() 1887{ 1888 if (!this.isReady) 1889 { 1890 //BX.timeman.showWait(this.parent.DIV); 1891 1892 BX.addCustomEvent('onClockRegister', BX.proxy(this.onClockRegister, this)); 1893 return BX.ajax.get('/bitrix/tools/clock_selector.php', {start_time: this.params.start_time, clock_id: this.CLOCK_ID, sessid: BX.bitrix_sessid()}, BX.delegate(this.Ready, this)); 1894 } 1895 1896 this.WND.setButtons(this.params.popup_buttons); 1897 this.WND.show(); 1898 1899 this.SHOW = true; 1900 1901 if (window['bxClock_' + this.obClocks[this.CLOCK_ID]]) 1902 { 1903 setTimeout("window['bxClock_" + this.obClocks[this.CLOCK_ID] + "'].CalculateCoordinates()", 40); 1904 } 1905 1906 return true; 1907}; 1908 1909BX.CClockSelector.prototype.onClockRegister = function(obClocks) 1910{ 1911 if (obClocks[this.CLOCK_ID]) 1912 { 1913 this.obClocks[this.CLOCK_ID] = obClocks[this.CLOCK_ID]; 1914 BX.removeCustomEvent('onClockRegister', BX.proxy(this.onClockRegister, this)); 1915 } 1916}; 1917 1918BX.CClockSelector.prototype.Ready = function(data) 1919{ 1920 this.content = this.CreateContent(data); 1921 this.WND.setContent(this.content); 1922 1923 this.isReady = true; 1924 //BX.timeman.closeWait(); 1925 1926 setTimeout(BX.proxy(this.Show, this), 30); 1927}; 1928 1929BX.CClockSelector.prototype.CreateContent = function(data) 1930{ 1931 return BX.create('DIV', { 1932 events: {click: BX.PreventDefault}, 1933 html: 1934 '<div class="bx-tm-popup-clock">' + data + '</div>' 1935 }); 1936}; 1937 1938BX.CClockSelector.prototype.setValue = function(e) 1939{ 1940 if (this.params.callback) 1941 { 1942 var input = BX.findChild(this.content, {tagName: 'INPUT'}, true); 1943 this.params.callback.apply(this.params.node, [input.value]); 1944 } 1945 1946 return BX.PreventDefault(e); 1947}; 1948 1949BX.CClockSelector.prototype.closeWnd = function(e) 1950{ 1951 this.WND.close(); 1952 return (e || window.event) ? BX.PreventDefault(e) : true; 1953}; 1954 1955BX.CClockSelector.prototype.setNode = function(node) 1956{ 1957 this.WND.setBindElement(node); 1958}; 1959 1960BX.CClockSelector.prototype.setTime = function(timestamp) 1961{ 1962 this.params.start_time = timestamp; 1963 if (window['bxClock_' + this.obClocks[this.CLOCK_ID]]) 1964 { 1965 window['bxClock_' + this.obClocks[this.CLOCK_ID]].SetTime(parseInt(timestamp/3600), parseInt((timestamp%3600)/60)); 1966 } 1967}; 1968 1969BX.CClockSelector.prototype.setCallback = function(cb) 1970{ 1971 this.params.callback = cb; 1972}; 1973 1974BX.CClockSelector.prototype.onPopupClose = function() 1975{ 1976 this.SHOW = false;
1977}; 1978 1979})();
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.