1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 ZmCalMonthView = function(parent, posStyle, controller, dropTgt) { 25 ZmCalBaseView.call(this, parent, "calendar_view", posStyle, controller, ZmId.VIEW_CAL_MONTH, false); 26 var element = this.getHtmlElement(); 27 // clear the onClick event handler. Otherwise accessibility code will 28 // generate spurious mouse up/down events 29 this._setEventHdlrs([DwtEvent.ONCLICK], true, element); 30 31 this.setScrollStyle(DwtControl.CLIP); 32 this._needFirstLayout = true; 33 this.numDays = 42; 34 }; 35 36 ZmCalMonthView.prototype = new ZmCalBaseView; 37 ZmCalMonthView.prototype.constructor = ZmCalMonthView; 38 39 ZmCalMonthView._DaySpacer = 1; // space between days 40 ZmCalMonthView.FIRST_WORKWEEK_DAY = 1; // hard code to monday until we get real prefs 41 ZmCalMonthView.NUM_DAYS_IN_WORKWEEK = 5;// hard code to 5 days until we get real prefs 42 43 ZmCalMonthView.EXPANDED_HEIGHT_PERCENT = 70; 44 ZmCalMonthView.EXPANDED_WIDTH_PERCENT = 50; 45 ZmCalMonthView.ANIMATE_INTERVAL = 1000 / 30; 46 ZmCalMonthView.ANIMATE_DURATION = 250; 47 48 ZmCalMonthView.OUT_OF_BOUNDS_SNAP = -1000; 49 50 ZmCalMonthView.ALL_DAY_DIV_BODY = "_body"; 51 52 ZmCalMonthView.prototype.toString = 53 function() { 54 return "ZmCalMonthView"; 55 }; 56 57 ZmCalMonthView.prototype.getRollField = 58 function() { 59 return AjxDateUtil.MONTH; 60 }; 61 62 ZmCalMonthView.prototype._dateUpdate = 63 function(rangeChanged) { 64 this._clearSelectedDay(); 65 this._updateSelectedDay(); 66 }; 67 68 ZmCalMonthView.prototype._updateTitle = 69 function() { 70 // updated in updateDays 71 }; 72 73 ZmCalMonthView.prototype._clearSelectedDay = 74 function() { 75 if (this._selectedData != null) { 76 var te = document.getElementById(this._selectedData.tdId); 77 te.className = 'calendar_month_cells_td'; 78 this._selectedData = null; 79 } 80 }; 81 82 ZmCalMonthView.prototype._updateSelectedDay = 83 function() { 84 var day = this._dateToDayIndex[this._dayKey(this._date)]; 85 if (day) { 86 var te = document.getElementById( day.tdId); 87 te.className = 'calendar_month_cells_td-selected'; 88 this._selectedData = day; 89 } 90 }; 91 92 ZmCalMonthView.prototype._apptSelected = 93 function() { 94 this._clearSelectedDay(); 95 }; 96 97 98 ZmCalMonthView.prototype._getDayForAppt = 99 function(appt) { 100 return this._getDayForDate(appt.startDate); 101 }; 102 103 ZmCalMonthView.prototype._getDayForDate = 104 function(date) { 105 return this._dateToDayIndex[this._dayKey(date)]; 106 }; 107 108 ZmCalMonthView.prototype._getDivForAppt = 109 function(appt) { 110 var day = this._getDayForAppt(appt); 111 return day ? document.getElementById( day.dayId) : null; 112 }; 113 114 ZmCalMonthView.prototype._getStartDate = 115 function() { 116 return new Date(this.getDate()); 117 }; 118 119 ZmCalMonthView.prototype._dayTitle = 120 function(date) { 121 if (this._shortMonInDay != date.getMonth()) { 122 this._shortMonInDay = date.getMonth(); 123 var formatter = DwtCalendar.getDayFormatter(); 124 return formatter.format(date); 125 } 126 return date.getDate(); 127 }; 128 129 ZmCalMonthView.prototype._getApptUniqueId = 130 function(appt) { 131 return (appt._orig) ? appt._orig.getUniqueId() : appt.getUniqueId(); 132 } 133 134 ZmCalMonthView.prototype._reserveRow = 135 function(day, apptSet, appt) { 136 var appts = day.allDayAppts; 137 var row = -1; 138 139 if (apptSet.rows[day.week] === undefined) { 140 // New apptSet, or another week in the set. Find a free slot or add to the end 141 row = this._allocateRow(day, apptSet); 142 } else { 143 // Use the existing row for the apptSet 144 row = apptSet.rows[day.week]; 145 } 146 var apptToMove = appts[row]; 147 appts[row] = appt; 148 149 if (apptToMove) { 150 // The row was in use, need to move to free slot or end 151 var uniqId = this._getApptUniqueId(apptToMove); 152 var apptSetToMove = this._apptSets[uniqId]; 153 row = this._allocateRow(day, apptSetToMove); 154 appts[row] = apptToMove; 155 apptSetToMove.rows[day.week] = row; 156 } 157 }; 158 159 ZmCalMonthView.prototype._allocateRow = 160 function(day, apptSet) { 161 var appts = day.allDayAppts; 162 apptSet.rows[day.week] = appts.length; 163 for (var i=0; i < appts.length; i++) { 164 if (appts[i] == null) { 165 apptSet.rows[day.week] = i; 166 break; 167 } 168 } 169 return apptSet.rows[day.week]; 170 } 171 172 ZmCalMonthView.prototype.addAppt = 173 function(appt) { 174 var day = this._getDayForAppt(appt); 175 176 if (appt._orig.isAllDayEvent() || appt._orig.isMultiDay()) { 177 var uniqueId = this._getApptUniqueId(appt); 178 var apptSet = this._apptSets[uniqueId]; 179 if (apptSet == null) { 180 apptSet = this._createApptSet(appt, uniqueId); 181 } 182 apptSet.appts.push(appt); 183 } 184 185 if (day) { 186 if (appt._orig.isAllDayEvent(appt)) { 187 // make sure multi-day all day appts line up 188 // Assuming sliced up appts passed in chronological order (first is start) - verify 189 if (!day.allDayAppts) { 190 day.allDayAppts = []; 191 } else { 192 193 } 194 // Reserve a row if its onscreen 195 this._reserveRow(day, apptSet, appt); 196 } else { 197 if (!day.appts) { 198 day.appts = []; 199 } 200 day.appts.push(appt); 201 } 202 } 203 204 }; 205 206 207 // Multi-day appts have been sliced into a set of single day appts. Accumulate 208 // the appts into an apptSet, so that when DnD is performed we can update the 209 // position of each appt slice that comprises the full appt. 210 ZmCalMonthView.prototype._createApptSet = 211 function(appt, uniqueId, day) { 212 var dow; 213 var apptSet = null; 214 if (day) { 215 dow = day.dow; 216 } else { 217 // DayIndex should be < 0 (no corresponding day, and assuming sliced appts 218 // passed in from earliest to last) 219 var dayIndex = this._createDayIndexFromDate(appt.startDate); 220 var zeroDay = this._days[0] 221 dow = (zeroDay.dow + dayIndex + 7) % 7; 222 } 223 // The set tracks the starting dow of the full appt, whether or not it is 224 // an all-day event (note that there can be multi-day non-all-day appts), 225 // the appt slices (one per day) that comprise the full appt, and the row 226 // position of each slice (in case the full appt spans multiple weeks). 227 apptSet = { appts: [], rows: {}, dow: dow, allDay: appt.isAllDayEvent()}; 228 this._apptSets[uniqueId] = apptSet; 229 return apptSet; 230 } 231 232 ZmCalMonthView.prototype._postSet = 233 function() { 234 // now go through each day and create appts in correct order to line things up 235 var day; 236 if(this._expandedDayInfo) { 237 var row = this._expandedDayInfo.week; 238 var col = this._expandedDayInfo.dow; 239 var day = this._days[row*7+col]; 240 var d = new Date(this._date.getTime()); 241 d.setHours(0,0,0); 242 if(d.getTime() == day.date.getTime()) { 243 this.setDayView(day); 244 }else { 245 this.createApptItems(); 246 } 247 }else { 248 this.createApptItems(); 249 } 250 }; 251 252 253 ZmCalMonthView.prototype.createApptItems = 254 function() { 255 var allDayParent = document.getElementById( this._daysId); 256 var day; 257 // Create the all-day divs 258 this._apptAllDayDiv = {}; 259 for (var uniqueId in this._apptSets) { 260 var apptSet = this._apptSets[uniqueId]; 261 if (!apptSet.allDay) continue; 262 263 var currentWeek = -1; 264 var first = true; 265 var last = false; 266 var startDayIndex = this._createDayIndexFromDate(apptSet.appts[0]._orig.startDate); 267 // Set first (header div) if offscreen and first div, or first on the grid, 268 // starting a new week. 269 // Set last if in last day (41) or last in appt sequence 270 for (var iAppt = 0; iAppt < apptSet.appts.length; iAppt++) { 271 var appt = apptSet.appts[iAppt]; 272 day = this._getDayForAppt(appt); 273 first = (iAppt == 0); 274 last = (iAppt == (apptSet.appts.length - 1)); 275 if (day) { 276 if (((startDayIndex + iAppt) == (this.numDays -1))) { 277 last = true; 278 } 279 if (day.week != currentWeek) { 280 // Catches 1st on-screen appt (0th or not) 281 first = true; 282 currentWeek = day.week; 283 } 284 } 285 var allDayDiv = this._createAllDayApptDiv(allDayParent, appt, iAppt, first, last); 286 if (!day) { 287 Dwt.setVisible(allDayDiv, false); 288 } 289 first = false; 290 last = false; 291 292 if (day) { 293 var date = DwtCalendar.getDateFormatter().format(day.date); 294 allDayDiv.setAttribute('aria-label', date + ' ' + appt.getName()); 295 } 296 } 297 } 298 299 for (var i=0; i < 6; i++) { 300 for (var j=0; j < 7; j++) { 301 var dayIndex = i*7+j; 302 day = this._days[dayIndex]; 303 if (day.allDayAppts) { 304 for (var k=0; k < day.allDayAppts.length; k++) { 305 var appt = day.allDayAppts[k]; 306 var div = this._attachAllDayFillerHtml(appt, dayIndex); 307 this._fillers.push(div); 308 } 309 } 310 if (day.appts) { 311 for (var k=0; k < day.appts.length; k++) 312 var div = this._createItemHtml(day.appts[k], null); 313 } 314 } 315 } 316 317 if (!this._needFirstLayout) 318 this._layout(); 319 320 if(this._dayView) { 321 this._dayView.setVisible(false); 322 this.clearExpandedDay(); 323 } 324 }; 325 326 ZmCalMonthView.prototype._preSet = 327 function() { 328 // reset all layout data 329 // cleanup any filler 330 if (this._fillers.length > 0) { 331 for (var i=0; i < this._fillers.length; i++) { 332 var f = this._fillers[i]; 333 this._fillers[i] = null; 334 f.parentNode.removeChild(f); 335 } 336 this._fillers = []; 337 } 338 this._apptSets = new Object();; 339 for (var i=0; i < 6; i++) { 340 for (var j=0; j < 7; j++) { 341 day = this._days[i*7+j]; 342 if (day.allDayAppts) delete day.allDayAppts; 343 if (day.appts) delete day.appts; 344 } 345 } 346 }; 347 348 349 ZmCalMonthView.prototype._createAllDayApptDiv = 350 function(allDayParent, appt, iAppt, first, last) { 351 var allDayDiv = this._createAllDayItemHtml(appt, first, last); 352 allDayParent.appendChild(allDayDiv); 353 var divKey = appt.invId + "_" + iAppt.toString(); 354 if (!this._apptAllDayDiv[divKey]) { 355 this._apptAllDayDiv[divKey] = allDayDiv.id; 356 } 357 return allDayDiv; 358 } 359 360 361 ZmCalMonthView.prototype._createAllDayItemHtml = 362 function(appt, first, last) { 363 //DBG.println("---- createItem ---- "+appt); 364 365 // set up DIV 366 var div = document.createElement("div"); 367 368 div.style.position = 'absolute'; 369 Dwt.setSize(div, 10, 10); 370 div.className = this._getStyle(); 371 372 div.style.overflow = "hidden"; 373 div.style.paddingBottom = "4px" 374 div.head = first; 375 div.tail = last; 376 377 this.associateItemWithElement(appt, div, ZmCalBaseView.TYPE_APPT); 378 var id = this._getItemId(appt); 379 div.innerHTML = ZmApptViewHelper._allDayItemHtml(appt, id, this._controller, first, last); 380 var apptBodyDiv = div.firstChild; 381 382 if (!first) { 383 apptBodyDiv.style.cssText += "border-left: 0px none black !important;"; 384 } 385 if (!last) { 386 apptBodyDiv.style.cssText += "border-right: 0px none black !important;"; 387 } 388 // Set opacity on the table that is colored with the gradient - needed by IE 389 var tableEl = Dwt.getDescendant(apptBodyDiv, id + "_tableBody"); 390 ZmCalBaseView._setApptOpacity(appt, tableEl); 391 392 return div; 393 }; 394 395 396 ZmCalMonthView.prototype._attachAllDayFillerHtml = 397 function(appt, dayIndex) { 398 var day = this._days[dayIndex]; 399 var dayTable = document.getElementById(day.dayId); 400 return this._createAllDayFillerHtml(appt, dayIndex, dayTable); 401 } 402 403 ZmCalMonthView.prototype._createAllDayFillerHtml = 404 function(appt, dayIndex, dayTable) { 405 var targetTable = null; 406 var remove = false; 407 if (!dayTable) { 408 if (!this._fillerGenTableBody) { 409 var table = document.createElement("table"); 410 this._fillerGenTableBody = document.createElement("tbody"); 411 table.appendChild(this._fillerGenTableBody); 412 } 413 targetTable = this._fillerGenTableBody; 414 remove = true; 415 } else { 416 targetTable = dayTable; 417 } 418 var result = targetTable.insertRow(-1); 419 if (appt) { 420 result.id = appt.invId + ":" + dayIndex; 421 } 422 result.className = "allday"; 423 this._createAllDayFillerContent(result, true); 424 if (remove) { 425 result.parentNode.removeChild(result); 426 } 427 return result; 428 }; 429 430 431 ZmCalMonthView.prototype._createAllDayFillerContent = 432 function(tr, createCell) { 433 var cell; 434 if (createCell) { 435 cell = tr.insertCell(-1); 436 } else { 437 cell = tr.firstChild; 438 } 439 cell.innerHTML = "<table class=allday><tr><td><div class=allday_item_filler></div></td></tr></table>"; 440 cell.className = "calendar_month_day_item"; 441 } 442 443 444 445 ZmCalMonthView.prototype._createItemHtml = 446 function(appt) { 447 var result = this._getDivForAppt(appt).insertRow(-1); 448 result.className = this._getStyle(ZmCalBaseView.TYPE_APPT); 449 result.apptStartTimeOffset = this._getTimeOffset(appt.getStartTime()); 450 451 this.associateItemWithElement(appt, result, ZmCalBaseView.TYPE_APPT); 452 453 this._createItemHtmlContents(appt, result); 454 455 return result; 456 }; 457 458 ZmCalMonthView.prototype._createItemHtmlContents = 459 function(appt, tr) { 460 var needsAction = appt.ptst == ZmCalBaseItem.PSTATUS_NEEDS_ACTION; 461 var calendar = appCtxt.getById(appt.folderId); 462 var fba = needsAction ? ZmCalBaseItem.PSTATUS_NEEDS_ACTION : appt.fba; 463 464 var tagNames = appt.getVisibleTags(); 465 var tagIcon = appt.getTagImageFromNames(tagNames); 466 467 var headerColors = ZmApptViewHelper.getApptColor(needsAction, calendar, tagNames, "header"); 468 var headerStyle = ZmCalBaseView._toColorsCss(headerColors.appt); 469 var bodyColors = ZmApptViewHelper.getApptColor(needsAction, calendar, tagNames, "body"); 470 var bodyStyle = ZmCalBaseView._toColorsCss(bodyColors.appt); 471 472 473 var data = { 474 id: this._getItemId(appt), 475 appt: appt, 476 duration: appt.getShortStartHour(), 477 headerStyle: headerStyle, 478 bodyStyle: bodyStyle, 479 multiday: appt._fanoutFirst != null, 480 first: appt._fanoutFirst, 481 last: appt._fanoutLast, 482 showAsColor : ZmApptViewHelper._getShowAsColorFromId(fba), 483 tagIcon: tagIcon 484 }; 485 ZmApptViewHelper.setupCalendarColor(true, bodyColors, tagNames, data, "headerStyle", null, 0, 0); 486 487 var cell = tr.insertCell(-1); 488 cell.className = "calendar_month_day_item"; 489 cell.innerHTML = AjxTemplate.expand("calendar.Calendar#month_appt", data); 490 // Hack for IE - it doesn't display the tag and peel unless you alter a containing className. 491 // The month template div does not have any classNames, so this is safe. 492 cell.firstChild.className = ""; 493 } 494 495 ZmCalMonthView.prototype._createDay = 496 function(html, loc, week, dow) { 497 var tdid = Dwt.getNextId(); 498 var did = Dwt.getNextId(); 499 var tid = Dwt.getNextId(); 500 501 html.append("<td class='calendar_month_cells_td' id='", tdid, "'>"); 502 html.append("<div style='width:100%;height:100%;'>"); 503 html.append("<table class='calendar_month_day_table'>"); 504 html.append("<tr><td colspan=2 id='", tid, "'></td></tr></table>"); 505 html.append("<table class='calendar_month_day_table'><tbody id='", did, "'>"); 506 html.append("</tbody></table>"); 507 html.append("</div>"); 508 html.append("</td>"); 509 510 var data = { dayId: did, titleId: tid, tdId: tdid, week: week, dow: dow, view: this}; 511 this._days[loc] = data; 512 }; 513 514 ZmCalMonthView.prototype._createHtml = 515 function() { 516 this._showWeekNumber = appCtxt.get(ZmSetting.CAL_SHOW_CALENDAR_WEEK); 517 this._days = new Object(); 518 this._rowIds = new Object(); 519 this._apptSets = new Object(); 520 this._dayInfo = new Object(); 521 this._fillers = []; 522 this._headerId = Dwt.getNextId(); 523 this._titleId = Dwt.getNextId(); 524 this._daysId = Dwt.getNextId(); 525 this._bodyId = Dwt.getNextId(); 526 this._weekNumBodyId = Dwt.getNextId(); 527 this._monthViewTable = Dwt.getNextId(); 528 this._headerColId = []; 529 this._dayNameId = []; 530 this._bodyColId = []; 531 this._weekNumberIds = {}; 532 533 var html = new AjxBuffer(); 534 535 html.append("<table class=calendar_view_table cellpadding=0 cellspacing=0 id='",this._monthViewTable,"'>"); 536 html.append("<tr>"); 537 538 html.append("<td>"); 539 html.append("<div id='", this._headerId, "' style='position:relative;'>"); 540 html.append("<table id=calendar_month_header_table class=calendar_month_header_table>"); 541 html.append("<colgroup>"); 542 543 // Add column group to adjust week title heading. 544 if (this._showWeekNumber) { 545 html.append("<col id='", Dwt.getNextId(), "'/>"); 546 } 547 548 for (var i=0; i < 7; i++) { 549 this._headerColId[i] = Dwt.getNextId(); 550 html.append("<col id='", this._headerColId[i], "'/>"); 551 } 552 html.append("</colgroup>"); 553 html.append("<tr>"); 554 html.append("<td colspan=7 class=calendar_month_header_month id='", this._titleId, "'></td>"); 555 html.append("</tr>"); 556 html.append("<tr>"); 557 558 // Week title to heading. 559 if (this._showWeekNumber) { 560 html.append("<td width=10 valign='bottom' class='calendar_month_header_cells_text'>"); 561 html.append(AjxMsg.calendarWeekTitle); 562 html.append("</td>"); 563 } 564 565 for (var day=0; day < 7; day++) { 566 this._dayNameId[day] = Dwt.getNextId(); 567 html.append("<td class=calendar_month_header_cells_text id='",this._dayNameId[day],"'></td>"); 568 } 569 570 html.append("</tr>"); 571 html.append("</table>"); 572 html.append("</div>"); 573 html.append("</td></tr>"); 574 html.append("<tr>"); 575 576 html.append("<td class='calendar_month_body_container'>"); 577 html.append("<div id='", this._daysId, "' class=calendar_month_body>"); 578 579 html.append("<table id='", this._bodyId, "' class=calendar_month_table>"); 580 html.append("<colgroup>"); 581 582 // Add column group to adjust week number. 583 if (this._showWeekNumber) { 584 html.append("<col id='"+ this._weekNumBodyId + "'></col>"); 585 } 586 587 for (var i=0; i < 7; i++) { 588 this._bodyColId[i] = Dwt.getNextId(); 589 html.append("<col id='", this._bodyColId[i], "'/>"); 590 } 591 html.append("</colgroup>"); 592 593 for (var i=0; i < 6; i++) { 594 var weekId = Dwt.getNextId(); 595 html.append("<tr id='" + weekId + "'>"); 596 597 // Holds week number per row. 598 if (this._showWeekNumber) { 599 var weekNumberId = Dwt.getNextId(); 600 html.append("<td id='" + weekNumberId + "' class='calendar_month_weekno_td'></td>"); 601 this._weekNumberIds[i] = weekNumberId; 602 } 603 604 for (var j=0; j < 7; j++) { 605 this._createDay(html, i*7+j, i, j); 606 } 607 html.append("</tr>"); 608 this._rowIds[i] = weekId; 609 } 610 611 html.append("</table>"); 612 html.append("</div>"); 613 html.append("</td></tr>"); 614 html.append("</table>"); 615 this.getHtmlElement().innerHTML = html.toString(); 616 617 }; 618 619 ZmCalMonthView.prototype._updateWeekNumber = 620 function(i) { 621 if(!this._showWeekNumber) return; 622 623 var day = this._days[i*7 + 0]; 624 if(day && day.date) { 625 626 //todo: need to use server setting to decide the weekno standard 627 var serverId = AjxTimezone.getServerId(AjxTimezone.DEFAULT); 628 var useISO8601WeekNo = (serverId && serverId.indexOf("Europe")==0 && serverId != "Europe/London"); 629 630 // AjxDateUtil alters the date. Make a copy 631 var date = new Date(day.date.getTime()); 632 var weekNumber = AjxDateUtil.getWeekNumber(date, this.firstDayOfWeek(), null, useISO8601WeekNo); 633 634 var wkId = this._weekNumberIds[i]; 635 var wkCell = wkId ? document.getElementById(wkId) : null; 636 if(wkCell) { 637 wkCell.innerHTML = weekNumber; 638 } 639 } 640 }; 641 642 ZmCalMonthView.prototype._updateDays = 643 function() { 644 var d = new Date(this._date.getTime()); 645 this._month = d.getMonth(); 646 647 d.setHours(0,0,0,0); 648 d.setDate(1) 649 var dow = d.getDay(); 650 var fdow = this.firstDayOfWeek(); 651 if (dow != fdow) { 652 d.setDate(d.getDate()-((dow+(7-fdow))%7)); 653 } 654 655 this._dateToDayIndex = new Object(); 656 657 var today = new Date(); 658 today.setHours(0,0,0, 0); 659 660 for (var i=0; i < 6; i++) { 661 for (var j=0; j < 7; j++) { 662 var loc = this._calcDayIndex(i, j); 663 var day = this._days[loc]; 664 day.date = new Date(d.getTime()); 665 this._dateToDayIndex[this._dayKey(day.date)] = day; 666 var thisMonth = day.date.getMonth() == this._month; 667 var te = document.getElementById(day.titleId); 668 var isToday = d.getTime() == today.getTime(); 669 //te.innerHTML = d.getTime() == today.getTime() ? ("<div class=calendar_month_day_today>" + this._dayTitle(d) + "</div>") : this._dayTitle(d); 670 te.innerHTML = this._dayTitle(d); 671 te.className = (thisMonth ? 'calendar_month_day_label' : 'calendar_month_day_label_off_month') + (isToday ? "_today" : ""); 672 day.dayClassName = te.className; 673 var id = day.tdId; 674 var de = document.getElementById(id); 675 de.className = 'calendar_month_cells_td'; 676 this.associateItemWithElement(null, de, ZmCalBaseView.TYPE_MONTH_DAY, id, {loc:loc}); 677 //d.setTime(d.getTime() + AjxDateUtil.MSEC_PER_DAY); 678 var oldDate = d.getDate(); 679 d.setDate(d.getDate() + 1); 680 if(oldDate == d.getDate()) { 681 //daylight saving problem 682 d.setHours(0,0,0,0); 683 d.setTime(d.getTime() + AjxDateUtil.MSEC_PER_DAY); 684 } 685 } 686 this._updateWeekNumber(i); 687 } 688 689 var formatter = DwtCalendar.getMonthFormatter(); 690 this._title = formatter.format(this._date); 691 var titleEl = document.getElementById(this._titleId); 692 titleEl.innerHTML = this._title; 693 }; 694 695 ZmCalMonthView.prototype._calcDayIndex = 696 function(rowIndex, colIndex) { 697 return (rowIndex * 7) + colIndex; 698 } 699 700 ZmCalMonthView.prototype.getShortCalTitle = function(){ 701 var formatter = DwtCalendar.getShortMonthFormatter(); 702 return formatter.format(this._date); 703 }; 704 705 ZmCalMonthView.prototype._setAllDayDivSize = 706 function(allDayDiv, width) { 707 Dwt.setSize(allDayDiv, width, 16 + 4); //Dwt.DEFAULT); 708 var apptBodyDiv = document.getElementById(allDayDiv.id + ZmCalMonthView.ALL_DAY_DIV_BODY); 709 Dwt.setSize(apptBodyDiv, width, 16); //Dwt.DEFAULT); 710 } 711 712 ZmCalMonthView.prototype._layoutAllDay = 713 function() { 714 var dayY = []; 715 var sum = 0; 716 for (var i=0; i < 6; i++) { 717 dayY[i] = sum; 718 var sz = Dwt.getSize(document.getElementById( this._days[7*i].tdId)); 719 if (i == 0) 720 this.dayWidth = sz.x; 721 sum += sz.y; 722 } 723 724 var apptWidth = this.dayWidth; 725 for (var uniqueId in this._apptSets) { 726 var apptSet = this._apptSets[uniqueId]; 727 if (!apptSet.allDay) continue; 728 729 for (var iAppt = 0; iAppt < apptSet.appts.length; iAppt++) { 730 var appt = apptSet.appts[iAppt]; 731 var ae = document.getElementById( this._getItemId(appt)); 732 if (ae) { 733 var width = this._calculateAllDayWidth(apptWidth, ae.head, ae.tail); 734 this._setAllDayDivSize(ae, width); 735 736 var day = this._getDayForAppt(appt); 737 if (day) { 738 var dow = (apptSet.dow + iAppt) % 7; 739 var apptX = this._calculateAllDayX(dow, ae.head) + (this._showWeekNumber ? 15 : 0); // Add week number width 740 var apptY = dayY[day.week] + (21*apptSet.rows[day.week]) + 18 + 3; //first 17, each appt + 1, second 17, day heading 741 Dwt.setLocation(ae, apptX, apptY); 742 } 743 } 744 } 745 } 746 747 }; 748 749 // Week = week integer index, row = row index within cell, dow = day of week, 750 // iAppt = appt slice of a multi-day appt, 0 .. (numDays-1) 751 ZmCalMonthView.prototype._calculateAllDayX = 752 function(dow, head) { 753 var apptX = 0; 754 if (head) { 755 apptX = (this.dayWidth * dow) + 3; 756 } else { 757 apptX = this.dayWidth * dow; 758 } 759 return apptX; 760 } 761 762 763 ZmCalMonthView.prototype._calculateAllDayWidth = 764 function(baseWidth, head, tail) { 765 var apptWidth = baseWidth; 766 if (head) { 767 apptWidth -= 3; 768 } 769 //return (this.dayWidth * (dow + iAppt)) + 3; 770 // +1 for overlap to make box-shadow on the bottom be seamless 771 return apptWidth + (tail ? -3 : 1); 772 } 773 774 775 ZmCalMonthView.prototype._layout = 776 function() { 777 778 DBG.println("ZmCalMonthView _layout!"); 779 780 var sz = this.getSize(); 781 var width = sz.x; 782 var height = sz.y; 783 784 if (width == 0 || height == 0) { 785 return; 786 } 787 788 this._needFirstLayout = false; 789 790 var he = document.getElementById(this._headerId); 791 var headingHeight = Dwt.getSize(he).y; 792 793 var w = width - 5; // No need to subtract week number column width. 794 var h = height - headingHeight - 10; 795 796 var de = document.getElementById(this._daysId); 797 Dwt.setSize(de, w, h); 798 799 var be = document.getElementById(this._bodyId); 800 if(h < Dwt.getSize(be).y){ 801 w = w - 15; //Less Scroll bar width 802 } 803 Dwt.setSize(be, w, h); 804 805 // Set the width to 15px fixed. 806 if (this._showWeekNumber) { 807 var wk = document.getElementById(this._weekNumBodyId); 808 Dwt.setSize(wk, 15, Dwt.DEFAULT); 809 } 810 811 colWidth = Math.floor(w / (this._showWeekNumber ? 8 : 7)) - 1; // Divide by 8 columns. 812 813 var fdow = this.firstDayOfWeek(); 814 for (var i=0; i < 7; i++) { 815 var col = document.getElementById(this._headerColId[i]); 816 Dwt.setSize(col, colWidth, Dwt.DEFAULT); 817 col = document.getElementById(this._bodyColId[i]); 818 Dwt.setSize(col, colWidth, Dwt.DEFAULT); 819 820 var dayName = document.getElementById(this._dayNameId[i]); 821 dayName.innerHTML = AjxDateUtil.WEEKDAY_LONG[(i+fdow)%7]; 822 } 823 824 for (var i=0; i < 6; i++) { 825 var row = document.getElementById(this._rowIds[i]); 826 Dwt.setSize(row, Dwt.DEFAULT, Math.floor(100/6) + '%'); 827 } 828 829 this._layoutAllDay(h); 830 if(this._expandedDayInfo) { 831 this.resizeCalendarGrid(); 832 } 833 this.resizeAllWeekNumberCell(); 834 }; 835 836 ZmCalMonthView.getDayToolTipText = 837 function(date, list, controller, noheader) { 838 var html = []; 839 var idx = 0; 840 841 html[idx++] = "<div><table cellpadding=0 cellspacing=0 border=0>"; 842 if (!noheader) { 843 html[idx++] = "<tr><td><div class='calendar_tooltip_month_day_label'>"; 844 html[idx++] = DwtCalendar.getDateFullFormatter().format(date); 845 html[idx++] = "</div></td></tr>"; 846 } 847 html[idx++] = "<tr><td><table cellpadding=1 cellspacing=0 border=0 width=100%>"; 848 849 var size = list ? list.size() : 0; 850 851 for (var i=0; i < size; i++) { 852 var ao = list.get(i); 853 if (ao.isAllDayEvent()) { 854 var bs = ""; 855 //if (!ao._fanoutFirst) bs = "border-left:none;"; 856 //if (!ao._fanoutLast) bs += "border-right:none;"; 857 //var bodyStyle = bs != "" ? ("style='" + bs + "'") : ""; 858 html[idx++] = "<tr><td><div class='appt'>"; 859 html[idx++] = ZmApptViewHelper._allDayItemHtml(ao, this._getItemId(ao), 860 controller, true, true); 861 html[idx++] = "</div></td></tr>"; 862 } 863 } 864 865 for (var i=0; i < size; i++) { 866 var ao = list.get(i); 867 if (!ao.isAllDayEvent()) { 868 var isNew = ao.ptst == ZmCalBaseItem.PSTATUS_NEEDS_ACTION; 869 var dur = ao.getDurationText(false, false); 870 871 html[idx++] = "<tr><td class='calendar_month_day_item'><div class='"; 872 html[idx++] = ZmCalendarApp.COLORS[controller.getCalendarColor(ao.folderId)]; 873 html[idx++] = isNew ? "DarkC" : "C"; 874 html[idx++] = "'>"; 875 if (isNew) html[idx++] = "<b>"; 876 html[idx++] = dur; 877 if (dur != "") html[idx++] = " "; 878 html[idx++] = AjxStringUtil.htmlEncode(ao.getName()); 879 if (isNew) html[idx++] = "</b>"; 880 html[idx++] = "</div></td></tr>"; 881 } 882 } 883 if ( size == 0) { 884 html[idx++] = "<tr><td>"; 885 html[idx++] = ZmMsg.noAppts; 886 html[idx++] = "</td></tr>"; 887 } 888 html[idx++] = "</table></tr></td></table></div>"; 889 890 return html.join(""); 891 }; 892 893 ZmCalMonthView.prototype._mouseDownAction = 894 function(ev, div) { 895 896 //if (Dwt.ffScrollbarCheck(ev)) { return false; } 897 898 var type = this._getItemData(div, "type"); 899 switch (type) { 900 case ZmCalBaseView.TYPE_MONTH_DAY: 901 if (!appCtxt.isWebClientOffline()) { 902 this._timeSelectionAction(ev, div, false); 903 if (ev.button == DwtMouseEvent.RIGHT) { 904 DwtUiEvent.copy(this._actionEv, ev); 905 this._actionEv.item = this; 906 this._evtMgr.notifyListeners(ZmCalBaseView.VIEW_ACTION, this._actionEv); 907 } 908 } 909 break; 910 case ZmCalBaseView.TYPE_APPT: 911 this.setToolTipContent(null); 912 this._apptMouseDownAction(ev, div); 913 break; 914 case ZmCalBaseView.TYPE_ALL_DAY: 915 this.setToolTipContent(null); 916 this._apptMouseDownAction(ev, div); 917 break; 918 } 919 return false; 920 }; 921 922 923 ZmCalMonthView.prototype._doubleClickAction = 924 function(ev, div) { 925 ZmCalBaseView.prototype._doubleClickAction.call(this, ev, div); 926 var type = this._getItemData(div, "type"); 927 if (type == ZmCalBaseView.TYPE_MONTH_DAY) { 928 this._timeSelectionAction(ev, div, true); 929 } 930 }; 931 932 ZmCalMonthView.prototype._timeSelectionAction = 933 function(ev, div, dblclick) { 934 935 var date; 936 937 var type = this._getItemData(div, "type"); 938 switch (type) { 939 case ZmCalBaseView.TYPE_MONTH_DAY: 940 var loc = this._getItemData(div, "loc"); 941 date = new Date(this._days[loc].date.getTime()); 942 var now = new Date(); 943 date.setHours(now.getHours(), now.getMinutes()); 944 if(ev.button == DwtMouseEvent.LEFT) { 945 if(ZmCalViewController._contextMenuOpened){ 946 ZmCalViewController._contextMenuOpened = false; 947 break; 948 } 949 AjxTimedAction.scheduleAction(new AjxTimedAction(this, this.expandDay, [this._days[loc]]), 200); 950 } 951 break; 952 default: 953 return; 954 } 955 this._timeSelectionEvent(date, AjxDateUtil.MSEC_PER_HOUR, dblclick); 956 }; 957 958 ZmCalMonthView.prototype.setDayView = 959 function(dayInfo) { 960 var tdCell = document.getElementById(dayInfo.tdId); 961 var size = Dwt.getSize(tdCell); 962 var view = this._dayView ; 963 var isDirty = !view || !view.getVisible() || !view.getDate() || view.getDate().getTime() !== dayInfo.date.getTime(); 964 965 if(!view) { 966 view = this._dayView = new ZmCalDayView(this, DwtControl.ABSOLUTE_STYLE, this._controller, this._dropTgt); 967 view.setCompactMode(true); 968 view.setCloseDayViewCallback(new AjxCallback(this, this._closeDayView)); 969 //listener changes 970 view.addViewActionListener(new AjxListener(this._controller, this._controller._viewActionListener)); 971 view.addTimeSelectionListener(new AjxListener(this._controller, this._controller._timeSelectionListener)); 972 view.addSelectionListener(new AjxListener(this, this._dayListSelectionListener)); 973 view.addActionListener(new AjxListener(this._controller, this._controller._listActionListener)); 974 975 }else { 976 view.setVisible(true); 977 } 978 979 if (isDirty) { 980 view.setDate(dayInfo.date, 0, true); 981 982 var subList = new AjxVector(); 983 var appts = dayInfo.appts; 984 985 if(appts) { 986 for(var i = 0; i < appts.length; i++) { 987 subList.add(appts[i]); 988 } 989 } 990 991 var allDayAppts = dayInfo.allDayAppts; 992 993 if(allDayAppts) { 994 for(var i = 0; i < allDayAppts.length; i++) { 995 subList.add(allDayAppts[i]) 996 } 997 } 998 999 view._preSet(); 1000 view.set(subList, true); 1001 } 1002 1003 view.setSize(size.x - 10, size.y - 12); 1004 view._syncScroll(); 1005 1006 var loc = Dwt.toWindow(tdCell, 0, 0, this.getHtmlElement(), true); 1007 view.setLocation(loc.x+5, loc.y+5); 1008 1009 view._layout(true); 1010 }; 1011 1012 ZmCalMonthView.prototype.expandDay = 1013 function(dayInfo) { 1014 this.clearCalendarGrid(true); 1015 this.startExpand(dayInfo); 1016 }; 1017 1018 1019 ZmCalMonthView.prototype.clearCalendarGrid = 1020 function(markApptDays) { 1021 for (var i=0; i < 6; i++) { 1022 1023 //clear all day appts 1024 for (var uniqueId in this._apptSets) { 1025 var apptSet = this._apptSets[uniqueId]; 1026 if (!apptSet.allDay) continue; 1027 1028 for (var iAppt = 0; iAppt < apptSet.appts.length; iAppt++) { 1029 var appt = apptSet.appts[iAppt]; 1030 var ae = document.getElementById( this._getItemId(appt)); 1031 if(ae) { 1032 ae.parentNode.removeChild(ae); 1033 } 1034 } 1035 } 1036 1037 for (var j=0; j < 7; j++) { 1038 var loc = i*7+j; 1039 var day = this._days[loc]; 1040 if(day && day.dayId) { 1041 var node = document.getElementById(day.dayId); 1042 while(node && node.firstChild) { 1043 node.firstChild.parentNode.removeChild(node.firstChild); 1044 } 1045 } 1046 if(day && day.titleId) { 1047 var te = document.getElementById(day.titleId); 1048 te.className = day.dayClassName?day.dayClassName : ''; 1049 Dwt.setOpacity(te, 100); 1050 if(markApptDays) { 1051 var apptAvailable = (day.appts && day.appts.length > 0) || (day.allDayAppts && day.allDayAppts.length > 0); 1052 te.className = te.className + (apptAvailable ? ' calendar_month_day_label_bold' : ''); 1053 } 1054 } 1055 } 1056 } 1057 1058 //clear all day fillers 1059 if (this._fillers.length > 0) { 1060 for (var i=0; i < this._fillers.length; i++) { 1061 var f = this._fillers[i]; 1062 this._fillers[i] = null; 1063 if(f.parentNode) { 1064 f.parentNode.removeChild(f); 1065 } 1066 } 1067 this._fillers = []; 1068 } 1069 }; 1070 1071 ZmCalMonthView.prototype.resizeWeekNumberCell = 1072 function(row, height) { 1073 1074 if(!this._showWeekNumber) return; 1075 1076 var weekNumCell = document.getElementById(this._weekNumberIds[row]); 1077 if (weekNumCell) { 1078 Dwt.setSize(weekNumCell, 15, Dwt.DEFAULT); // No need to set fixed height to rows. 1079 } 1080 }; 1081 1082 ZmCalMonthView.prototype.resizeCalendarGrid = 1083 function() { 1084 var grid = document.getElementById(this._daysId) 1085 var size = Dwt.getSize(grid); 1086 1087 var avgHeight = size.y/6; 1088 var avgWidth = size.x/7; 1089 1090 for (var i=0; i < 6; i++) { 1091 var row = document.getElementById(this._rowIds[i]); 1092 if(i==5) { 1093 avgHeight = avgHeight-1; 1094 } 1095 Dwt.setSize(row, Dwt.DEFAULT, avgHeight); 1096 1097 if(AjxEnv.isSafari) { 1098 Dwt.setSize(this.getCell(i, 0), Dwt.DEFAULT, avgHeight); 1099 } 1100 } 1101 1102 for (var j=0; j < 7; j++) { 1103 var hdrCol = document.getElementById(this._headerColId[j]); 1104 var bdyCol = document.getElementById(this._bodyColId[j]); 1105 if(j==6) { 1106 avgWidth = avgWidth-1; 1107 } 1108 Dwt.setSize(hdrCol, avgWidth, Dwt.DEFAULT); 1109 Dwt.setSize(bdyCol, avgWidth, Dwt.DEFAULT); 1110 if(AjxEnv.isSafari) { 1111 Dwt.setSize(this.getCell(0, j), avgWidth, Dwt.DEFAULT); 1112 } 1113 } 1114 }; 1115 1116 ZmCalMonthView.prototype.resizeAllWeekNumberCell = 1117 function() { 1118 // Calculate the row heights and apply to the week number cells 1119 var previousY = 0; 1120 for (var iRow=0; iRow < 6; iRow++) { 1121 var row = document.getElementById(this._rowIds[iRow]); 1122 // Use location to calculate y size - getSize may get off by one 1123 // due to rounding errors. 1124 var location = Dwt.getLocation(row); 1125 if (iRow > 0) { 1126 var ySize = location.y - previousY; 1127 this.resizeWeekNumberCell(iRow-1, ySize); 1128 } 1129 previousY = location.y; 1130 } 1131 } 1132 1133 ZmCalMonthView.prototype._closeDayView = 1134 function() { 1135 if(this._dayView) { 1136 this._dayView.setVisible(false); 1137 this._needFirstLayout = false; 1138 this.clearExpandedDay(); 1139 this.clearCalendarGrid(); 1140 var newList = new AjxVector(); 1141 newList.addList(this._list || []) 1142 this.set(newList, true); 1143 } 1144 }; 1145 1146 ZmCalMonthView.prototype.resizeCol = 1147 function(colIdx, params) { 1148 var dayInfo = params.dayInfo; 1149 var hdrCol = document.getElementById(this._headerColId[colIdx]); 1150 var bdyCol = document.getElementById(this._bodyColId[colIdx]); 1151 var newWidth = params.avgWidth; 1152 1153 if(dayInfo.dow == colIdx) { 1154 newWidth = params.expandedWidth; 1155 }else if( params.collapseColId == colIdx) { 1156 newWidth = params.collapsedWidth; 1157 } 1158 1159 if(bdyCol && hdrCol) { 1160 newWidth = (colIdx==6) ? newWidth-1 : newWidth; 1161 Dwt.setSize(bdyCol, newWidth, Dwt.DEFAULT); 1162 Dwt.setSize(hdrCol, newWidth, Dwt.DEFAULT); 1163 1164 if(AjxEnv.isSafari || AjxEnv.isChrome || (AjxEnv.isFirefox2_0up && !AjxEnv.isFirefox3up)) { 1165 //change first column cell 1166 Dwt.setSize(this.getCell(0, colIdx), newWidth, Dwt.DEFAULT); 1167 } 1168 1169 } 1170 }; 1171 1172 ZmCalMonthView.prototype.resizeRow = 1173 function(rowIdx, params) { 1174 1175 if(rowIdx==null) return; 1176 1177 var dayInfo = params.dayInfo; 1178 var height = params.avgHeight; 1179 1180 var colId = null; 1181 1182 if(dayInfo.week == rowIdx) { 1183 height = params.expandedHeight; 1184 colId = dayInfo.dow; 1185 }else if( params.collapseRowId == rowIdx) { 1186 height = params.collapsedHeight; 1187 } 1188 1189 height = (rowIdx==5) ? height-1 : height; 1190 1191 var row = document.getElementById(this._rowIds[rowIdx]); 1192 Dwt.setSize(row, Dwt.DEFAULT, height); 1193 1194 //change first row cell 1195 if(AjxEnv.isSafari || AjxEnv.isChrome) { 1196 Dwt.setSize(this.getCell(rowIdx,0), Dwt.DEFAULT, height); 1197 } 1198 1199 //IE needs direct cell expansion 1200 if(AjxEnv.isIE && colId!=null && rowIdx!=null) { 1201 var day = this.getCell(rowIdx, colId); 1202 Dwt.setSize(day, Dwt.DEFAULT, height); 1203 } 1204 1205 this.resizeWeekNumberCell(rowIdx, height); 1206 }; 1207 1208 ZmCalMonthView.prototype.resizeCell = 1209 function(dayInfo, height) { 1210 var day = this.getCell(dayInfo.week, dayInfo.dow); 1211 Dwt.setSize(day, Dwt.DEFAULT, height); 1212 this.resizeWeekNumberCell(dayInfo.week, height); 1213 }; 1214 1215 ZmCalMonthView.prototype.clearCellHeight = 1216 function(dayInfo) { 1217 if(!dayInfo) return; 1218 var day = this.getCell(dayInfo.week, dayInfo.dow); 1219 Dwt.setSize(day, Dwt.DEFAULT, Dwt.CLEAR); 1220 this.resizeWeekNumberCell(dayInfo.week, Dwt.CLEAR); 1221 }; 1222 1223 ZmCalMonthView.prototype.getCell = 1224 function(row, col) { 1225 var loc = row*7+col; 1226 var cellId = this._days[loc].tdId 1227 return document.getElementById(cellId); 1228 }; 1229 1230 ZmCalMonthView.prototype.startExpand = 1231 function(dayInfo) { 1232 1233 var grid = document.getElementById(this._daysId) 1234 var size = Dwt.getSize(grid); 1235 1236 var expandedHeight = size.y*ZmCalMonthView.EXPANDED_HEIGHT_PERCENT/100; 1237 var expandedWidth = size.x*ZmCalMonthView.EXPANDED_WIDTH_PERCENT/100; 1238 var avgHeight = (size.y-expandedHeight)/5; 1239 var avgWidth = (size.x-expandedWidth)/6; 1240 1241 var param = { 1242 dayInfo: dayInfo, 1243 avgWidth: avgWidth, 1244 avgHeight: avgHeight, 1245 maxWidth: expandedWidth, 1246 maxHeight: expandedHeight, 1247 changeCol: true, 1248 changeRow: true, 1249 startTime: new Date().getTime() 1250 }; 1251 1252 //old expanded day needs to be collapsed 1253 if(this._expandedDayInfo) { 1254 var oldDayInfo = this._expandedDayInfo; 1255 1256 param.collapseRowId = oldDayInfo.week; 1257 param.collapseColId = oldDayInfo.dow; 1258 1259 if(oldDayInfo.week == dayInfo.week) { 1260 param.changeRow = false; 1261 } 1262 if(oldDayInfo.dow == dayInfo.dow) { 1263 param.changeCol = false; 1264 } 1265 } 1266 1267 if(this._dayView) { 1268 this._dayView.setVisible(false); 1269 } 1270 1271 clearInterval(this._animationInterval); 1272 this._animationFrames = 0; 1273 this._animationInterval = 1274 setInterval(this.animateExpansion.bind(this, param), 1275 ZmCalMonthView.ANIMATE_INTERVAL); 1276 1277 this.animateExpansion(param); 1278 }; 1279 1280 1281 ZmCalMonthView.prototype.animateExpansion = 1282 function(param) { 1283 var diffWidth = param.maxWidth - param.avgWidth; 1284 var diffHeight = param.maxHeight - param.avgHeight; 1285 1286 var passed = new Date().getTime() - param.startTime; 1287 var progressFraction = 1288 Math.min(passed / ZmCalMonthView.ANIMATE_DURATION, 1); 1289 var opacity = 100 * progressFraction; 1290 1291 if(param.changeCol) { 1292 param.expandedWidth = param.avgWidth + diffWidth * progressFraction; 1293 param.collapsedWidth = param.maxWidth - diffWidth * progressFraction; 1294 }else { 1295 param.expandedWidth = param.collapsedWidth = param.maxWidth; 1296 } 1297 1298 if(param.changeRow) { 1299 param.expandedHeight = param.avgHeight + diffHeight * progressFraction; 1300 param.collapsedHeight = param.maxHeight - diffHeight * progressFraction; 1301 }else { 1302 param.expandedHeight = param.collapsedHeight = param.maxHeight; 1303 } 1304 1305 this._expandDayGrid(param); 1306 this.setDayView(param.dayInfo); 1307 1308 this._dayView.setOpacity(opacity); 1309 Dwt.setOpacity(Dwt.byId(param.dayInfo.titleId), 100 - opacity); 1310 1311 this._animationFrames += 1; 1312 1313 // are we done? 1314 if (progressFraction === 1) { 1315 clearInterval(this._animationInterval); 1316 1317 var dayInfo = param.dayInfo; 1318 this._expandedDayInfo = { 1319 week: dayInfo.week, 1320 dow: dayInfo.dow, 1321 date: dayInfo.date 1322 }; 1323 1324 var fps = Math.round(this._animationFrames / passed * 1000); 1325 DBG.println(AjxDebug.DBG1, "fisheye animation speed: " + fps + "FPS"); 1326 } 1327 }; 1328 1329 ZmCalMonthView.prototype._expandDayGrid = 1330 function(params) { 1331 1332 var dayInfo = params.dayInfo; 1333 1334 if(!this._expandedDayInfo) { 1335 for (var i=0; i < 6; i++) { 1336 this.resizeRow(i, params); 1337 } 1338 for (var j=0; j < 7; j++) { 1339 this.resizeCol(j, params); 1340 } 1341 }else { 1342 if(params.changeRow) { 1343 this.resizeRow(params.collapseRowId, params); 1344 this.resizeRow(dayInfo.week, params); 1345 } 1346 1347 if(params.changeCol) { 1348 this.resizeCol(params.collapseColId, params); 1349 this.resizeCol(dayInfo.dow, params); 1350 } 1351 1352 if(AjxEnv.isIE){ 1353 if(!params.changeRow) { 1354 this.resizeCell(dayInfo, params.maxHeight); 1355 } 1356 this.clearCellHeight(this._expandedDayInfo); 1357 } 1358 1359 } 1360 }; 1361 1362 ZmCalMonthView.prototype.clearExpandedDay = 1363 function() { 1364 if(!this._expandedDayInfo) return; 1365 this.clearCellHeight(this._expandedDayInfo); 1366 this.resizeCalendarGrid(); 1367 this.resizeAllWeekNumberCell(); 1368 this._expandedDayInfo = null; 1369 }; 1370 1371 ZmCalMonthView.prototype._controlListener = 1372 function(ev) { 1373 if(!this._expandedDayInfo) { 1374 ZmCalBaseView.prototype._controlListener.call(this, ev); 1375 var mvTable = document.getElementById(this._monthViewTable); 1376 var s = Dwt.getSize(mvTable); 1377 if(s.y != ev.newHeight || s.x != ev.newWidth){ 1378 this._layout(); 1379 } 1380 }else { 1381 this._closeDayView(); 1382 } 1383 }; 1384 1385 ZmCalMonthView.prototype._viewActionListener = 1386 function(ev) { 1387 this.notifyListeners(ZmCalBaseView.VIEW_ACTION, ev); 1388 }; 1389 1390 ZmCalMonthView.prototype._dayListSelectionListener = 1391 function(ev) { 1392 this._evtMgr.notifyListeners(DwtEvent.SELECTION, ev); 1393 }; 1394 1395 ZmCalMonthView.prototype.getSelection = 1396 function() { 1397 if(this._expandedDayInfo) { 1398 return this._dayView.getSelection(); 1399 }else { 1400 return ZmCalBaseView.prototype.getSelection.call(this); 1401 } 1402 }; 1403 1404 ZmCalMonthView.prototype.resizeDayCell = 1405 function(rowId, colId) { 1406 var sz = this.getSize(); 1407 var width = sz.x; 1408 var height = sz.y; 1409 1410 var he = document.getElementById(this._headerId); 1411 var headingHeight = Dwt.getSize(he).y; 1412 1413 var w = width - 5; 1414 var h = height - headingHeight - 10; 1415 1416 var de = document.getElementById(this._daysId); 1417 Dwt.setSize(de, w, h); 1418 1419 var be = document.getElementById(this._bodyId); 1420 Dwt.setSize(be, w, h); 1421 1422 var grid = document.getElementById(this._daysId) 1423 var size = Dwt.getSize(grid); 1424 var height = size.y*ZmCalMonthView.EXPANDED_HEIGHT_PERCENT/100; 1425 var width = size.x*ZmCalMonthView.EXPANDED_WIDTH_PERCENT/100; 1426 1427 1428 var row = document.getElementById(this._rowIds[rowId]); 1429 var bodyCol = document.getElementById(this._bodyColId[colId]); 1430 var headerCol = document.getElementById(this._headerColId[colId]); 1431 if(row) { 1432 Dwt.setSize(row, Dwt.DEFAULT, height); 1433 Dwt.setSize(row.firstChild, Dwt.DEFAULT, height); 1434 Dwt.setSize(document.getElementById(this._days[rowId*7+colId].tdId), Dwt.DEFAULT, height); 1435 } 1436 if(bodyCol && headerCol) { 1437 Dwt.setSize(bodyCol, width, Dwt.DEFAULT); 1438 Dwt.setSize(headerCol, width, Dwt.DEFAULT); 1439 } 1440 1441 }; 1442 1443 // --- Overrides of ZmCalBaseView Appt DnD, and custom DnD functions 1444 ZmCalMonthView.prototype._createContainerRect = 1445 function(data) { 1446 var calendarBody = document.getElementById(this._bodyId); 1447 var calPt = Dwt.getLocation(calendarBody); 1448 var calSize = Dwt.getSize(calendarBody); 1449 this._containerRect = new DwtRectangle(calPt.x, calPt.y, calSize.x, calSize.y); 1450 data.originX = calPt.x; 1451 data.originY = calPt.y; 1452 DBG.println(AjxDebug.DBG3,"_createContainerRect containerRect.y: " + calPt.y); 1453 } 1454 1455 1456 // called when DND is confirmed after threshold 1457 ZmCalMonthView.prototype._apptDndBegin = 1458 function(data) { 1459 var loc = Dwt.getLocation(data.apptEl); 1460 data.dndObj = {}; 1461 data.apptX = loc.x; 1462 data.apptY = loc.y; 1463 //DBG.println(AjxDebug.DBG3,"MouseMove Begin apptOffset.x,y: " + data.apptOffset.x + "," + data.apptOffset.y + 1464 // ", originX, originY: " + data.originX + "," + data.originY); 1465 1466 this._colWidth = this.dayWidth; 1467 1468 data.snap = this._snapXYToDate(data.docX - data.originX, data.docY - data.originY); 1469 if (data.snap == null) return false; 1470 1471 var originalAppt = data.appt._orig; 1472 data.startDate = new Date(originalAppt.getStartTime()); 1473 var date = new Date(data.startDate); 1474 date.setHours(0,0,0,0); 1475 data.startDayIndex = this._createDayIndexFromDate(date); 1476 data.offsetDayIndex = data.snap.dayIndex - data.startDayIndex; 1477 data.startDateOffset = -(data.offsetDayIndex * AjxDateUtil.MSEC_PER_DAY); 1478 data.timeOffset = []; 1479 1480 if (data.appt.isAllDayEvent()) { 1481 // All day, possibly multi-day appt 1482 data.timeOffset.push(0); 1483 data.numDays = this._createDayIndexFromDate(originalAppt.endDate) - data.startDayIndex; 1484 data.offsetY = []; 1485 var allDayDiv = null; 1486 var blankHtml = null; 1487 1488 // Offscreen divs are already setup, merely not positioned and made visible. 1489 // Alter the display html of onscreen divs from 2nd to last-1 to be blank (!head and !tail) 1490 for (var i = 0; i < data.numDays; i++) { 1491 var iDay = data.startDayIndex + i; 1492 allDayDiv = data.apptEl || this._getAllDayDiv(data.appt, i); 1493 if ((iDay >= 0) && (iDay < this.numDays)) { 1494 // Initially onscreen div 1495 day = this._days[iDay]; 1496 this._calculateOffsetY(data, allDayDiv, day.week); 1497 if (data.numDays > 1) { 1498 if (i == 0) { 1499 allDayDiv.saveHtml = allDayDiv.innerHTML; 1500 this._clearIcon(allDayDiv.id, "tag"); 1501 this._clearIcon(allDayDiv.id, "peel"); 1502 } else { 1503 if (allDayDiv.head || (allDayDiv.tail && (i < (data.numDays - 1)))) { 1504 allDayDiv.saveHtml = allDayDiv.innerHTML; 1505 if (!blankHtml) { 1506 var itemId = this._getItemId(data.appt); 1507 blankHtml = ZmApptViewHelper._allDayItemHtml(data.appt, itemId, this._controller, false, false); 1508 } 1509 allDayDiv.innerHTML = blankHtml; 1510 allDayDiv.firstChild.id = allDayDiv.id + ZmCalMonthView.ALL_DAY_DIV_BODY; 1511 1512 allDayDiv.firstChild.style.cssText += "border-left: 0px none black !important;"; 1513 allDayDiv.firstChild.style.cssText += "border-right: 0px none black !important;"; 1514 this._setAllDayDnDSize(allDayDiv, false, false); 1515 } 1516 } 1517 } 1518 1519 } 1520 //this._setAllDayDnDSize(data, i, allDayDiv); 1521 this._highlightAllDayDiv(allDayDiv, data.appt, true); 1522 } 1523 1524 } else { 1525 // Non-all day appt - It could be a multi-day non-all-day appt 1526 var uniqueId = this._getApptUniqueId(data.appt); 1527 var apptSet = this._apptSets[uniqueId]; 1528 if (!apptSet) { 1529 // Non-multiday, Non-all-day 1530 var apptDay = this._getDayForAppt(data.appt); 1531 apptSet = this._createApptSet(data.appt, uniqueId, apptDay); 1532 apptSet.appts.push(data.appt); 1533 } 1534 data.trEl = []; 1535 data.tableEl = []; 1536 for (var iAppt = 0; iAppt < apptSet.appts.length; iAppt++) { 1537 var appt = apptSet.appts[iAppt]; 1538 var trId = this._getItemId(appt); 1539 var trEl = document.getElementById(trId); 1540 if (trEl == null) { 1541 // Offscreen ,create a tr for DnD 1542 trEl = document.createElement("tr"); 1543 trEl.className = "appt-selected"; 1544 this._createItemHtmlContents(appt, trEl); 1545 this.associateItemWithElement(appt, trEl, ZmCalBaseView.TYPE_APPT); 1546 } 1547 data.tableEl[iAppt] = Dwt.getDescendant(trEl, this._getItemId(appt) + "_tableBody"); 1548 data.trEl.push(trEl); 1549 data.timeOffset.push(this._getTimeOffset(appt.getStartTime())); 1550 } 1551 this._calculateWeekY(data); 1552 data.apptDiv = {}; 1553 } 1554 1555 data.dndStarted = true; 1556 return true; 1557 }; 1558 1559 ZmCalMonthView.prototype._clearIcon = 1560 function(allDayDivId, iconName) { 1561 var td = document.getElementById(allDayDivId + "_" + iconName); 1562 if (td) { 1563 td.innerHTML = ""; 1564 } 1565 } 1566 1567 1568 ZmCalMonthView.prototype._highlightAllDayDiv = 1569 function(allDayDiv, appt, highlight) { 1570 var apptBodyDiv = document.getElementById(allDayDiv.id + ZmCalMonthView.ALL_DAY_DIV_BODY); 1571 var tableEl = document.getElementById(this._getItemId(appt) + "_tableBody"); 1572 // Not altering opacity - it was setting it to 0.7 for DnD, but the base opacity for all day is 0.4 1573 if (highlight) { 1574 Dwt.addClass(apptBodyDiv, DwtCssStyle.DROPPABLE); 1575 Dwt.setZIndex(allDayDiv, "1000000000"); 1576 } else { 1577 Dwt.delClass(apptBodyDiv, DwtCssStyle.DROPPABLE); 1578 Dwt.setZIndex(allDayDiv, ""); 1579 } 1580 } 1581 1582 ZmCalMonthView.prototype._setAllDayDnDSize = 1583 function(allDayDiv, first, last) { 1584 var width = this._calculateAllDayWidth(this.dayWidth, first, last); 1585 this._setAllDayDivSize(allDayDiv, width); 1586 } 1587 1588 ZmCalMonthView.prototype._getAllDayDiv = 1589 function(appt, iSlice) { 1590 var divKey = appt.invId + "_" + iSlice.toString(); 1591 var allDayDivId = this._apptAllDayDiv[divKey]; 1592 return document.getElementById(allDayDivId); 1593 1594 } 1595 1596 1597 // Generate a dayIndex that may be < 0 or > (number of days-1), using this._days[0] as 1598 // the 0 reference 1599 ZmCalMonthView.prototype._createDayIndexFromDate = 1600 function(dayDate) { 1601 // Bug 68507: all-day appointments don't appear correctly in month view 1602 // Round it. If the dayDate is has a daylight savings time transition between itself 1603 // and the current day, the day index may be off by +/- 1/24. The DayIndex needs 1604 // to be an integer value, otherwise we get incorrect dayOfWeek values (dayIndex % 7) 1605 return Math.round((dayDate.getTime() - 1606 this._days[0].date.getTime())/AjxDateUtil.MSEC_PER_DAY); 1607 } 1608 1609 1610 // Calculate the y position of each week 1611 ZmCalMonthView.prototype._calculateWeekY = 1612 function(data) { 1613 data.weekY = []; 1614 var y = 0; 1615 for (var iWeek=0; iWeek < 6; iWeek++) { 1616 data.weekY[iWeek] = y; 1617 var size = Dwt.getSize(document.getElementById( this._days[7*iWeek].tdId)); 1618 y += size.y; 1619 } 1620 data.weekY[6] = y; 1621 } 1622 1623 ZmCalMonthView.prototype._calculateOffsetY = 1624 function(data, allDayDiv, week) { 1625 // Record the y offset within the start cell for a particular week 1626 if (!data.weekY) { 1627 this._calculateWeekY(data); 1628 } 1629 if (data.offsetY[week] === undefined) { 1630 var allDayDivPt = Dwt.getLocation(allDayDiv); 1631 data.offsetY[week] = (allDayDivPt.y - data.weekY[week]); 1632 } 1633 } 1634 1635 ZmCalMonthView.prototype._getTimeOffset = 1636 function(time) { 1637 var date = new Date(time); 1638 date.setHours(0,0,0,0); 1639 return time - date.getTime(); 1640 } 1641 1642 1643 ZmCalMonthView.prototype._snapXYToDate = 1644 function(x, y) { 1645 var colIndex = Math.floor(x/this._colWidth); 1646 var rowIndex = 5; 1647 1648 // Recheck the row heights each time - these can change as an DnD element 1649 // moves and out, potentially expanding or contracting a cell 1650 var height = 0; 1651 for (var iRow=0; iRow < 6; iRow++) { 1652 var row = document.getElementById(this._rowIds[iRow]); 1653 var rowSize = Dwt.getSize(row); 1654 height += rowSize.y; 1655 if (y < height) { 1656 rowIndex = iRow; 1657 break; 1658 } 1659 } 1660 // containerRect should aways have constrained this to be 0 <= index < numDays 1661 var dayIndex = this._calcDayIndex(rowIndex, colIndex); 1662 var dayOffset = 0; 1663 if (dayIndex < 0) { 1664 dayOffset = -dayIndex; 1665 dayIndex = 0; 1666 } else if (dayIndex >= this.numDays) { 1667 dayOffset = dayIndex - this.numDays + 1; 1668 dayIndex = this.numDays - 1; 1669 } 1670 var day = this._days[dayIndex]; 1671 var dayDate = new Date(this._days[dayIndex].date.getTime()); 1672 // Set to zero hours/min/sec/msec - the last day has a time set to 23:59:59:999 1673 dayDate.setHours(0,0,0,0); 1674 1675 var snapDate = null; 1676 if(day && dayDate) { 1677 snapDate = new Date(dayDate.getTime() + (AjxDateUtil.MSEC_PER_DAY * dayOffset)); 1678 } 1679 DBG.println(AjxDebug.DBG3,"mouseMove colIndex: " + colIndex + ", rowIndex: " + rowIndex + ", dayIndex: " + dayIndex + ", snapDate: " + snapDate); 1680 1681 return {date:snapDate, dayIndex:dayIndex}; 1682 } 1683 1684 1685 ZmCalMonthView.prototype._clearSnap = 1686 function(snap) { 1687 snap.dayIndex = ZmCalMonthView.OUT_OF_BOUNDS_SNAP; 1688 } 1689 1690 1691 ZmCalMonthView.prototype._doApptMove = 1692 function(data, deltaX, deltaY) { 1693 var x = data.docX - data.originX + deltaX; 1694 var y = data.docY - data.originY + deltaY; 1695 //DBG.println(AjxDebug.DBG3,"_doApptMove docY: " + data.docY + ", originY: " + data.originY + ", deltaY: " + deltaY + ", y: " + y); 1696 var snap = this._snapXYToDate(x, y); 1697 if ((snap != null) && (snap.dayIndex != data.snap.dayIndex)) { 1698 DBG.println(AjxDebug.DBG3,"mouseMove new snap: " + snap.date + " (" + snap.dayIndex + ") data snap: " + 1699 data.snap.date+ " (" + data.snap.dayIndex + ")"); 1700 1701 if (data.appt.isAllDayEvent()) { 1702 // Map the dayIndex to the start of the (potentially) multi-day appt 1703 this._moveAllDayAppt(data, snap.dayIndex- data.offsetDayIndex); 1704 } else { 1705 this._moveApptRow(data, snap.dayIndex); 1706 } 1707 data.startDate = new Date(snap.date.getTime() + data.startDateOffset + data.timeOffset[0]); 1708 data.snap = snap; 1709 } 1710 1711 } 1712 1713 ZmCalMonthView.prototype._moveAllDayAppt = 1714 function(data, newDayIndex) { 1715 var currentWeek = -1; 1716 var firstDow = this.firstDayOfWeek(); 1717 for (var i = 0; i < data.numDays; i++) { 1718 var iDay = newDayIndex + i; 1719 var allDayDiv = data.apptEl || this._getAllDayDiv(data.appt, i); 1720 if ((iDay < 0) || (iDay >= this.numDays)) { 1721 Dwt.setVisible(allDayDiv, false); 1722 } else { 1723 var dow = (newDayIndex + i) % 7; 1724 var first = (i== 0) || (firstDow == dow); 1725 var last = ((i == (data.numDays-1) || (iDay == (this.numDays-1)) || (dow == (firstDow + 6)))); 1726 var apptX = this._calculateAllDayX(dow, first); 1727 var day = this._days[iDay]; 1728 var apptY = 0; 1729 Dwt.setVisible(allDayDiv, true); 1730 this._setAllDayDnDSize(allDayDiv, first, last); 1731 var size = Dwt.getSize(allDayDiv); 1732 var halfHeight = size.y/2; 1733 if (data.offsetY[day.week] !== undefined) { 1734 apptY = data.weekY[day.week] + data.offsetY[day.week]; 1735 } else { 1736 apptY = (data.weekY[day.week] + data.weekY[day.week + 1])/2 - halfHeight; 1737 } 1738 Dwt.setLocation(allDayDiv, apptX, apptY); 1739 } 1740 } 1741 } 1742 1743 1744 // Move a non-all-day appt 1745 ZmCalMonthView.prototype._moveApptRow = 1746 function(data, newDayIndex) { 1747 newDayIndex = newDayIndex - data.offsetDayIndex; 1748 var allDayParent = null; 1749 for (var i = 0; i < data.trEl.length; i++) { 1750 var day = this._days[newDayIndex + i]; 1751 if (day) { 1752 if (!data.apptDiv[i]) { 1753 // TR -> TD -> TemplateApptDiv. 1754 var td = data.trEl[i].firstChild; 1755 var templateApptDiv = td.firstChild; 1756 td.saveHTML = td.innerHTML; 1757 // Replace the templateApptDiv with filler content 1758 td.removeChild(templateApptDiv); 1759 // Create a spacer row - changes in height invalidates the all day div positioning 1760 this._createAllDayFillerContent(data.trEl[i], false); 1761 if (!allDayParent) { 1762 allDayParent = document.getElementById( this._daysId); 1763 } 1764 data.apptDiv[i] = this._createDnDApptDiv(data, i, allDayParent, templateApptDiv); 1765 } 1766 Dwt.setVisible(data.apptDiv[i], true); 1767 var apptTable = data.apptDiv[i].firstChild; 1768 var apptSize = Dwt.getSize(apptTable); 1769 var apptX = (this.dayWidth * day.dow) + this.dayWidth/2 - apptSize.x/2 + (this._showWeekNumber ? 15 : 0); // Adjust week number width while dragging 1770 var apptY = (data.weekY[day.week] + data.weekY[day.week + 1])/2 - apptSize.y/2; 1771 Dwt.setLocation(data.apptDiv[i], apptX, apptY); 1772 1773 } else if (data.apptDiv[i]) { 1774 Dwt.setVisible(data.apptDiv[i], false); 1775 } 1776 } 1777 } 1778 1779 ZmCalMonthView.prototype._createDnDApptDiv = 1780 function(data, iAppt, allDayParent, templateApptDiv) { 1781 var div = document.createElement("div"); 1782 var subs = { apptSlice:iAppt}; 1783 div.style.position = "absolute"; 1784 // Attach month appt to DnD proxy div 1785 div.appendChild(templateApptDiv); 1786 1787 var trSize = Dwt.getSize(data.trEl[iAppt]); 1788 Dwt.setSize(div, trSize.x, Dwt.CLEAR); 1789 Dwt.setZIndex(div, '100000000'); 1790 allDayParent.appendChild(div); 1791 1792 // Set the opacity on the table that has the gradient coloring; Needed for IE 1793 Dwt.setOpacity(data.tableEl[iAppt], ZmCalColView._OPACITY_APPT_DND); 1794 Dwt.addClass(div, DwtCssStyle.DROPPABLE); 1795 1796 return div; 1797 } 1798 1799 1800 ZmCalMonthView.prototype._reattachApptDnDHtml = 1801 function(data, startIndex, deselect) { 1802 for (var i = 0; i < data.trEl.length; i++) { 1803 var day = this._days[startIndex + i]; 1804 if (data.apptDiv[i]) { 1805 // Detach the Appt DnD Proxy Div from the allDayParent 1806 data.apptDiv[i].parentNode.removeChild(data.apptDiv[i]); 1807 } 1808 1809 if (day && data.trEl[i]) { 1810 // TD that originally contained the appt 1811 var td = data.trEl[i].firstChild; 1812 if (td.saveHTML) { 1813 if (startIndex == data.startDayIndex) { 1814 // Remove the filler 1815 td.removeChild(td.firstChild); 1816 } else { 1817 // Dropped in a new cell - find the correct position within the appts of the current day 1818 var tBody = document.getElementById(day.dayId); 1819 var insertIndex = 0; 1820 for (insertIndex = 0; insertIndex < tBody.childNodes.length; insertIndex++) { 1821 var targetTR = tBody.childNodes[insertIndex]; 1822 if ((targetTR.apptStartTimeOffset !== undefined) && (targetTR.apptStartTimeOffset > data.timeOffset[i])) { 1823 break; 1824 } 1825 } 1826 // Remove the original TR from its day div 1827 if (data.trEl[i].parentNode) { 1828 data.trEl[i].parentNode.removeChild(data.trEl[i]); 1829 } 1830 data.trEl[i].removeChild(td); 1831 1832 // Create a new TR in the new day div 1833 var tr = tBody.insertRow(insertIndex); 1834 tr.appendChild(td); 1835 tr.id = data.trEl[i].id; 1836 tr.className = data.trEl[i].className; 1837 } 1838 // Set the td with the original appt content. Do via innerHTML since IE 1839 // does not handle the gradient coloring properly if the appt's div is simply moved 1840 td.innerHTML = td.saveHTML; 1841 // Hack for IE - it doesn't display the tag and peel unless you alter a containing className. 1842 // The month template div does not have any classNames, so this is safe. 1843 td.firstChild.className = ""; 1844 } 1845 } 1846 } 1847 data.apptDiv = {}; 1848 } 1849 1850 ZmCalMonthView.prototype._removeDnDApptDiv = 1851 function(data) { 1852 if (data.apptDiv) { 1853 for (var iAppt in data.apptDiv) { 1854 data.apptDiv[iAppt].parentNode.removeChild(data.apptDiv[iAppt]); 1855 } 1856 data.apptDiv = null; 1857 } 1858 } 1859 1860 ZmCalMonthView.prototype._restoreApptLoc = 1861 function(data) { 1862 if(data && data.appt) { 1863 if (data.appt.isAllDayEvent()) { 1864 this._moveAllDayAppt(data, data.startDayIndex); 1865 } else { 1866 this._reattachApptDnDHtml(data, data.startDayIndex, false); 1867 } 1868 data.snap.dayIndex = data.startDayIndex; 1869 } 1870 }; 1871 1872 ZmCalMonthView.prototype._deselectDnDHighlight = 1873 function(data) { 1874 if (data.appt.isAllDayEvent()) { 1875 for (var i = 0; i < data.numDays; i++) { 1876 var allDayDiv = data.apptEl || this._getAllDayDiv(data.appt, i); 1877 if (allDayDiv) { 1878 this._highlightAllDayDiv(allDayDiv, data.appt, false); 1879 } 1880 } 1881 } else { 1882 if (data.snap.dayIndex == ZmCalMonthView.OUT_OF_BOUNDS_SNAP) { 1883 for (var i = 0; i < data.trEl.length; i++) { 1884 var day = this._days[data.startDayIndex + i]; 1885 if (day) { 1886 var td = data.trEl[i].firstChild; 1887 // Set the opacity on the table containing the gradient coloring; needed for IE 1888 ZmCalBaseView._setApptOpacity(data.appt, data.tableEl[i]); 1889 } 1890 } 1891 } else { 1892 this._reattachApptDnDHtml(data, data.snap.dayIndex - data.offsetDayIndex, true); 1893 } 1894 } 1895 }; 1896 1897 ZmCalMonthView.prototype._restoreAppt = 1898 function(data) { 1899 if (data.appt.isAllDayEvent()) { 1900 for (var i = 0; i < data.numDays; i++) { 1901 var allDayDiv = data.apptEl || this._getAllDayDiv(data.appt, i); 1902 if (allDayDiv.saveHtml !== undefined) { 1903 allDayDiv.innerHTML = allDayDiv.saveHtml; 1904 allDayDiv.saveHtml = undefined; 1905 } 1906 } 1907 } 1908 }; 1909 1910 ZmCalMonthView.prototype._handleApptScrollRegion = 1911 function(docX, docY, incr, data) { 1912 var offset = 0; 1913 var div = document.getElementById(this._daysId); 1914 var fullDiv = document.getElementById(this._bodyId); 1915 var originPt = Dwt.getLocation(div); 1916 var size = Dwt.getSize(div); 1917 var he = document.getElementById(this._headerId); 1918 var headingHeight = Dwt.getSize(he).y; 1919 var headingBaseY = Dwt.getLocation(he).y; 1920 1921 DBG.println(AjxDebug.DBG3,"_handleApptScrollRegion mouseY: " + docY + " headingHeight:" + headingHeight + 1922 " headingBaseY: " + headingBaseY + " sizeY:" + size.y); 1923 1924 var upper = docY < headingBaseY + headingHeight + 4;; 1925 var lower = docY > originPt.y + size.y - 8; // - 8; 1926 1927 if (upper || lower) { 1928 var sTop = div.scrollTop; 1929 if (upper && sTop > 0) { 1930 DBG.println(AjxDebug.DBG3,"_handleApptScrollRegion sTop: " + sTop); 1931 offset = -(sTop > incr ? incr : sTop); 1932 } else if (lower) { 1933 var fullSize = Dwt.getSize(fullDiv); 1934 var sVisibleTop = fullSize.y - size.y; 1935 DBG.println(AjxDebug.DBG3,"_handleApptScrollRegion sTop: " + sTop + ", sVisibleTop: " + sVisibleTop); 1936 if (sTop < sVisibleTop) { 1937 var spaceLeft = sVisibleTop - sTop; 1938 offset = spaceLeft > incr ?incr : spaceLeft; 1939 DBG.println(AjxDebug.DBG3,"_handleApptScrollRegion spaceLeft: " + spaceLeft); 1940 } 1941 } 1942 if (offset != 0) { 1943 div.scrollTop += offset; 1944 DBG.println(AjxDebug.DBG3,"_handleApptScrollRegion offset: " + offset); 1945 this._containerRect.set(this._containerRect.x, this._containerRect.y - offset); 1946 data.originY -= offset; 1947 //DBG.println(AjxDebug.DBG3,"_handleApptScrollRegion new containerRect.y = " + this._containerRect.y + ", originY = " + data.originY); 1948 } 1949 1950 } 1951 return offset; 1952 }; 1953 1954 ZmCalMonthView.prototype.startIndicatorTimer=function(){ 1955 if(!this._indicatorTimer){ 1956 this._indicatorTimer = this.updateTimeIndicator(); 1957 } 1958 }; 1959 1960 ZmCalMonthView.prototype.updateTimeIndicator=function(){ 1961 // For the monthView, the indicator is the highlighting for the current day 1962 if (this._selectedData) { 1963 var today = new Date(); 1964 today.setHours(0,0,0, 0); 1965 if (this._selectedData.date.getTime() != today.getTime()) { 1966 // Current date has changed 1967 this._date = today; 1968 this._dateUpdate(); 1969 } 1970 } 1971 return this.setTimer(1); 1972 }; 1973