1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 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) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 /****************** OLD VERSION OF SCHEDULE VIEW *********************/ 24 ZmCalScheduleView = function(parent, posStyle, controller, dropTgt) { 25 ZmCalColView.call(this, parent, posStyle, controller, dropTgt, null, 1, true); 26 }; 27 28 ZmCalScheduleView.prototype = new ZmCalColView; 29 ZmCalScheduleView.prototype.constructor = ZmCalScheduleView; 30 31 ZmCalScheduleView.prototype.toString = 32 function() { 33 return "ZmCalScheduleView"; 34 }; 35 36 ZmCalScheduleView.prototype._apptMouseDownAction = 37 function(ev, apptEl) { 38 appt = this.getItemFromElement(apptEl); 39 if (appt.isAllDayEvent()) { 40 return false; 41 } else { 42 return ZmCalBaseView.prototype._apptMouseDownAction.call(this, ev, apptEl, appt); 43 } 44 } 45 46 47 48 49 50 /****************** NEW VERSION OF SCHEDULE VIEW *********************/ 51 ZmCalNewScheduleView = function(parent, posStyle, controller, dropTgt) { 52 ZmCalColView.call(this, parent, posStyle, controller, dropTgt, ZmId.VIEW_CAL_FB, 1, true); 53 var app = appCtxt.getApp(ZmApp.CALENDAR); 54 this._fbCache = new ZmFreeBusyCache(app); 55 }; 56 57 ZmCalNewScheduleView.prototype = new ZmCalColView; 58 ZmCalNewScheduleView.prototype.constructor = ZmCalNewScheduleView; 59 60 ZmCalNewScheduleView.prototype.toString = 61 function() { 62 return "ZmCalNewScheduleView"; 63 }; 64 65 ZmCalNewScheduleView.ATTENDEES_METADATA = 'MD_SCHED_VIEW_ATTENDEES'; 66 67 ZmCalNewScheduleView.prototype.getFreeBusyCache = 68 function() { 69 return this._fbCache; 70 } 71 72 ZmCalNewScheduleView.prototype._createHtml = 73 function(abook) { 74 DBG.println(AjxDebug.DBG2, "ZmCalNewScheduleView in _createHtml!"); 75 //TODO: Check and remove unnecessary instance vars 76 this._days = {}; 77 this._columns = []; 78 this._hours = {}; 79 this._layouts = []; 80 this._allDayAppts = []; 81 this._calendarOwners = {}; 82 83 this._headerYearId = Dwt.getNextId(); 84 this._yearHeadingDivId = Dwt.getNextId(); 85 this._yearAllDayDivId = Dwt.getNextId(); 86 this._leftAllDaySepDivId = Dwt.getNextId(); 87 this._leftApptSepDivId = Dwt.getNextId(); 88 89 this._allDayScrollDivId = Dwt.getNextId(); 90 this._allDayHeadingDivId = Dwt.getNextId(); 91 this._allDayApptScrollDivId = Dwt.getNextId(); 92 this._allDayDivId = Dwt.getNextId(); 93 this._hoursScrollDivId = Dwt.getNextId(); 94 this._bodyHourDivId = Dwt.getNextId(); 95 this._allDaySepDivId = Dwt.getNextId(); 96 this._bodyDivId = Dwt.getNextId(); 97 this._apptBodyDivId = Dwt.getNextId(); 98 this._newApptDivId = Dwt.getNextId(); 99 this._newAllDayApptDivId = Dwt.getNextId(); 100 this._timeSelectionDivId = Dwt.getNextId(); 101 102 103 this._unionHeadingDivId = Dwt.getNextId(); 104 this._unionAllDayDivId = Dwt.getNextId(); 105 this._unionHeadingSepDivId = Dwt.getNextId(); 106 this._unionGridScrollDivId = Dwt.getNextId(); 107 this._unionGridDivId = Dwt.getNextId(); 108 this._unionGridSepDivId = Dwt.getNextId(); 109 this._workingHrsFirstDivId = Dwt.getNextId(); 110 this._workingHrsSecondDivId = Dwt.getNextId(); 111 112 113 this._allDayRows = []; 114 this._attendees = {}; 115 this._attendees[ZmCalBaseItem.PERSON] = {}; 116 this._attendees[ZmCalBaseItem.LOCATION] = {}; 117 this._attendees[ZmCalBaseItem.EQUIPMENT] = {}; 118 119 var html = new AjxBuffer(); 120 html.append("<div id='", this._bodyDivId, "' class=calendar_body style='position:absolute'>"); 121 html.append("<div id='", this._apptBodyDivId, "' style='width:100%;position:absolute;'>","</div>"); 122 html.append("</div>"); 123 this.getHtmlElement().innerHTML = html.toString(); 124 125 }; 126 127 128 ZmCalNewScheduleView.prototype._layout = 129 function(refreshApptLayout) { 130 DBG.println(AjxDebug.DBG2, "ZmCalNewScheduleView in layout!"); 131 132 var sz = this.getSize(); 133 var width = sz.x; 134 var height = sz.y; 135 if (width == 0 || height == 0) { return; } 136 this._setBounds(this._bodyDivId, 0, 0, width, height); 137 this._setBounds(this._apptBodyDivId, 0, 0, width-Dwt.SCROLLBAR_WIDTH, height); 138 //this._layoutAllDayAppts(); 139 140 }; 141 142 ZmCalNewScheduleView.prototype.getCalendarAccount = 143 function() { 144 return null; 145 }; 146 147 //mouse actions removed for now 148 ZmCalNewScheduleView.prototype._apptMouseDownAction = 149 function(ev, apptEl) { 150 DBG.println(AjxDebug.DBG2, "mouse listeners"); 151 }; 152 153 ZmCalNewScheduleView.prototype._doubleClickAction = 154 function(ev, div) { 155 this._mouseDownAction(ev, div, true); 156 }; 157 158 ZmCalNewScheduleView.prototype._mouseDownAction = 159 function(ev, div, isDblClick) { 160 DBG.println(AjxDebug.DBG2, "mouse down action"); 161 var target = DwtUiEvent.getTarget(ev), 162 targetId, 163 tmp, 164 index = {}, 165 apptDate, 166 duration = 30, 167 folderId = null, 168 isAllDay = false; 169 isDblClick = isDblClick || false; 170 if(target && target.className.indexOf("ZmSchedulerGridDiv") != -1) { 171 targetId = target.id; 172 tmp = targetId.split("__"); 173 index.start = tmp[1] - 1; 174 index.end = tmp[1]; 175 176 if(this._scheduleView) { 177 this._scheduleView.setDateBorder(index); 178 this._scheduleView._outlineAppt(); 179 if(!this._date) { 180 this._date = new Date(); 181 } 182 apptDate = new Date(this._date); 183 apptDate.setHours(0, index.end*30, 0); 184 185 this._timeSelectionEvent(apptDate, duration, isDblClick, isAllDay, folderId, ev.shiftKey); 186 } 187 } 188 }; 189 190 ZmCalNewScheduleView.prototype.getOrganizer = 191 function() { 192 var organizer = new ZmContact(null); 193 organizer.initFromEmail(appCtxt.getUsername(), true); 194 return organizer; 195 }; 196 //overridden method - do not remove 197 ZmCalNewScheduleView.prototype.getRsvp = 198 function() { 199 return false; 200 }; 201 //overridden method - do not remove 202 ZmCalNewScheduleView.prototype._scrollToTime = 203 function(hour) { 204 }; 205 206 ZmCalNewScheduleView.prototype.getDateInfo = 207 function(date) { 208 var dateInfo = {}, 209 d = date || new Date(); 210 dateInfo.startDate = AjxDateUtil.simpleComputeDateStr(d); 211 dateInfo.endDate = AjxDateUtil.simpleComputeDateStr(d); 212 dateInfo.timezone = AjxDateFormat.format("z", d); 213 dateInfo.isAllDay = true; 214 return dateInfo; 215 }; 216 217 ZmCalNewScheduleView.prototype._navDateChangeListener = 218 function(date) { 219 this._date = date; 220 this._scheduleView.changeDate(this.getDateInfo(date)); 221 }; 222 //overridden method - do not remove 223 ZmCalNewScheduleView.prototype._dateUpdate = 224 function(rangeChanged) { 225 }; 226 227 ZmCalNewScheduleView.prototype.set = 228 function(list, skipMiniCalUpdate) { 229 this._preSet(); 230 //Check added for sync issue - not sure if schedule view is ready by this time 231 if(!this._scheduleView) { 232 this._calNotRenderedList = list; 233 return; 234 } 235 this.resetListItems(list); 236 this.renderAppts(list); 237 }; 238 239 ZmCalNewScheduleView.prototype.resetListItems = 240 function(list) { 241 this._selectedItems.removeAll(); 242 var newList = list; 243 if (list && (list == this._list)) { 244 newList = list.clone(); 245 } 246 this._resetList(); 247 this._list = newList; 248 }; 249 250 ZmCalNewScheduleView.prototype.renderAppts = 251 function(list) { 252 var timeRange = this.getTimeRange(); 253 if (list) { 254 var size = list.size(); 255 DBG.println(AjxDebug.DBG2,"list.size:"+size); 256 if (size != 0) { 257 var showDeclined = appCtxt.get(ZmSetting.CAL_SHOW_DECLINED_MEETINGS); 258 this._computeApptLayout(); 259 for (var i=0; i < size; i++) { 260 var ao = list.get(i); 261 if (ao && ao.isInRange(timeRange.start, timeRange.end) && 262 (showDeclined || (ao.ptst != ZmCalBaseItem.PSTATUS_DECLINED))) { 263 this.addAppt(ao); 264 } 265 } 266 } 267 } 268 }; 269 270 ZmCalNewScheduleView.prototype.addAppt = 271 function(appt) { 272 if(this._scheduleView) { 273 var item = this._createItemHtml(appt), 274 div = this._getDivForAppt(appt); 275 276 if (div) { 277 div.appendChild(item); 278 } 279 this._scheduleView.colorAppt(appt, item); 280 } 281 }; 282 283 ZmCalNewScheduleView.prototype.removeAppt = 284 function(appt) { 285 if(this._scheduleView) { 286 var itemId = this._getItemId(appt), 287 item = document.getElementById(itemId), 288 div = this._getDivForAppt(appt); 289 290 if (div && item) { 291 div.removeChild(item); 292 } 293 } 294 }; 295 296 ZmCalNewScheduleView.prototype.removeApptByEmail = 297 function(email) { 298 if(this._scheduleView) { 299 for (var i = 0; i<this._list.size(); i++) { 300 var appt = this._list.get(i); 301 if(appt && appt.getFolder().getOwner() == email) { 302 var itemId = this._getItemId(appt), 303 item = document.getElementById(itemId), 304 div = this._getDivForAppt(appt); 305 306 if (div && item) { 307 div.removeChild(item); 308 } 309 } 310 } 311 } 312 }; 313 314 ZmCalNewScheduleView.prototype.refreshAppts = 315 function() { 316 this._selectedItems.removeAll(); 317 var newList = this._list.clone(); 318 this._resetList(); 319 this._list = newList; 320 this.renderAppts(newList); 321 }; 322 323 //overridden method - do not remove 324 ZmCalNewScheduleView.prototype._layoutAllDayAppts = 325 function() { 326 }; 327 328 ZmCalNewScheduleView.prototype.getAtttendees = 329 function() { 330 return this._attendees[ZmCalBaseItem.PERSON].getArray(); 331 }; 332 333 ZmCalNewScheduleView.prototype.getMetadataAttendees = 334 function(organizer) { 335 var md = new ZmMetaData(organizer.getAccount()); 336 var callback = new AjxCallback(this, this.processMetadataAttendees); 337 md.get('MD_SCHED_VIEW_ATTENDEES', null, callback); 338 }; 339 340 ZmCalNewScheduleView.prototype.processMetadataAttendees = 341 function(metadataResponse) { 342 var objAttendees = metadataResponse.getResponse().BatchResponse.GetMailboxMetadataResponse[0].meta[0]._attrs, 343 emails = [], 344 email, 345 acct, 346 i; 347 348 for (email in objAttendees) { 349 if(email && objAttendees[email]) { 350 emails.push(objAttendees[email]); 351 } 352 } 353 this._mdAttendees = AjxVector.fromArray(emails); 354 for (i=0; i<this._mdAttendees.size(); i++) { 355 acct = ZmApptViewHelper.getAttendeeFromItem(this._mdAttendees.get(i), ZmCalBaseItem.PERSON); 356 this._attendees[ZmCalBaseItem.PERSON].add(acct, null, true); 357 } 358 359 AjxDispatcher.require(["MailCore", "CalendarCore", "Calendar", "CalendarAppt"]); 360 this._scheduleView = new ZmFreeBusySchedulerView(this, this._attendees, this._controller, this.getDateInfo()); 361 this._scheduleView.setComposeMode(false); 362 this._scheduleView.setVisible(true); 363 this._scheduleView.showMe(); 364 this._scheduleView.reparentHtmlElement(this._apptBodyDivId); 365 366 //Called to handle the sync issue 367 this.resetListItems(this._calNotRenderedList); 368 this.renderAppts(this._calNotRenderedList); 369 delete this._calNotRenderedList; 370 }; 371 372 ZmCalNewScheduleView.prototype.setMetadataAttendees = 373 function(organizer, email) { 374 if(!organizer) { 375 organizer = this.getOrganizer(); 376 } 377 if (email instanceof Array) { 378 email = email.join(','); 379 } 380 var md = new ZmMetaData(organizer.getAccount()); 381 this._mdAttendees.add(email, null, true); 382 return md.set(ZmCalNewScheduleView.ATTENDEES_METADATA, this._mdAttendees.getArray()); 383 }; 384 385 ZmCalNewScheduleView.prototype.removeMetadataAttendees = 386 function(organizer, email) { 387 if(!organizer) { 388 organizer = this.getOrganizer(); 389 } 390 if (email instanceof Array) { 391 email = email.join(','); 392 } 393 var md = new ZmMetaData(organizer.getAccount()); 394 this._mdAttendees.remove(email, null, true); 395 return md.set(ZmCalNewScheduleView.ATTENDEES_METADATA, this._mdAttendees.getArray()); 396 }; 397 398 ZmCalNewScheduleView.prototype._resetCalendarData = 399 function() { 400 var i, 401 tb, 402 acct, 403 acctEmail, 404 strAttendees, 405 mdAttendees, 406 organizer = this.getOrganizer(); 407 this._calendars = this._controller.getCheckedCalendars(); 408 this._calendars.sort(ZmFolder.sortCompareNonMail); 409 this._folderIdToColIndex = {}; 410 this._columns = []; 411 this._numCalendars = this._calendars.length; 412 this._attendees[ZmCalBaseItem.PERSON] = new AjxVector(); 413 414 for (i=0; i<this._numCalendars; i++) { 415 acctEmail = this._calendars[i].getOwner(); 416 if(organizer.getEmail() != acctEmail) { 417 //if not organizer add to the attendee list 418 acct = ZmApptViewHelper.getAttendeeFromItem(acctEmail, ZmCalBaseItem.PERSON); 419 this._attendees[ZmCalBaseItem.PERSON].add(acct, null, true); 420 } 421 } 422 423 if(this._scheduleView) { 424 //this._attendees[ZmCalBaseItem.PERSON] = this._scheduleView.getAttendees(); 425 426 for (i=0; i<this._mdAttendees.size(); i++) { 427 acct = ZmApptViewHelper.getAttendeeFromItem(this._mdAttendees.get(i), ZmCalBaseItem.PERSON); 428 this._attendees[ZmCalBaseItem.PERSON].add(acct, null, true); 429 } 430 431 this._scheduleView.cleanup(); 432 this._scheduleView.setComposeMode(false); 433 this._scheduleView.set(this.getDate(), organizer, this._attendees); 434 this._scheduleView.enablePartcipantStatusColumn(true); 435 } 436 else { 437 this._mdAttendees = new AjxVector(); 438 this.getMetadataAttendees(organizer); 439 } 440 };