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 = new BX.PopupWindow( 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 events: { 1410 onPopupShow: BX.delegate(function() { 1411 if (this.popup_year) 1412 { 1413 this.popup_year.close(); 1414 } 1415 }, this) 1416 } 1417 } 1418 ); 1419 1420 this.popup_month.BXMONTH = this.value.getUTCMonth(); 1421 } 1422 else if (this.popup_month.BXMONTH != this.value.getUTCMonth()) 1423 { 1424 this.popup_month.setContent(this._menu_month_content()); 1425 this.popup_month.BXMONTH = this.value.getUTCMonth(); 1426 } 1427 1428 this.popup_month.show(); 1429 }; 1430 1431 this._menu_year_content = function() 1432 { 1433 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">'; 1434 1435 for (var i=-3; i <= 3; i++) 1436 { 1437 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>'; 1438 } 1439 1440 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>'; 1441 1442 return s; 1443 }; 1444 1445 this._menu_year = function() 1446 { 1447 if (!this.popup_year) 1448 { 1449 this.popup_year = new BX.PopupWindow( 1450 'calendar_popup_year_' + this.control_id, this.PARTS.YEAR, 1451 { 1452 content: this._menu_year_content(), 1453 zIndex: 3001, 1454 closeByEsc: true, 1455 autoHide: true, 1456 offsetTop: -29, 1457 offsetLeft: -1, 1458 events: { 1459 onPopupShow: BX.delegate(function() { 1460 if (this.popup_month) 1461 { 1462 this.popup_month.close(); 1463 } 1464 }, this) 1465 } 1466 } 1467 ); 1468 1469 this.popup_year.BXYEAR = this.value.getUTCFullYear(); 1470 } 1471 else if (this.popup_year.BXYEAR != this.value.getUTCFullYear()) 1472 { 1473 this.popup_year.setContent(this._menu_year_content()); 1474 this.popup_year.BXYEAR = this.value.getUTCFullYear(); 1475 } 1476 1477 this.popup_year.show(); 1478 }; 1479 1480 this._check_date = function(v) 1481 { 1482 var res = v; 1483 1484 if (BX.type.isString(v)) 1485 { 1486 res = BX.parseDate(v, true); 1487 } 1488 1489 if (!BX.type.isDate(res) || isNaN(res.valueOf())) 1490 { 1491 res = BX.date.convertToUTC(new Date()); 1492 if (this.params.bHideTime) 1493 { 1494 res.setUTCHours(0); 1495 res.setUTCMinutes(0); 1496 } 1497 } 1498 1499 res.setUTCMilliseconds(0); 1500 res.setUTCSeconds(0); 1501 1502 res.BXCHECKED = true; 1503 1504 return res; 1505 }; 1506}; 1507 1508BX.JCCalendar.prototype.Show = function(params) 1509{ 1510 if (!BX.isReady) 1511 { 1512 BX.ready(BX.delegate(function() {this.Show(params)}, this)); 1513 return; 1514 } 1515 1516 params.node = params.node||document.body; 1517 1518 if (BX.type.isNotEmptyString(params.node)) 1519 { 1520 var n = BX(params.node); 1521 if (!n) 1522 { 1523 n = document.getElementsByName(params.node); 1524 if (n && n.length > 0) 1525 { 1526 n = n[0] 1527 } 1528 } 1529 params.node = n; 1530 } 1531 1532 if (!params.node) 1533 return; 1534 1535 if (!!params.field) 1536 { 1537 if (BX.type.isString(params.field)) 1538 { 1539 n = BX(params.field); 1540 if (!!n) 1541 { 1542 params.field = n; 1543 } 1544 else 1545 {
1546 if (params.form) 1547 { 1548 if (BX.type.isString(params.form)) 1549 { 1550 params.form = document.forms[params.form]; 1551 } 1552 } 1553 1554 if (BX.type.isDomNode(params.form) && !!params.form[params.field]) 1555 { 1556 params.field = params.form[params.field]; 1557 } 1558 else 1559 { 1560 n = document.getElementsByName(params.field); 1561 if (n && n.length > 0) 1562 { 1563 n = n[0]; 1564 params.field = n; 1565 } 1566 } 1567 } 1568 1569 if (BX.type.isString(params.field)) 1570 { 1571 params.field = BX(params.field); 1572 } 1573 } 1574 } 1575 1576 var bShow = !this.popup || !this.popup.isShown() || this.params.node != params.node; 1577 1578 this.params = params; 1579 1580 this.params.bTime = typeof this.params.bTime == 'undefined' ? true : !!this.params.bTime; 1581 this.params.bHideTime = typeof this.params.bHideTime == 'undefined' ? true : !!this.params.bHideTime; 1582 1583 this.weekStart = parseInt(this.params.weekStart || this.params.weekStart || BX.message('WEEK_START')); 1584 if (isNaN(this.weekStart)) 1585 this.weekStart = 1; 1586 1587 if (!this.popup) 1588 { 1589 this._create(this.params); 1590 } 1591 else 1592 { 1593 this.popup.setBindElement(this.params.node); 1594 } 1595 1596 var bHideTime = !!this.params.bHideTime; 1597 if (this.params.value) 1598 { 1599 this.SetValue(this.params.value); 1600 bHideTime = this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0; 1601 } 1602 else if (this.params.field) 1603 { 1604 this.SetValue(this.params.field.value); 1605 bHideTime = this.value.getUTCHours() <= 0 && this.value.getUTCMinutes() <= 0; 1606 } 1607 else if (!!this.params.currentTime) 1608 { 1609 this.SetValue(this.params.currentTime); 1610 } 1611 else 1612 { 1613 this.SetValue(); 1614 } 1615 1616 if (!!this.params.bTime) 1617 BX.removeClass(this.DIV, 'bx-calendar-time-disabled'); 1618 else 1619 BX.addClass(this.DIV, 'bx-calendar-time-disabled'); 1620 1621 if (!!bHideTime) 1622 BX.removeClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1623 else 1624 BX.addClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1625 1626 if (bShow) 1627 { 1628 this._auto_hide_disable(); 1629 this.popup.show(); 1630 setTimeout(BX.proxy(this._auto_hide_enable, this), 0); 1631 } 1632 1633 this.params.bSetFocus = typeof this.params.bSetFocus == 'undefined' ? true : !!this.params.bSetFocus; 1634 if(this.params.bSetFocus) 1635 params.node.blur(); 1636 1637 return this; 1638}; 1639 1640BX.JCCalendar.prototype.SetDay = function(d) 1641{ 1642 this.value.setUTCDate(d); 1643 return this.SetValue(this.value); 1644}; 1645 1646BX.JCCalendar.prototype.SetMonth = function(m) 1647{ 1648 if (this.popup_month) 1649 this.popup_month.close(); 1650 1651 this.value.setUTCMonth(m); 1652 1653 if(m < 0) 1654 m += 12; 1655 else if (m >= 12) 1656 m -= 12; 1657 1658 while(this.value.getUTCMonth() > m) 1659 { 1660 this.value.setUTCDate(this.value.getUTCDate()-1); 1661 } 1662 1663 return this.SetValue(this.value); 1664}; 1665 1666BX.JCCalendar.prototype.SetYear = function(y) 1667{ 1668 if (this.popup_year) 1669 this.popup_year.close(); 1670 this.value.setUTCFullYear(y); 1671 return this.SetValue(this.value); 1672}; 1673 1674BX.JCCalendar.prototype.SetDate = function(v, bSet) 1675{ 1676 v = this._check_date(v); 1677 v.setUTCHours(this.value.getUTCHours()); 1678 v.setUTCMinutes(this.value.getUTCMinutes()); 1679 v.setUTCSeconds(this.value.getUTCSeconds()); 1680 1681 if (this.params.bTime && !bSet) 1682 { 1683 return this.SetValue(v); 1684 } 1685 else 1686 { 1687 this.SetValue(v); 1688 this.SaveValue(); 1689 } 1690}; 1691 1692BX.JCCalendar.prototype.SetValue = function(v) 1693{ 1694 this.value = (v && v.BXCHECKED) ? v : this._check_date(v); 1695 1696 this.PARTS.MONTH.innerHTML = BX.message('MONTH_' + (this.value.getUTCMonth()+1)); 1697 this.PARTS.YEAR.innerHTML = this.value.getUTCFullYear(); 1698 1699 if (!!this.params.bTime) 1700 { 1701 var h = this.value.getUTCHours(); 1702 if (this.bAmPm) 1703 { 1704 if (h >= 12) 1705 { 1706 this.PARTS.TIME_AMPM.innerHTML = 'PM'; 1707 1708 if (h != 12) 1709 h -= 12; 1710 } 1711 else 1712 { 1713 this.PARTS.TIME_AMPM.innerHTML = 'AM'; 1714 1715 if (h == 0) 1716 h = 12; 1717 } 1718 } 1719 1720 this.PARTS.TIME_INPUT_H.value = BX.util.str_pad_left(h.toString(), 2, "0"); 1721 this.PARTS.TIME_INPUT_M.value = BX.util.str_pad_left(this.value.getUTCMinutes().toString(), 2, "0"); 1722 } 1723 1724 this._set_layer(); 1725 1726 return this; 1727}; 1728 1729BX.JCCalendar.prototype.SaveValue = function() 1730{ 1731 if (this.popup_month) 1732 this.popup_month.close(); 1733 if (this.popup_year) 1734 this.popup_year.close(); 1735 1736 var bSetValue = true; 1737 if (!!this.params.callback) 1738 { 1739 var res = this.params.callback.apply(this, [new Date(this.value.valueOf()+this.value.getTimezoneOffset()*60000)]); 1740 if (res === false) 1741 bSetValue = false;
1742 } 1743 1744 if (bSetValue) 1745 { 1746 var bTime = !!this.params.bTime && BX.hasClass(this.PARTS.TIME, 'bx-calendar-set-time-opened'); 1747 1748 if (this.params.field) 1749 { 1750 this.params.field.value = BX.calendar.ValueToString(this.value, bTime, true); 1751 BX.fireEvent(this.params.field, 'change'); 1752 } 1753 1754 this.popup.close(); 1755 1756 if (!!this.params.callback_after) 1757 { 1758 this.params.callback_after.apply(this, [new Date(this.value.valueOf()+this.value.getTimezoneOffset()*60000), bTime]); 1759 } 1760 } 1761 1762 return this; 1763}; 1764 1765BX.JCCalendar.prototype.Close = function() 1766{ 1767 if (!!this.popup) 1768 this.popup.close(); 1769 1770 return this; 1771}; 1772 1773BX.JCSpinner = function(params) 1774{ 1775 params = params || {}; 1776 this.params = { 1777 input: params.input || null, 1778 1779 delta: params.delta || 1, 1780 1781 timeout_start: params.timeout_start || 1000, 1782 timeout_cont: params.timeout_cont || 150, 1783 1784 callback_start: params.callback_start || null, 1785 callback_change: params.callback_change || null, 1786 callback_finish: params.callback_finish || null, 1787 1788 bSaveValue: typeof params.bSaveValue == 'undefined' ? !!params.input : !!params.bSaveValue 1789 }; 1790 1791 this.mousedown = false; 1792 this.direction = 1; 1793}; 1794 1795BX.JCSpinner.prototype.Show = function() 1796{ 1797 this.node = BX.create('span', { 1798 events: { 1799 mousedown: BX.delegateEvent( 1800 {attr: 'data-dir'}, 1801 BX.delegate(this.Start, this) 1802 ) 1803 }, 1804 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>' 1805 }); 1806 return this.node; 1807}; 1808 1809BX.JCSpinner.prototype.Start = function() 1810{ 1811 this.mousedown = true; 1812 this.direction = BX.proxy_context.getAttribute('data-dir') > 0 ? 1 : -1; 1813 BX.bind(document, "mouseup", BX.proxy(this.MouseUp, this)); 1814 this.ChangeValue(true); 1815}; 1816 1817BX.JCSpinner.prototype.ChangeValue = function(bFirst) 1818{ 1819 if(!this.mousedown) 1820 return; 1821 1822 if (this.params.input) 1823 { 1824 var v = parseInt(this.params.input.value, 10) + this.params.delta * this.direction; 1825 1826 if (this.params.bSaveValue) 1827 this.params.input.value = v; 1828 1829 if (!!bFirst && this.params.callback_start) 1830 this.params.callback_start(this.params, v, this.direction); 1831 1832 if (this.params.callback_change) 1833 this.params.callback_change(this.params, v, this.direction); 1834 1835 setTimeout( 1836 BX.proxy(this.ChangeValue, this), 1837 !!bFirst ? this.params.timeout_start : this.params.timeout_cont 1838 ); 1839 } 1840}; 1841 1842BX.JCSpinner.prototype.MouseUp = function() 1843{ 1844 this.mousedown = false; 1845 BX.unbind(document, "mouseup", BX.proxy(this.MouseUp, this)); 1846 1847 if (this.params.callback_finish) 1848 this.params.callback_finish(this.params, this.params.input.value); 1849}; 1850 1851/**************** compatibility hacks ***************************/ 1852 1853window.jsCalendar = { 1854 Show: function(obj, field, fieldFrom, fieldTo, bTime, serverTime, form_name, bHideTimebar) 1855 { 1856 return BX.calendar({ 1857 node: obj, field: field, form: form_name, bTime: !!bTime, currentTime: serverTime, bHideTimebar: !!bHideTimebar 1858 }); 1859 }, 1860 1861 ValueToString: BX.calendar.ValueToString 1862}; 1863 1864 1865/************ clock popup transferred from timeman **************/ 1866 1867BX.CClockSelector = function(params) 1868{ 1869 this.params = params; 1870 1871 this.params.popup_buttons = this.params.popup_buttons || [ 1872 new BX.PopupWindowButton({ 1873 text : BX.message('CAL_BUTTON'), 1874 className : "popup-window-button-create", 1875 events : {click : BX.proxy(this.setValue, this)} 1876 }) 1877 ]; 1878 1879 this.isReady = false; 1880 1881 this.WND = new BX.PopupWindow( 1882 this.params.popup_id || 'clock_selector_popup', 1883 this.params.node, 1884 this.params.popup_config || { 1885 titleBar: BX.message('CAL_TIME'), 1886 offsetLeft: -45, 1887 offsetTop: -135, 1888 autoHide: true, 1889 closeIcon: true, 1890 closeByEsc: true, 1891 zIndex: this.params.zIndex 1892 } 1893 ); 1894 1895 this.SHOW = false;
1896 BX.addCustomEvent(this.WND, "onPopupClose", BX.delegate(this.onPopupClose, this)); 1897 1898 this.obClocks = {}; 1899 this.CLOCK_ID = this.params.clock_id || 'clock_selector'; 1900}; 1901 1902BX.CClockSelector.prototype.Show = function() 1903{ 1904 if (!this.isReady) 1905 { 1906 //BX.timeman.showWait(this.parent.DIV); 1907 1908 BX.addCustomEvent('onClockRegister', BX.proxy(this.onClockRegister, this)); 1909 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)); 1910 } 1911 1912 this.WND.setButtons(this.params.popup_buttons); 1913 this.WND.show(); 1914 1915 this.SHOW = true; 1916 1917 if (window['bxClock_' + this.obClocks[this.CLOCK_ID]]) 1918 { 1919 setTimeout("window['bxClock_" + this.obClocks[this.CLOCK_ID] + "'].CalculateCoordinates()", 40); 1920 } 1921 1922 return true; 1923}; 1924 1925BX.CClockSelector.prototype.onClockRegister = function(obClocks) 1926{ 1927 if (obClocks[this.CLOCK_ID]) 1928 { 1929 this.obClocks[this.CLOCK_ID] = obClocks[this.CLOCK_ID]; 1930 BX.removeCustomEvent('onClockRegister', BX.proxy(this.onClockRegister, this)); 1931 } 1932}; 1933 1934BX.CClockSelector.prototype.Ready = function(data) 1935{ 1936 this.content = this.CreateContent(data); 1937 this.WND.setContent(this.content); 1938 1939 this.isReady = true; 1940 //BX.timeman.closeWait(); 1941 1942 setTimeout(BX.proxy(this.Show, this), 30); 1943}; 1944 1945BX.CClockSelector.prototype.CreateContent = function(data) 1946{ 1947 return BX.create('DIV', { 1948 events: {click: BX.PreventDefault}, 1949 html: 1950 '<div class="bx-tm-popup-clock">' + data + '</div>' 1951 }); 1952}; 1953 1954BX.CClockSelector.prototype.setValue = function(e) 1955{ 1956 if (this.params.callback) 1957 { 1958 var input = BX.findChild(this.content, {tagName: 'INPUT'}, true); 1959 this.params.callback.apply(this.params.node, [input.value]); 1960 } 1961 1962 return BX.PreventDefault(e); 1963}; 1964 1965BX.CClockSelector.prototype.closeWnd = function(e) 1966{ 1967 this.WND.close(); 1968 return (e || window.event) ? BX.PreventDefault(e) : true; 1969}; 1970 1971BX.CClockSelector.prototype.setNode = function(node) 1972{ 1973 this.WND.setBindElement(node); 1974}; 1975 1976BX.CClockSelector.prototype.setTime = function(timestamp) 1977{ 1978 this.params.start_time = timestamp; 1979 if (window['bxClock_' + this.obClocks[this.CLOCK_ID]]) 1980 { 1981 window['bxClock_' + this.obClocks[this.CLOCK_ID]].SetTime(parseInt(timestamp/3600), parseInt((timestamp%3600)/60)); 1982 } 1983}; 1984 1985BX.CClockSelector.prototype.setCallback = function(cb) 1986{ 1987 this.params.callback = cb; 1988}; 1989 1990BX.CClockSelector.prototype.onPopupClose = function() 1991{ 1992 this.SHOW = false;
1993}; 1994 1995})();
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.