[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 /** 2 * @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> 3 * @license GNU General Public License version 2 or later; see LICENSE.txt 4 */ 5 !(function(window, document){ 6 'use strict'; 7 8 var JoomlaCalendar = function (element) { 9 10 // Initialize only if the element exists 11 if (!element) { 12 throw new Error("Calendar setup failed:\n No valid element found, Please check your code"); 13 } 14 15 if (typeof Date.parseFieldDate !== 'function') { 16 throw new Error("Calendar setup failed:\n No valid date helper, Please check your code"); 17 } 18 19 if (element._joomlaCalendar) { 20 throw new Error('JoomlaCalendar instance already exists for the element'); 21 } 22 23 element._joomlaCalendar = this; 24 25 var self = this; 26 27 this.writable = true; 28 this.hidden = true; 29 this.params = {}; 30 this.element = element; 31 this.inputField = element.getElementsByTagName('input')[0]; 32 this.button = element.getElementsByTagName('button')[0]; 33 34 if (!this.inputField) { 35 throw new Error("Calendar setup failed:\n No valid input found, Please check your code"); 36 } 37 38 // Prepare the parameters 39 this.params = { 40 debug: false, 41 clicked: false, 42 element: {style: {display: "none"}}, 43 writable: true, 44 }; 45 46 // Localisation strings 47 var _t = Joomla.Text._; 48 this.strings = { 49 today: _t('JLIB_HTML_BEHAVIOR_TODAY', 'Today'), 50 wk: _t('JLIB_HTML_BEHAVIOR_WK', 'wk'), 51 // ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], 52 days: ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY'], 53 // ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], 54 shortDays: ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'], 55 // ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 56 months: ['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER'], 57 // ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 58 shortMonths: ['JANUARY_SHORT', 'FEBRUARY_SHORT', 'MARCH_SHORT', 'APRIL_SHORT', 'MAY_SHORT', 'JUNE_SHORT', 59 'JULY_SHORT', 'AUGUST_SHORT', 'SEPTEMBER_SHORT', 'OCTOBER_SHORT', 'NOVEMBER_SHORT', 'DECEMBER_SHORT',], 60 am: _t('JLIB_HTML_BEHAVIOR_AM', 'am'), 61 pm: _t('JLIB_HTML_BEHAVIOR_PM', 'pm'), 62 exit: _t('JCLOSE', 'Close'), 63 clear: _t('JCLEAR', 'Clear') 64 }; 65 66 // Translate lists of Days, Months 67 this.strings.days = this.strings.days.map(function (c){ 68 return _t(c); 69 }); 70 this.strings.shortDays = this.strings.shortDays.map(function (c){ 71 return _t(c); 72 }); 73 this.strings.months = this.strings.months.map(function (c){ 74 return _t(c); 75 }); 76 this.strings.shortMonths = this.strings.shortMonths.map(function (c){ 77 return _t(c); 78 }); 79 80 var btn = this.button, 81 instanceParams = { 82 inputField : this.inputField, 83 dateType : btn.dataset.dateType || 'gregorian', 84 direction : document.dir ? document.dir : document.getElementsByTagName("html")[0].getAttribute("dir"), 85 firstDayOfWeek : btn.dataset.firstday ? parseInt(btn.dataset.firstday, 10) : 0, 86 dateFormat : btn.dataset.dateFormat || "%Y-%m-%d %H:%M:%S", 87 weekend : [0,6], 88 minYear : 1000, 89 maxYear : 2100, 90 time24 : true, 91 showsOthers : true, 92 showsTime : true, 93 weekNumbers : true, 94 showsTodayBtn : true, 95 compressedHeader: false, 96 }; 97 98 if ('showOthers' in btn.dataset) { 99 instanceParams.showsOthers = parseInt(btn.dataset.showOthers, 10) === 1; 100 } 101 102 if ('weekNumbers' in btn.dataset) { 103 instanceParams.weekNumbers = parseInt(btn.dataset.weekNumbers, 10) === 1; 104 } 105 106 if ('onlyMonthsNav' in btn.dataset) { 107 instanceParams.compressedHeader = parseInt(btn.dataset.onlyMonthsNav, 10) === 1; 108 } 109 110 if ('time24' in btn.dataset) { 111 instanceParams.time24 = parseInt(btn.dataset.time24 , 10) === 24; 112 } 113 114 if ('showTime' in btn.dataset) { 115 instanceParams.showsTime = parseInt(btn.dataset.showTime, 10) === 1; 116 } 117 118 if ('todayBtn' in btn.dataset) { 119 instanceParams.showsTodayBtn = parseInt(btn.dataset.todayBtn, 10) === 1; 120 } 121 122 // Merge the parameters 123 for (var param in instanceParams) { 124 this.params[param] = instanceParams[param]; 125 } 126 127 // Evaluate the min year 128 if (btn.dataset.minYear) { 129 self.params.minYear = parseInt(btn.dataset.minYear, 10); 130 } 131 // Evaluate the max year 132 if (btn.dataset.maxYear) { 133 self.params.maxYear = parseInt(btn.dataset.maxYear, 10); 134 } 135 // Evaluate the weekend days 136 if (btn.dataset.weekend) { 137 self.params.weekend = btn.dataset.weekend.split(',').map(function(item) { return parseInt(item, 10); }); 138 } 139 140 // Legacy thing, days for RTL is reversed 141 if (this.params.direction === 'rtl') { 142 this.strings.days = this.strings.days.reverse(); 143 this.strings.shortDays = this.strings.shortDays.reverse(); 144 } 145 146 // Other calendar may have a different order for months 147 this.strings.months = Date.monthsToLocalOrder(this.strings.months, this.params.dateType); 148 this.strings.shortMonths = Date.monthsToLocalOrder(this.strings.shortMonths, this.params.dateType); 149 150 // Event handler need to define here, to be able access in current context 151 this._dayMouseDown = function(event) { 152 return self._handleDayMouseDown(event); 153 }; 154 this._calKeyEvent = function(event) { 155 return self._handleCalKeyEvent(event); 156 }; 157 this._documentClick = function(event) { 158 return self._handleDocumentClick(event); 159 }; 160 161 // Set it up 162 this.checkInputs(); 163 164 // For the fields with readonly tag calendar will not initiate fully 165 if (this.inputField.getAttribute('readonly')) { 166 return; 167 } 168 169 this._create(); 170 this._bindEvents(); 171 }; 172 173 JoomlaCalendar.prototype.checkInputs = function () { 174 // Get the date from the input 175 var inputAltValueDate = Date.parseFieldDate(this.inputField.getAttribute('data-alt-value'), this.params.dateFormat, 'gregorian', this.strings); 176 177 if (this.inputField.value !== '') { 178 this.date = inputAltValueDate; 179 this.inputField.value = inputAltValueDate.print(this.params.dateFormat, this.params.dateType, true, this.strings); 180 } else { 181 this.date = new Date(); 182 } 183 }; 184 185 /** Removes the calendar object from the DOM tree and destroys it and then recreates it. */ 186 JoomlaCalendar.prototype.recreate = function () { 187 var element = this.element, el = element.querySelector('.js-calendar'); 188 if (el) { 189 element._joomlaCalendar = null; 190 el.parentNode.removeChild(el); 191 new JoomlaCalendar(element); 192 } 193 }; 194 195 /** Time Control */ 196 JoomlaCalendar.prototype.updateTime = function (hours, mins, secs) { 197 var self = this, 198 date = self.date; 199 200 var d = self.date.getLocalDate(self.params.dateType), 201 m = self.date.getLocalMonth(self.params.dateType), 202 y = self.date.getLocalFullYear(self.params.dateType), 203 ampm = this.inputField.parentNode.parentNode.querySelectorAll('.time-ampm')[0]; 204 205 if (!self.params.time24) { 206 if (/pm/i.test(ampm.value) && hours < 12) { 207 hours = parseInt(hours) + 12; 208 } else if (/am/i.test(ampm.value) && hours == 12) { 209 hours = 0; 210 } 211 } 212 213 date.setHours(hours); 214 date.setMinutes(parseInt(mins, 10)); 215 date.setSeconds(date.getSeconds()); 216 date.setLocalFullYear(self.params.dateType, y); 217 date.setLocalMonth(self.params.dateType, m); 218 date.setLocalDate(self.params.dateType, d); 219 self.dateClicked = false; 220 221 this.callHandler(); 222 }; 223 224 /** Method to set the date to the given date object */ 225 JoomlaCalendar.prototype.setDate = function (date) { 226 if (!date.equalsTo(this.date)) { 227 this.date = date; 228 this.processCalendar(this.params.firstDayOfWeek, date); 229 } 230 }; 231 232 /** Method to set the current date by a number, step */ 233 JoomlaCalendar.prototype.moveCursorBy = function (step) { 234 var date = new Date(this.date); 235 date.setDate(date.getDate() - step); 236 this.setDate(date); 237 }; 238 239 /** Reset select element */ 240 JoomlaCalendar.prototype.resetSelected = function (element) { 241 var options = element.options; 242 var i = options.length; 243 while (i--) { 244 var current = options[i]; 245 if (current.selected) { 246 current.selected = false; 247 } 248 } 249 }; 250 251 /** Method to set the value for the input field */ 252 JoomlaCalendar.prototype.callHandler = function () { 253 /** Output the date **/ 254 this.inputField.setAttribute('data-alt-value', this.date.print(this.params.dateFormat, 'gregorian', false, this.strings)); 255 256 if (this.inputField.getAttribute('data-alt-value') && this.inputField.getAttribute('data-alt-value') !== '0000-00-00 00:00:00') { 257 this.inputField.value = this.date.print(this.params.dateFormat, this.params.dateType, true, this.strings); 258 if (this.params.dateType !== 'gregorian') { 259 this.inputField.setAttribute('data-local-value', this.date.print(this.params.dateFormat, this.params.dateType, true, this.strings)); 260 } 261 } 262 this.inputField.value = this.date.print(this.params.dateFormat, this.params.dateType, true, this.strings); 263 264 if (this.dateClicked && typeof this.params.onUpdate === "function") { 265 this.params.onUpdate(this); 266 } 267 268 this.inputField.dispatchEvent(new CustomEvent('change', {bubbles: true, cancelable: true})); 269 270 if (this.dateClicked) { 271 this.close(); 272 } else { 273 this.processCalendar(); 274 } 275 }; 276 277 /** Method to close/hide the calendar */ 278 JoomlaCalendar.prototype.close = function () { 279 this.hide(); 280 }; 281 282 /** Method to show the calendar. */ 283 JoomlaCalendar.prototype.show = function () { 284 this.checkInputs(); 285 this.inputField.focus(); 286 this.dropdownElement.classList.add('open'); 287 this.dropdownElement.removeAttribute('hidden'); 288 this.hidden = false; 289 290 document.addEventListener("keydown", this._calKeyEvent, true); 291 document.addEventListener("keypress", this._calKeyEvent, true); 292 document.addEventListener("mousedown", this._documentClick, true); 293 294 /** Move the calendar to top position if it doesn't fit below. */ 295 var containerTmp = this.element.querySelector('.js-calendar'); 296 297 if (window.innerHeight < containerTmp.getBoundingClientRect().bottom + 20) { 298 containerTmp.style.marginTop = - (containerTmp.getBoundingClientRect().height + this.inputField.getBoundingClientRect().height) + "px"; 299 } 300 301 this.processCalendar(); 302 }; 303 304 /** Method to hide the calendar. */ 305 JoomlaCalendar.prototype.hide = function () { 306 document.removeEventListener("keydown", this._calKeyEvent, true); 307 document.removeEventListener("keypress", this._calKeyEvent, true); 308 document.removeEventListener("mousedown", this._documentClick, true); 309 310 this.dropdownElement.classList.remove('open'); 311 this.dropdownElement.setAttribute('hidden', ''); 312 this.hidden = true; 313 }; 314 315 /** Method to catch clicks outside of the calendar (used as close call) */ 316 JoomlaCalendar.prototype._handleDocumentClick = function (ev) { 317 var el = ev.target; 318 319 if (el !== null && !el.classList.contains('time')) { 320 for (; el !== null && el !== this.element; el = el.parentNode); 321 } 322 323 if (el === null) { 324 document.activeElement.blur(); 325 this.hide(); 326 return stopCalEvent(ev); 327 } 328 }; 329 330 /** Method to handle mouse click events (menus, buttons) **/ 331 JoomlaCalendar.prototype._handleDayMouseDown = function (ev) { 332 var self = this, 333 el = ev.currentTarget, 334 target = ev.target || ev.srcElement; 335 336 if (target && target.hasAttribute('data-action')) { 337 return; 338 } 339 340 if (el.nodeName !== 'TD') { // A bootstrap inner button was pressed? 341 var testel = el.getParent('TD'); 342 if (testel.nodeName === 'TD') { // Yes so use that element's td 343 el = testel; 344 } else { // No - try to find the table this way 345 el = el.getParent('TD'); 346 if (el.classList.contains('js-calendar')) { 347 el = el.getElementsByTagName('table')[0]; 348 } 349 } 350 } else { // Check that doesn't have a button and is not a day td 351 if (!(target.classList.contains('js-btn')) && !el.classList.contains('day') && !el.classList.contains('title')) { 352 return; 353 } 354 } 355 356 if (!el || el.disabled) { 357 return false; 358 } 359 360 if (typeof el.navtype === "undefined" || el.navtype !== 300) { 361 if (el.navtype === 50) { el._current = el.innerHTML; } 362 363 if (target === el || target.parentNode === el) { self.cellClick(el, ev); } 364 365 var mon = null; 366 if (typeof el.month !== "undefined") { 367 mon = el; 368 } 369 if (typeof el.parentNode.month !== "undefined") { 370 mon = el.parentNode; 371 } 372 var date = null; 373 if (mon) { 374 date = new Date(self.date); 375 if (mon.month !== date.getLocalMonth(self.params.dateType)) { 376 date.setLocalMonth(self.params.dateType, mon.month); 377 self.setDate(date); 378 self.dateClicked = false; 379 this.callHandler(); 380 } 381 } else { 382 var year = null; 383 if (typeof el.year !== "undefined") { 384 year = target; 385 } 386 if (typeof el.parentNode.year !== "undefined") { 387 year = target.parentNode; 388 } 389 if (year) { 390 date = new Date(self.date); 391 if (year.year !== date.getLocalFullYear(self.params.dateType)) { 392 date.setFullYear(self.params.dateType, year.year); 393 self.setDate(date); 394 self.dateClicked = false; 395 this.callHandler(); 396 } 397 } 398 } 399 } 400 401 return stopCalEvent(ev); 402 }; 403 404 /** Method to handle mouse click events (dates) **/ 405 JoomlaCalendar.prototype.cellClick = function (el, ev) { 406 var self = this, 407 closing = false, 408 newdate = false, 409 date = null; 410 411 if (typeof el.navtype === "undefined") { 412 if (self.currentDateEl) { 413 el.classList.add("selected"); 414 self.currentDateEl = el.caldate; 415 closing = (self.currentDateEl === el.caldate); 416 if (!closing) { 417 self.currentDateEl = el.caldate; 418 } 419 } 420 self.date.setLocalDateOnly('gregorian', el.caldate); 421 var other_month = !(self.dateClicked = !el.otherMonth); 422 if (self.currentDateEl) { newdate = !el.disabled; } 423 if (other_month) { 424 this.processCalendar(); 425 } 426 } else { 427 date = new Date(self.date); 428 self.dateClicked = false; 429 var year = date.getOtherFullYear(self.params.dateType), mon = date.getLocalMonth(self.params.dateType); 430 switch (el.navtype) { 431 case 400: 432 break; 433 case -2: // Prev year 434 if (!self.params.compressedHeader) { 435 if (year > self.params.minYear) { 436 date.setOtherFullYear(self.params.dateType, year - 1); 437 } 438 } 439 break; 440 case -1: // Prev month 441 var day = date.getLocalDate(self.params.dateType); 442 if (mon > 0) { 443 var max = date.getLocalMonthDays(self.params.dateType, mon - 1); 444 if (day > max) { 445 date.setLocalDate(self.params.dateType, max); 446 } 447 date.setLocalMonth(self.params.dateType, mon - 1); 448 } else if (year-- > self.params.minYear) { 449 date.setOtherFullYear(self.params.dateType, year); 450 var max = date.getLocalMonthDays(self.params.dateType, 11); 451 if (day > max) { 452 date.setLocalDate(self.params.dateType, max); 453 } 454 date.setLocalMonth(self.params.dateType, 11); 455 } 456 break; 457 case 1: // Next month 458 var day = date.getLocalDate(self.params.dateType); 459 if (mon < 11) { 460 var max = date.getLocalMonthDays(self.params.dateType, mon + 1); 461 if (day > max) { 462 date.setLocalDate(self.params.dateType, max); 463 } 464 date.setLocalMonth(self.params.dateType, mon + 1); 465 } else if (year < self.params.maxYear) { 466 date.setOtherFullYear(self.params.dateType, year + 1); 467 var max = date.getLocalMonthDays(self.params.dateType, 0); 468 if (day > max) { 469 date.setLocalDate(self.params.dateType, max); 470 } 471 date.setLocalMonth(self.params.dateType, 0); 472 } 473 break; 474 case 2: // Next year 475 if (!self.params.compressedHeader) 476 if (year < self.params.maxYear) { 477 date.setOtherFullYear(self.params.dateType, year + 1); 478 } 479 break; 480 case 0: // Today 481 break; 482 } 483 484 if (!date.equalsTo(self.date)) { 485 this.setDate(date); 486 newdate = true; 487 } else if (el.navtype === 0) { 488 newdate = closing = true; 489 } 490 } 491 492 if (newdate) { 493 if (self.params.showsTime) { 494 this.dateClicked = false; 495 } 496 ev && this.callHandler(); 497 } 498 499 el.classList.remove("hilite"); 500 501 if (closing && !self.params.showsTime) { 502 self.dateClicked = false; 503 ev && this.close(); 504 } 505 }; 506 507 /** Method to handle keyboard click events **/ 508 JoomlaCalendar.prototype._handleCalKeyEvent = function (ev) { 509 var self = this, 510 K = ev.keyCode; 511 512 // Get value from input 513 if (ev.target === this.inputField && (K === 13 || K === 9)) { 514 this.close(); 515 } 516 517 if (self.params.direction === 'rtl') { 518 if (K === 37) { 519 K = 39; 520 } else if (K === 39) { 521 K = 37; 522 } 523 } 524 525 if (K === 32) { // KEY Shift + space (now) 526 if (ev.shiftKey) { 527 ev.preventDefault(); 528 this.cellClick(self._nav_now, ev); 529 self.close(); 530 } 531 } 532 if (K === 27) { // KEY esc (close); 533 this.close(); 534 } 535 if (K === 38) { // KEY up (previous week) 536 this.moveCursorBy(7); 537 } 538 if (K === 40) { // KEY down (next week) 539 this.moveCursorBy( -7); 540 } 541 if (K === 37) { // KEY left (previous day) 542 this.moveCursorBy(1); 543 } 544 if (K === 39) { // KEY right (next day) 545 this.moveCursorBy( -1); 546 } 547 if (ev.target === this.inputField && !(K>48 || K<57 || K===186 || K===189 || K===190 || K===32)) { 548 return stopCalEvent(ev); 549 } 550 }; 551 552 /** Method to create the html structure of the calendar */ 553 JoomlaCalendar.prototype._create = function () { 554 var self = this, 555 parent = this.element, 556 table = createElement("table"), 557 div = createElement("div"); 558 559 this.table = table; 560 table.className = 'table'; 561 table.style.marginBottom = 0; 562 563 this.dropdownElement = div; 564 parent.appendChild(div); 565 566 if (this.params.direction) { 567 div.style.direction = this.params.direction; 568 } 569 570 div.className = 'js-calendar'; 571 div.style.position = "absolute"; 572 div.style.boxShadow = "0 0 70px 0 rgba(0,0,0,0.67)"; 573 div.style.minWidth = this.inputField.width; 574 div.style.padding = '0'; 575 div.setAttribute('hidden', ''); 576 div.style.left = "auto"; 577 div.style.top = "auto"; 578 div.style.zIndex = 1060; 579 div.style.borderRadius = "20px"; 580 581 this.wrapper = createElement('div'); 582 this.wrapper.className = 'calendar-container'; 583 div.appendChild(this.wrapper); 584 this.wrapper.appendChild(table); 585 586 var thead = createElement("thead", table); 587 thead.className = 'calendar-header'; 588 589 var cell = null, 590 row = null, 591 cal = this, 592 hh = function (text, cs, navtype, node, styles, classes, attributes) { 593 node = node ? node : "td"; 594 styles = styles ? styles : {}; 595 cell = createElement(node, row); 596 if (cs) { 597 classes = classes ? 'class="' + classes + '"' : ''; 598 cell.colSpan = cs; 599 } 600 601 for (var key in styles) { 602 cell.style[key] = styles[key]; 603 } 604 for (var key in attributes) { 605 cell.setAttribute(key, attributes[key]); 606 } 607 if (navtype !== 0 && Math.abs(navtype) <= 2) { 608 cell.className += " nav"; 609 } 610 611 if (cs) { 612 cell.addEventListener("mousedown", self._dayMouseDown, true); 613 } 614 615 cell.calendar = cal; 616 cell.navtype = navtype; 617 if (navtype !== 0 && Math.abs(navtype) <= 2) { 618 cell.innerHTML = Joomla.sanitizeHtml("<a " + classes + " style='display:inline;padding:2px 6px;cursor:pointer;text-decoration:none;' unselectable='on'>" + text + "</a>"); 619 } else { 620 cell.innerHTML = cs ? Joomla.sanitizeHtml("<div unselectable='on'" + classes + ">" + text + "</div>") : Joomla.sanitizeHtml(text); 621 if (!cs && classes) { 622 cell.className = classes; 623 } 624 } 625 return cell; 626 }; 627 628 if (this.params.compressedHeader === false) { // Head - year 629 row = createElement("tr", thead); 630 row.className = "calendar-head-row"; 631 this._nav_py = hh("‹", 1, -2, '', {"text-align": "center", "font-size": "18px", "line-height": "18px"}, 'js-btn btn-prev-year'); // Previous year button 632 this.title = hh('<div style="text-align:center;font-size:18px"><span></span></div>', this.params.weekNumbers ? 6 : 5, 300); 633 this.title.className = "title"; 634 this._nav_ny = hh(" ›", 1, 2, '', {"text-align": "center", "font-size": "18px", "line-height": "18px"}, 'js-btn btn-next-year'); // Next year button 635 } 636 637 row = createElement("tr", thead); // Head - month 638 row.className = "calendar-head-row"; 639 this._nav_pm = hh("‹", 1, -1, '', {"text-align": "center", "font-size": "2em", "line-height": "1em"}, 'js-btn btn-prev-month'); // Previous month button 640 this._nav_month = hh('<div style="text-align:center;font-size:1.2em"><span></span></div>', this.params.weekNumbers ? 6 : 5, 888, 'td', {'textAlign': 'center'}); 641 this._nav_month.className = "title"; 642 this._nav_nm = hh(" ›", 1, 1, '', {"text-align": "center", "font-size": "2em", "line-height": "1em"}, 'js-btn btn-next-month'); // Next month button 643 644 row = createElement("tr", thead); // day names 645 row.className = self.params.weekNumbers ? "daynames wk" : "daynames"; 646 if (this.params.weekNumbers) { 647 cell = createElement("td", row); 648 cell.className = "day-name wn"; 649 cell.textContent = self.strings.wk; 650 } 651 for (var i = 7; i > 0; --i) { 652 cell = createElement("td", row); 653 if (!i) { 654 cell.calendar = self; 655 } 656 } 657 this.firstdayname = (this.params.weekNumbers) ? row.firstChild.nextSibling : row.firstChild; 658 659 var fdow = this.params.firstDayOfWeek, 660 cell = this.firstdayname, 661 weekend = this.params.weekend; 662 663 for (var i = 0; i < 7; ++i) { 664 var realday = (i + fdow) % 7; 665 cell.classList.add("day-name"); 666 this.params.weekNumbers ? cell.classList.add('day-name-week') : ''; 667 668 if (i) { 669 cell.calendar = self; 670 cell.fdow = realday; 671 } 672 if (weekend.indexOf(weekend) !== -1) { 673 cell.classList.add("weekend"); 674 } 675 676 cell.textContent = this.strings.shortDays[(i + fdow) % 7]; 677 cell = cell.nextSibling; 678 } 679 680 var tbody = createElement("tbody", table); 681 this.tbody = tbody; 682 for (i = 6; i > 0; --i) { 683 row = createElement("tr", tbody); 684 if (this.params.weekNumbers) { 685 cell = createElement("td", row); 686 } 687 688 for (var j = 7; j > 0; --j) { 689 cell = createElement("td", row); 690 cell.calendar = this; 691 cell.addEventListener("mousedown", this._dayMouseDown, true); 692 } 693 } 694 695 if (this.params.showsTime) { 696 row = createElement("tr", tbody); 697 row.className = "time"; 698 699 cell = createElement("td", row); 700 cell.className = "time time-title"; 701 cell.colSpan = 1; 702 cell.style.verticalAlign = 'middle'; 703 cell.innerHTML = " "; 704 705 var cell1 = createElement("td", row); 706 cell1.className = "time hours-select"; 707 cell1.colSpan = 2; 708 709 var cell2 = createElement("td", row); 710 cell2.className = "time minutes-select"; 711 cell2.colSpan = 2; 712 713 (function () { 714 function makeTimePart(className, selected, range_start, range_end, cellTml) { 715 var part = createElement("select", cellTml), num; 716 part.calendar = self; 717 part.className = className; 718 part.setAttribute('data-chosen', true); // avoid Chosen, hack 719 part.style.width = '100%'; 720 part.navtype = 50; 721 part._range = []; 722 for (var i = range_start; i <= range_end; ++i) { 723 var txt, selAttr = ''; 724 if (i === selected) { 725 selAttr = true; 726 } 727 if (i < 10 && range_end >= 10) { 728 num = '0' + i; 729 txt = Date.convertNumbers('0') + Date.convertNumbers(i); 730 } else { 731 num = '' + i; 732 txt = '' + Date.convertNumbers(i); 733 } 734 part.options.add(new Option(txt, num, selAttr, selAttr)); 735 } 736 return part; 737 } 738 var hrs = self.date.getHours(), 739 mins = self.date.getMinutes(), 740 t12 = !self.params.time24, 741 pm = (self.date.getHours() > 12); 742 743 if (t12 && pm) { 744 hrs -= 12; 745 } 746 747 var H = makeTimePart("time time-hours", hrs, t12 ? 1 : 0, t12 ? 12 : 23, cell1), 748 M = makeTimePart("time time-minutes", mins, 0, 59, cell2), 749 AP = null; 750 751 cell = createElement("td", row); 752 cell.className = "time ampm-select"; 753 cell.colSpan = self.params.weekNumbers ? 1 : 2; 754 755 if (t12) { 756 var selAttr = true, 757 altDate = Date.parseFieldDate(self.inputField.getAttribute('data-alt-value'), self.params.dateFormat, 'gregorian', self.strings); 758 pm = (altDate.getHours() >= 12); 759 760 var part = createElement("select", cell); 761 part.className = "time-ampm"; 762 part.style.width = '100%'; 763 part.options.add(new Option(self.strings.pm, "pm", pm ? selAttr : '', pm ? selAttr : '')); 764 part.options.add(new Option(self.strings.am, "am", pm ? '' : selAttr, pm ? '' : selAttr)); 765 AP = part; 766 767 // Event listener for the am/pm select 768 AP.addEventListener("change", function (event) { 769 self.updateTime(event.target.parentNode.parentNode.childNodes[1].childNodes[0].value, 770 event.target.parentNode.parentNode.childNodes[2].childNodes[0].value, 771 event.target.parentNode.parentNode.childNodes[3].childNodes[0].value); 772 }, false); 773 } else { 774 cell.innerHTML = " "; 775 cell.colSpan = self.params.weekNumbers ? 3 : 2; 776 } 777 778 H.addEventListener("change", function (event) { 779 self.updateTime(event.target.parentNode.parentNode.childNodes[1].childNodes[0].value, 780 event.target.parentNode.parentNode.childNodes[2].childNodes[0].value, 781 event.target.parentNode.parentNode.childNodes[3].childNodes[0].value); 782 }, false); 783 M.addEventListener("change", function (event) { 784 self.updateTime(event.target.parentNode.parentNode.childNodes[1].childNodes[0].value, 785 event.target.parentNode.parentNode.childNodes[2].childNodes[0].value, 786 event.target.parentNode.parentNode.childNodes[3].childNodes[0].value); 787 }, false); 788 })(); 789 } 790 791 row = createElement("div", this.wrapper); 792 row.className = "buttons-wrapper btn-group"; 793 794 this._nav_clear = hh(this.strings.clear, '', 100, 'button', '', 'js-btn btn btn-clear', {"type": "button", "data-action": "clear"}); 795 796 var cleara = row.querySelector('[data-action="clear"]'); 797 cleara.addEventListener("click", function (e) { 798 e.preventDefault(); 799 var days = self.table.querySelectorAll('td'); 800 for (var i = 0; i < days.length; i++) { 801 if (days[i].classList.contains('selected')) { 802 days[i].classList.remove('selected'); 803 break; 804 } 805 } 806 self.inputField.setAttribute('data-alt-value', "0000-00-00 00:00:00"); 807 self.inputField.setAttribute('value', ''); 808 self.inputField.value = ''; 809 self.inputField.dispatchEvent(new CustomEvent('change', {bubbles: true, cancelable: true})); 810 }); 811 812 if (this.params.showsTodayBtn) { 813 this._nav_now = hh(this.strings.today, '', 0, 'button', '', 'js-btn btn btn-today', {"type": "button", "data-action": "today"}); 814 815 var todaya = this.wrapper.querySelector('[data-action="today"]'); 816 todaya.addEventListener('click', function (e) { 817 e.preventDefault(); 818 self.date.setLocalDateOnly('gregorian', new Date()); // TODAY 819 self.dateClicked = true; 820 self.callHandler(); 821 self.close(); 822 }); 823 } 824 825 this._nav_exit = hh(this.strings.exit, '', 999, 'button', '', 'js-btn btn btn-exit', {"type": "button", "data-action": "exit"}); 826 var exita = this.wrapper.querySelector('[data-action="exit"]'); 827 exita.addEventListener('click', function (e) { 828 e.preventDefault(); 829 if (!self.dateClicked) { 830 if (self.inputField.value) { 831 if (self.params.dateType !== 'gregorian') { 832 self.inputField.setAttribute('data-local-value', self.inputField.value); 833 } 834 if (typeof self.dateClicked === 'undefined') { 835 // value needs to be validated 836 self.inputField.setAttribute('data-alt-value', Date.parseFieldDate(self.inputField.value, self.params.dateFormat, self.params.dateType, self.strings) 837 .print(self.params.dateFormat, 'gregorian', false, self.strings)); 838 } else { 839 self.inputField.setAttribute('data-alt-value', self.date.print(self.params.dateFormat, 'gregorian', false, self.strings)); 840 } 841 } else { 842 self.inputField.setAttribute('data-alt-value', '0000-00-00 00:00:00'); 843 } 844 self.date = Date.parseFieldDate(self.inputField.getAttribute('data-alt-value'), self.params.dateFormat, self.params.dateType, self.strings); 845 } 846 self.close(); 847 }); 848 849 this.processCalendar(); 850 }; 851 852 /** Method to append numbers to the calendar table */ 853 JoomlaCalendar.prototype.processCalendar = function () { 854 this.table.style.visibility = "hidden"; 855 856 var firstDayOfWeek = this.params.firstDayOfWeek, 857 date = this.date, 858 today = new Date(), 859 TY = today.getLocalFullYear(this.params.dateType), 860 TM = today.getLocalMonth(this.params.dateType), 861 TD = today.getLocalDate(this.params.dateType), 862 year = date.getOtherFullYear(this.params.dateType), 863 hrs = date.getHours(), 864 mins = date.getMinutes(), 865 secs = date.getSeconds(), 866 t12 = !this.params.time24; 867 868 if (year < this.params.minYear) { // Check min,max year 869 year = this.params.minYear; 870 date.setOtherFullYear(this.params.dateType, year); 871 } else if (year > this.params.maxYear) { 872 year = this.params.maxYear; 873 date.setOtherFullYear(this.params.dateType, year); 874 } 875 876 this.params.firstDayOfWeek = firstDayOfWeek; 877 this.date = new Date(date); 878 879 var month = date.getLocalMonth(this.params.dateType); 880 var mday = date.getLocalDate(this.params.dateType); 881 882 // Compute the first day that would actually be displayed in the calendar, even if it's from the previous month. 883 date.setLocalDate(this.params.dateType, 1); 884 var day1 = (date.getLocalDay(this.params.dateType) - this.params.firstDayOfWeek) % 7; 885 886 if (day1 < 0) { 887 day1 += 7; 888 } 889 890 date.setLocalDate(this.params.dateType, - day1); 891 date.setLocalDate(this.params.dateType, date.getLocalDate(this.params.dateType) + 1); 892 893 var row = this.tbody.firstChild, 894 ar_days = this.ar_days = new Array(), 895 weekend = this.params.weekend, 896 monthDays = parseInt(date.getLocalWeekDays(this.params.dateType)); 897 898 /** Fill the table **/ 899 for (var i = 0; i < monthDays; ++i, row = row.nextSibling) { 900 var cell = row.firstChild; 901 if (this.params.weekNumbers) { 902 cell.className = "day wn"; 903 cell.textContent = date.getLocalWeekNumber(this.params.dateType); 904 cell = cell.nextSibling; 905 } 906 907 row.className = this.params.weekNumbers ? "daysrow wk" : "daysrow"; 908 var hasdays = false, iday, 909 dpos = ar_days[i] = [], 910 totalDays = monthDays + 1; 911 912 for (var j = 0; j < totalDays; ++j, cell = cell.nextSibling, date.setLocalDate(this.params.dateType, iday + 1)) { 913 cell.className = "day"; 914 cell.style['textAlign'] = 'center'; 915 iday = date.getLocalDate(this.params.dateType); 916 var wday = date.getLocalDay(this.params.dateType); 917 cell.pos = i << 4 | j; 918 dpos[j] = cell; 919 var current_month = (date.getLocalMonth(this.params.dateType) === month); 920 if (!current_month) { 921 if (this.params.showsOthers) { 922 cell.className += " disabled othermonth "; 923 cell.otherMonth = true; 924 } else { 925 cell.className += " emptycell"; 926 cell.innerHTML = " "; 927 cell.disabled = true; 928 continue; 929 } 930 } else { 931 cell.otherMonth = false; 932 hasdays = true; 933 cell.style.cursor = "pointer"; 934 } 935 cell.disabled = false; 936 cell.textContent = this.params.debug ? iday : Date.convertNumbers(iday); // translated day number for each cell 937 if (!cell.disabled) { 938 cell.caldate = new Date(date); 939 if (current_month && iday === mday) { 940 cell.className += " selected"; 941 this.currentDateEl = cell; 942 } 943 if (date.getLocalFullYear(this.params.dateType) === TY && date.getLocalMonth(this.params.dateType) === TM && iday === TD) { 944 cell.className += " today"; 945 } 946 if (weekend.indexOf(wday) !== -1) 947 cell.className += " weekend"; 948 } 949 } 950 if (!(hasdays || this.params.showsOthers)) { 951 row.classList.add('hidden'); 952 row.setAttribute('hidden', ''); 953 row.className = "emptyrow"; 954 } else { 955 row.classList.remove('hidden'); 956 row.removeAttribute('hidden', ''); 957 } 958 } 959 960 /* Set the time */ 961 if (this.params.showsTime) { 962 if (hrs > 12 && t12) { 963 hrs -= 12; 964 } 965 966 hrs = (hrs < 10) ? "0" + hrs : hrs; 967 mins = (mins < 10) ? "0" + mins : mins; 968 969 var hoursEl = this.table.querySelector('.time-hours'), 970 minsEl = this.table.querySelector('.time-minutes'); 971 972 /* remove the selected class for the hours*/ 973 this.resetSelected(hoursEl); 974 if (!this.params.time24) 975 { 976 hoursEl.value = (hrs == "00") ? "12" : hrs; 977 } 978 else 979 { 980 hoursEl.value = hrs; 981 } 982 983 /* remove the selected class for the minutes*/ 984 this.resetSelected(minsEl); 985 minsEl.value = mins; 986 987 if (!this.params.time24) 988 { 989 var dateAlt = new Date(this.inputField.getAttribute('data-alt-value')), 990 ampmEl = this.table.querySelector('.time-ampm'), 991 hrsAlt = dateAlt.getHours(); 992 993 if (hrsAlt > 12) { 994 /* remove the selected class for the am-pm*/ 995 this.resetSelected(ampmEl); 996 ampmEl.value = 'pm'; 997 } 998 } 999 } 1000 1001 if (!this.params.compressedHeader) { 1002 this._nav_month.getElementsByTagName('span')[0].textContent = this.params.debug ? month + ' ' + this.strings.months[month] : this.strings.months[month]; 1003 this.title.getElementsByTagName('span')[0].textContent = this.params.debug ? year + ' ' + Date.convertNumbers(year.toString()) : Date.convertNumbers(year.toString()); 1004 } else { 1005 var tmpYear = Date.convertNumbers(year.toString()); 1006 this._nav_month.getElementsByTagName('span')[0].textContent = !this.params.monthBefore ? this.strings.months[month] + ' - ' + tmpYear : tmpYear + ' - ' + this.strings.months[month] ; 1007 } 1008 this.table.style.visibility = "visible"; 1009 }; 1010 1011 /** Method to listen for the click event on the input button. **/ 1012 JoomlaCalendar.prototype._bindEvents = function () { 1013 var self = this; 1014 this.inputField.addEventListener('blur', function(event) { 1015 var calObj = JoomlaCalendar.getCalObject(this)._joomlaCalendar; 1016 1017 // If calendar is open we will handle the event elsewhere 1018 if (!calObj.dropdownElement.hasAttribute('hidden')) { 1019 event.preventDefault(); 1020 return; 1021 } 1022 1023 if (calObj) { 1024 if (calObj.inputField.value) { 1025 if (typeof calObj.params.dateClicked === 'undefined') { 1026 calObj.inputField.setAttribute('data-local-value', calObj.inputField.value); 1027 1028 if (calObj.params.dateType !== 'gregorian') { 1029 // We need to transform the date for the data-alt-value 1030 var ndate, date = Date.parseFieldDate(calObj.inputField.value, calObj.params.dateFormat, calObj.params.dateType, calObj.strings); 1031 ndate = Date.localCalToGregorian(date.getFullYear(), date.getMonth(), date.getDate()); 1032 date.setFullYear(ndate[0]); 1033 date.setMonth(ndate[1]); 1034 date.setDate(ndate[2]); 1035 calObj.inputField.setAttribute('data-alt-value', date.print(calObj.params.dateFormat, 'gregorian', false, calObj.strings)); 1036 } else { 1037 calObj.inputField.setAttribute('data-alt-value', Date.parseFieldDate(calObj.inputField.value, calObj.params.dateFormat, calObj.params.dateType, calObj.strings) 1038 .print(calObj.params.dateFormat, 'gregorian', false, calObj.strings)); 1039 } 1040 } else { 1041 calObj.inputField.setAttribute('data-alt-value', calObj.date.print(calObj.params.dateFormat, 'gregorian', false, calObj.strings)); 1042 } 1043 } else { 1044 calObj.inputField.setAttribute('data-alt-value', '0000-00-00 00:00:00'); 1045 } 1046 calObj.date = Date.parseFieldDate(calObj.inputField.getAttribute('data-alt-value'), calObj.params.dateFormat, calObj.params.dateType, calObj.strings); 1047 } 1048 1049 self.close(); 1050 }, true); 1051 this.button.addEventListener('click', function() { 1052 self.show(); 1053 }, false); 1054 }; 1055 1056 /** Helpers **/ 1057 var stopCalEvent = function (ev) { ev || (ev = window.event); ev.preventDefault(); ev.stopPropagation(); return false; }; 1058 var createElement = function (type, parent) { var el = null; el = document.createElement(type); if (typeof parent !== "undefined") { parent.appendChild(el); } return el; }; 1059 var isInt = function (input) { return !isNaN(input) && (function(x) { return (x | 0) === x; })(parseFloat(input)) }; 1060 var getBoundary = function (input, type) { var date = new Date(); var y = date.getLocalFullYear(type); return y + input; }; 1061 1062 /** Method to get the active calendar element through any descendant element. */ 1063 JoomlaCalendar.getCalObject = function(element) { 1064 if (!element) { 1065 return false; 1066 } 1067 while (element.parentNode) { 1068 element = element.parentNode; 1069 if (element.classList.contains('field-calendar')) { 1070 return element; 1071 } 1072 } 1073 return false; 1074 }; 1075 1076 /** 1077 * Method to change input values with the data-alt-value values. This method is e.g. being called 1078 * by the onSubmit handler of the calendar fields form. 1079 */ 1080 JoomlaCalendar.prototype.setAltValue = function() { 1081 var input = this.inputField; 1082 if (input.getAttribute('disabled')) return; 1083 1084 // Set the value to the data-alt-value attribute, but only if it really has a value. 1085 input.value = ( 1086 input.getAttribute('data-alt-value') && input.getAttribute('data-alt-value') !== '0000-00-00 00:00:00' 1087 ? input.getAttribute('data-alt-value') 1088 : '' 1089 ); 1090 }; 1091 1092 /** Method to change the inputs before submit. **/ 1093 JoomlaCalendar.onSubmit = function() { 1094 Joomla = window.Joomla || {}; 1095 if (!Joomla.calendarProcessed) { 1096 Joomla.calendarProcessed = true; 1097 var elements = document.querySelectorAll(".field-calendar"); 1098 1099 for (var i = 0; i < elements.length; i++) { 1100 var element = elements[i], 1101 instance = element._joomlaCalendar; 1102 1103 if (instance) { 1104 instance.setAltValue(); 1105 } 1106 } 1107 } 1108 }; 1109 1110 /** 1111 * Init the Calendars on the page 1112 * 1113 * @param {Node} element The element node 1114 * @param {HTMLElement} container The field container (optional) 1115 */ 1116 JoomlaCalendar.init = function (element, container) { 1117 1118 var instance = element._joomlaCalendar; 1119 if (!instance) { 1120 new JoomlaCalendar(element); 1121 } else { 1122 instance.recreate(); 1123 } 1124 1125 if (element && element.getElementsByTagName('input')[0] && element.getElementsByTagName('input')[0].form && !element.getElementsByTagName('input')[0].disabled) { 1126 element.getElementsByTagName('input')[0].form.addEventListener('submit', JoomlaCalendar.onSubmit); 1127 } 1128 }; 1129 1130 window.JoomlaCalendar = JoomlaCalendar; 1131 1132 /** 1133 * Instantiate all the calendar fields when the document is ready/updated 1134 * @param {Event} event 1135 * @private 1136 */ 1137 function _initCalendars(event) { 1138 var elements = event.target.querySelectorAll(".field-calendar"); 1139 1140 for (var i = 0, l = elements.length; i < l; i++) { 1141 JoomlaCalendar.init(elements[i]); 1142 } 1143 } 1144 document.addEventListener("DOMContentLoaded", _initCalendars); 1145 document.addEventListener("joomla:updated", _initCalendars); 1146 1147 /** B/C related code 1148 * @deprecated 4.0.0 1149 */ 1150 window.Calendar = {}; 1151 1152 /** B/C related code 1153 * @deprecated 4.0.0 1154 */ 1155 Calendar.setup = function(obj) { 1156 1157 if (obj.inputField && document.getElementById(obj.inputField)) { 1158 var element = document.getElementById(obj.inputField), 1159 cal = element.parentNode.querySelectorAll('button')[0]; 1160 1161 for (var property in obj) { 1162 if (obj.hasOwnProperty(property)) { 1163 switch (property) { 1164 case 'ifFormat': 1165 if (cal) cal.setAttribute('data-dayformat', obj.ifFormat); 1166 break; 1167 1168 case 'firstDay': 1169 if (cal) cal.setAttribute('data-firstday', parseInt(obj.firstDay)); 1170 break; 1171 1172 case 'weekNumbers': 1173 if (cal) cal.setAttribute('data-week-numbers', (obj.weekNumbers === "true" || obj.weekNumbers === true) ? '1' : '0'); 1174 break; 1175 1176 case 'showOthers': 1177 if (cal) cal.setAttribute('data-show-others', (obj.showOthers === "true" || obj.showOthers === true) ? '1' : '0'); 1178 break; 1179 1180 case 'showsTime': 1181 if (cal) cal.setAttribute('data-show-time', (obj.showsTime === "true" || obj.showsTime === true) ? '1' : '0'); 1182 break; 1183 1184 case 'timeFormat': 1185 if (cal) cal.setAttribute('data-time-24', parseInt(obj.timeFormat)); 1186 break; 1187 1188 case 'displayArea': 1189 case 'inputField': 1190 case 'button': 1191 case 'eventName': 1192 case 'daFormat': 1193 case 'disableFunc': 1194 case 'dateStatusFunc': 1195 case 'dateTooltipFunc': 1196 case 'dateText': 1197 case 'align': 1198 case 'range': 1199 case 'flat': 1200 case 'flatCallback': 1201 case 'onSelect': 1202 case 'onClose': 1203 case 'onUpdate': 1204 case 'date': 1205 case 'electric': 1206 case 'step': 1207 case 'position': 1208 case 'cache': 1209 case 'multiple': 1210 break; 1211 } 1212 1213 1214 } 1215 } 1216 JoomlaCalendar.init(element.parentNode.parentNode); 1217 } 1218 return null; 1219 }; 1220 1221 })(window, document);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |