1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 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) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 /** 24 * Appointment list view. 25 */ 26 ZmApptListView = function(parent, posStyle, controller, dropTgt) { 27 if (arguments.length == 0) return; 28 var params = Dwt.getParams(arguments, ZmApptListView.PARAMS); 29 params.headerList = this._getHeaderList(); 30 params.view = params.view || ZmId.VIEW_CAL_TRASH; 31 ZmListView.call(this, params); 32 this._bSortAsc = true; 33 this._defaultSortField = ZmItem.F_DATE; 34 this.setDragSource(params.controller._dragSrc); 35 }; 36 ZmApptListView.prototype = new ZmListView; 37 ZmApptListView.prototype.constructor = ZmApptListView; 38 39 ZmApptListView.prototype.toString = function() { 40 return "ZmApptListView"; 41 }; 42 43 ZmApptListView.PARAMS = ["parent","posStyle","controller","dropTgt"]; 44 45 // 46 // Constants 47 // 48 49 ZmApptListView.COL_WIDTH_DATE = ZmMsg.COLUMN_WIDTH_DATE_CAL; 50 ZmApptListView.COL_WIDTH_LOCATION = ZmMsg.COLUMN_WIDTH_LOCATION_CAL; 51 ZmApptListView.COL_WIDTH_STATUS = ZmMsg.COLUMN_WIDTH_STATUS_CAL; 52 ZmApptListView.COL_WIDTH_FOLDER = ZmMsg.COLUMN_WIDTH_FOLDER_CAL; 53 54 // 55 // Public methods 56 // 57 58 ZmApptListView.prototype.getApptList = function() { 59 return this._apptList; 60 }; 61 62 ZmApptListView.prototype.refresh = function() { 63 if (this.needsRefresh()) { 64 var selection = this.getSelection(); 65 this.set(this.getApptList()); 66 if (selection) { 67 this.setSelectedItems(selection); 68 } 69 this.setNeedsRefresh(false); 70 } 71 }; 72 73 ZmApptListView.prototype.needsRefresh = function() { 74 var controller = this._controller; 75 return controller.getCurrentView().needsRefresh(); 76 }; 77 78 ZmApptListView.prototype.setNeedsRefresh = function(needsRefresh) { 79 var controller = this._controller; 80 if(controller.getCurrentView().setNeedsRefresh){ 81 return controller.getCurrentView().setNeedsRefresh(needsRefresh); 82 } 83 return null; 84 }; 85 86 //to override 87 ZmApptListView.prototype.getAtttendees = function() { 88 return null; 89 }; 90 91 ZmApptListView.prototype.updateTimeIndicator=function(force){ 92 //override 93 }; 94 95 ZmApptListView.prototype.startIndicatorTimer=function(force){ 96 //override 97 }; 98 99 ZmApptListView.prototype.checkIndicatorNeed=function(viewId,startDate){ 100 //override 101 }; 102 103 // 104 // Protected methods 105 // 106 107 ZmApptListView.prototype._getToolTip = 108 function(params) { 109 var tooltip, field = params.field, item = params.item; 110 if (field && (field == ZmItem.F_SELECTION || field == ZmItem.F_TAG)) { 111 tooltip = ZmListView.prototype._getToolTip.apply(this, arguments); 112 } else if (item.getToolTip) { 113 tooltip = item.getToolTip(this._controller); 114 } 115 return tooltip; 116 }; 117 118 ZmApptListView.prototype._sortList = function(list, column) { 119 ZmApptListView.sortByAsc = this._bSortAsc; 120 121 switch (column) { 122 case ZmItem.F_SUBJECT: list.sort(ZmApptListView._sortSubject); break; 123 case ZmItem.F_STATUS: list.sort(ZmApptListView._sortStatus); break; 124 case ZmItem.F_FOLDER: list.sort(ZmApptListView._sortFolder); break; 125 case ZmItem.F_DATE: list.sort(ZmApptListView._sortDate); break; 126 } 127 }; 128 129 ZmApptListView.prototype._sortColumn = function(columnItem, bSortAsc) { 130 this._defaultSortField = columnItem._field; 131 132 var list = this.getList(); 133 list = list && list.clone(); 134 if (list) { 135 this._sortList(list, columnItem._field); 136 this.set(list, null, true); 137 } 138 }; 139 140 ZmApptListView.prototype._getHeaderToolTip = function(field, itemIdx) { 141 switch (field) { 142 case ZmItem.F_LOCATION: return ZmMsg.location; 143 case ZmItem.F_FOLDER: return ZmMsg.calendar; 144 case ZmItem.F_DATE: return ZmMsg.date; 145 case ZmItem.F_RECURRENCE:return ZmMsg.recurrence; 146 } 147 return ZmListView.prototype._getHeaderToolTip.call(this, field, itemIdx); 148 }; 149 150 ZmApptListView.prototype._getHeaderList = function() { 151 var hList = []; 152 153 if (appCtxt.get(ZmSetting.SHOW_SELECTION_CHECKBOX)) { 154 hList.push(new DwtListHeaderItem({field:ZmItem.F_SELECTION, icon:"CheckboxUnchecked", width:ZmListView.COL_WIDTH_ICON, name:ZmMsg.selection})); 155 } 156 if (appCtxt.get(ZmSetting.TAGGING_ENABLED)) { 157 hList.push(new DwtListHeaderItem({field:ZmItem.F_TAG, icon:"Tag", width:ZmListView.COL_WIDTH_ICON, name:ZmMsg.tag})); 158 } 159 hList.push(new DwtListHeaderItem({field:ZmItem.F_ATTACHMENT, icon:"Attachment", width:ZmListView.COL_WIDTH_ICON, name:ZmMsg.attachment})); 160 hList.push(new DwtListHeaderItem({field:ZmItem.F_SUBJECT, text:ZmMsg.subject, noRemove:true, sortable:ZmItem.F_SUBJECT})); 161 hList.push(new DwtListHeaderItem({field:ZmItem.F_LOCATION, text:ZmMsg.location, width:ZmApptListView.COL_WIDTH_LOCATION, resizeable:true})); 162 hList.push(new DwtListHeaderItem({field:ZmItem.F_STATUS, text:ZmMsg.status, width:ZmApptListView.COL_WIDTH_STATUS, resizeable:true, sortable:ZmItem.F_STATUS})); 163 hList.push(new DwtListHeaderItem({field:ZmItem.F_FOLDER, text:ZmMsg.calendar, width:ZmApptListView.COL_WIDTH_FOLDER, resizeable:true, sortable:ZmItem.F_FOLDER})); 164 hList.push(new DwtListHeaderItem({field:ZmItem.F_RECURRENCE, icon:"ApptRecur", width:ZmListView.COL_WIDTH_ICON, name:ZmMsg.recurrence})); 165 hList.push(new DwtListHeaderItem({field:ZmItem.F_DATE, text:ZmMsg.startDate, width:ZmApptListView.COL_WIDTH_DATE, sortable:ZmItem.F_DATE})); 166 167 return hList; 168 }; 169 170 // 171 // DwtListView methods 172 // 173 174 ZmApptListView.prototype._itemClicked = function() { 175 ZmListView.prototype._itemClicked.apply(this, arguments); 176 this._controller.setCurrentListView(this); 177 }; 178 179 ZmApptListView.prototype.set = function(apptList, skipMiniCalUpdate, skipSort) { 180 this._apptList = apptList; 181 if (!skipSort) { 182 if ((this._defaultSortField != ZmItem.F_DATE) || 183 (this._defaultSortField == ZmItem.F_DATE && !this._bSortAsc)) 184 { 185 this._sortList(apptList, this._defaultSortField); 186 } 187 } 188 ZmListView.prototype.set.call(this, apptList, this._defaultSortField); 189 this._resetColWidth(); 190 //Does not make sense but required to make the scrollbar appear 191 var size = this.getSize(); 192 this._listDiv.style.height = (size.y - DwtListView.HEADERITEM_HEIGHT)+"px"; 193 }; 194 195 ZmApptListView.prototype._getItemId = function(item) { 196 var itemId = (item && item.id) ? item.getUniqueId(true) : Dwt.getNextId(); 197 return DwtId.getListViewItemId(DwtId.WIDGET_ITEM, this._view, itemId); 198 }; 199 200 ZmApptListView.prototype._getFieldId = function(item, field) { 201 var itemId = (item && item.getUniqueId) ? item.getUniqueId(true) : item.id; 202 return DwtId.getListViewItemId(DwtId.WIDGET_ITEM_FIELD, this._view, itemId, field); 203 }; 204 205 ZmApptListView.prototype._getCellId = function(item, field) { 206 if (field == ZmItem.F_SUBJECT || field == ZmItem.F_DATE || field == ZmItem.F_LOCATION || field == ZmItem.F_STATUS || field == ZmItem.F_FOLDER) { 207 return this._getFieldId(item, field); 208 } 209 }; 210 211 ZmApptListView.prototype._getCellContents = function(htmlArr, idx, appt, field, colIdx, params) { 212 if (field == ZmItem.F_RECURRENCE) { 213 var icon; 214 if (appt.isException) { 215 icon = "ApptExceptionIndicator"; 216 } 217 else if (appt.isRecurring()) { 218 icon = "ApptRecur"; 219 } 220 idx = this._getImageHtml(htmlArr, idx, icon, this._getFieldId(appt, field)); 221 222 } 223 else if (field == ZmItem.F_SUBJECT) { 224 htmlArr[idx++] = AjxStringUtil.htmlEncode(appt.getName(), true); 225 if (appCtxt.get(ZmSetting.SHOW_FRAGMENTS) && appt.fragment) { 226 htmlArr[idx++] = this._getFragmentSpan(appt); 227 } 228 229 } 230 else if (field == ZmItem.F_LOCATION) { 231 htmlArr[idx++] = AjxStringUtil.htmlEncode(appt.getLocation(), true); 232 233 } 234 else if (field == ZmItem.F_STATUS) { 235 if (appt.otherAttendees) { 236 htmlArr[idx++] = appt.getParticipantStatusStr(); 237 } 238 239 } 240 else if (field == ZmItem.F_FOLDER) { 241 var calendar = appt.getFolder(); 242 var rgb = calendar.rgb || ZmOrganizer.COLOR_VALUES[calendar.color||ZmOrganizer.DEFAULT_COLOR[ZmOrganizer.CALENDAR]]; 243 var colors = ZmCalBaseView._getColors(rgb); 244 var subs = { 245 folder: calendar, 246 folderColor: colors.standard.header.bgcolor, 247 folderName: calendar.getName(), 248 id: Dwt.getNextId() 249 }; 250 htmlArr[idx++] = AjxTemplate.expand("calendar.Calendar#ListViewFolder", subs); 251 252 } 253 else if (field == ZmItem.F_DATE) { 254 htmlArr[idx++] = (appt.isAllDayEvent()) 255 ? AjxMessageFormat.format(ZmMsg.apptDateTimeAllDay, [appt.startDate]) 256 : AjxMessageFormat.format(ZmMsg.apptDateTime, [appt.startDate, appt.startDate]); 257 258 } 259 else { 260 idx = ZmListView.prototype._getCellContents.apply(this, arguments); 261 } 262 263 return idx; 264 }; 265 266 ZmApptListView.prototype._getLabelForField = 267 function(appt, field) { 268 switch (field) { 269 case ZmItem.F_RECURRENCE: 270 if (appt.isException) { 271 return ZmMsg.recurrenceException; 272 } else if (appt.isRecurring()) { 273 return ZmMsg.recurrence; 274 } else { 275 return ''; 276 } 277 278 case ZmItem.F_SUBJECT: 279 return appt.getName() || ZmMsg.noSubject; 280 281 case ZmItem.F_LOCATION: 282 return appt.location || ZmMsg.noLocation; 283 284 case ZmItem.F_STATUS: 285 return appt.otherAttendees && appt.getParticipantStatusStr(); 286 287 case ZmItem.F_FOLDER: 288 return appt.getFolder().getName(); 289 290 case ZmItem.F_ATTACHMENT: 291 return appt.hasAttach && ZmMsg.hasAttachment; 292 293 case ZmItem.F_TAG: 294 if (appt.tags.length > 0) { 295 var tags = appt.tags.join(' & '); 296 return AjxMessageFormat.format(ZmMsg.taggedAs, [tags]); 297 } 298 299 break; 300 301 case ZmItem.F_DATE: 302 if (appt.isAllDayEvent()) { 303 return AjxMessageFormat.format(ZmMsg.apptDateTimeAllDay, 304 [appt.startDate]); 305 } else { 306 return AjxMessageFormat.format(ZmMsg.apptDateTime, 307 [appt.startDate, appt.startDate]); 308 } 309 } 310 311 return ZmListView.prototype._getLabelForField.apply(this, arguments); 312 }; 313 314 // 315 // Private methods 316 // 317 318 ZmApptListView._sortSubject = function(a, b) { 319 // Bug fix # 80458 - Convert the subject line to lower case and compare 320 var aVal = a.getName().toLowerCase(); 321 var bVal = b.getName().toLowerCase(); 322 323 if (aVal < bVal) { return ZmApptListView.sortByAsc ? -1 : 1; } 324 else if (aVal > bVal) { return ZmApptListView.sortByAsc ? 1 : -1; } 325 else { return 0; } 326 }; 327 328 ZmApptListView._sortStatus = function(a, b) { 329 if (!a.otherAttendees) { return ZmApptListView.sortByAsc ? -1 : 1; } 330 if (!b.otherAttendees) { return ZmApptListView.sortByAsc ? 1 : -1; } 331 332 var aVal = a.getParticipantStatusStr(); 333 var bVal = b.getParticipantStatusStr(); 334 335 if (aVal < bVal) { return ZmApptListView.sortByAsc ? -1 : 1; } 336 else if (aVal > bVal) { return ZmApptListView.sortByAsc ? 1 : -1; } 337 else { return 0; } 338 }; 339 340 ZmApptListView._sortFolder = function(a, b) { 341 var aVal = a.getFolder().getName(); 342 var bVal = b.getFolder().getName(); 343 344 if (aVal < bVal) { return ZmApptListView.sortByAsc ? -1 : 1; } 345 else if (aVal > bVal) { return ZmApptListView.sortByAsc ? 1 : -1; } 346 else { return 0; } 347 }; 348 349 ZmApptListView._sortDate = function(a, b) { 350 var aVal = a.startDate.getTime(); 351 var bVal = b.startDate.getTime(); 352 353 if (aVal < bVal) { return ZmApptListView.sortByAsc ? -1 : 1; } 354 else if (aVal > bVal) { return ZmApptListView.sortByAsc ? 1 : -1; } 355 else { return 0; } 356 }; 357