1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 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) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * @overview 26 * This file contains the task list controller class. 27 */ 28 29 /** 30 * Creates the task list controller. 31 * @class 32 * This class represents the task list controller. 33 * 34 * @param {DwtControl} container the containing shell 35 * @param {ZmApp} app the containing application 36 * @param {constant} type type of controller 37 * @param {string} sessionId the session id 38 * @param {ZmSearchResultsController} searchResultsController containing controller 39 * 40 * @extends ZmListController 41 */ 42 ZmTaskListController = function(container, app, type, sessionId, searchResultsController) { 43 44 ZmListController.apply(this, arguments); 45 46 if (this.supportsDnD()) { 47 this._dragSrc = new DwtDragSource(Dwt.DND_DROP_MOVE); 48 this._dragSrc.addDragListener(this._dragListener.bind(this)); 49 } 50 51 this._listeners[ZmOperation.EDIT] = this._editListener.bind(this); 52 this._listeners[ZmOperation.PRINT_TASK] = this._printTaskListener.bind(this); 53 this._listeners[ZmOperation.PRINT_TASKFOLDER] = this._printTaskFolderListener.bind(this); 54 this._listeners[ZmOperation.SHOW_ORIG] = this._showOrigListener.bind(this); 55 this._listeners[ZmOperation.MARK_AS_COMPLETED] = this._markAsCompletedListener.bind(this); 56 this._listeners[ZmOperation.DELETE] = this._deleteListener.bind(this); 57 58 this._listeners[ZmOperation.PRINT] = null; // override base class to do nothing 59 60 var pref = appCtxt.get(ZmSetting.TASKS_FILTERBY); 61 this._currentTaskView = ZmTaskListController.FILTERBY_SETTING_ID[pref]; 62 }; 63 64 ZmTaskListController.prototype = new ZmListController; 65 ZmTaskListController.prototype.constructor = ZmTaskListController; 66 67 ZmTaskListController.prototype.isZmTaskListController = true; 68 ZmTaskListController.prototype.toString = function() { return "ZmTaskListController"; }; 69 70 // Consts 71 ZmTaskListController.SORT_BY = [ 72 ZmId.VIEW_TASK_NOT_STARTED, 73 ZmId.VIEW_TASK_COMPLETED, 74 ZmId.VIEW_TASK_IN_PROGRESS, 75 ZmId.VIEW_TASK_WAITING, 76 ZmId.VIEW_TASK_DEFERRED, 77 ZmId.VIEW_TASK_ALL, 78 ZmId.VIEW_TASK_TODO 79 ]; 80 81 ZmTaskListController.ICON = {}; 82 ZmTaskListController.ICON[ZmId.VIEW_TASK_NOT_STARTED] = "TaskViewNotStarted"; 83 ZmTaskListController.ICON[ZmId.VIEW_TASK_COMPLETED] = "TaskViewCompleted"; 84 ZmTaskListController.ICON[ZmId.VIEW_TASK_IN_PROGRESS] = "TaskViewInProgress"; 85 ZmTaskListController.ICON[ZmId.VIEW_TASK_WAITING] = "TaskViewWaiting"; 86 ZmTaskListController.ICON[ZmId.VIEW_TASK_DEFERRED] = "TaskViewDeferred"; 87 ZmTaskListController.ICON[ZmId.VIEW_TASK_ALL] = "TaskList"; 88 ZmTaskListController.ICON[ZmId.VIEW_TASK_TODO] = "TaskViewTodoList"; 89 90 ZmTaskListController.MSG_KEY = {}; 91 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_NOT_STARTED] = "notStarted"; 92 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_COMPLETED] = "completed"; 93 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_IN_PROGRESS] = "inProgress"; 94 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_WAITING] = "waitingOn"; 95 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_DEFERRED] = "deferred"; 96 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_ALL] = "all"; 97 ZmTaskListController.MSG_KEY[ZmId.VIEW_TASK_TODO] = "todoList"; 98 99 ZmTaskListController.FILTERBY_SETTING = {}; 100 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_NOT_STARTED] = ZmSetting.TASK_FILTER_NOTSTARTED; 101 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_COMPLETED] = ZmSetting.TASK_FILTER_COMPLETED; 102 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_IN_PROGRESS] = ZmSetting.TASK_FILTER_INPROGRESS; 103 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_WAITING] = ZmSetting.TASK_FILTER_WAITING; 104 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_DEFERRED] = ZmSetting.TASK_FILTER_DEFERRED; 105 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_ALL] = ZmSetting.TASK_FILTER_ALL; 106 ZmTaskListController.FILTERBY_SETTING[ZmId.VIEW_TASK_TODO] = ZmSetting.TASK_FILTER_TODO; 107 108 ZmTaskListController.FILTERBY_SETTING_ID = {}; 109 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_NOTSTARTED] = ZmId.VIEW_TASK_NOT_STARTED; 110 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_COMPLETED] = ZmId.VIEW_TASK_COMPLETED; 111 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_INPROGRESS] = ZmId.VIEW_TASK_IN_PROGRESS; 112 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_WAITING] = ZmId.VIEW_TASK_WAITING; 113 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_DEFERRED] = ZmId.VIEW_TASK_DEFERRED; 114 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_ALL] = ZmId.VIEW_TASK_ALL; 115 ZmTaskListController.FILTERBY_SETTING_ID[ZmSetting.TASK_FILTER_TODO] = ZmId.VIEW_TASK_TODO; 116 117 /** 118 * Defines the status. 119 */ 120 ZmTaskListController.SOAP_STATUS = {}; 121 ZmTaskListController.SOAP_STATUS[ZmId.VIEW_TASK_NOT_STARTED]= "NEED"; 122 ZmTaskListController.SOAP_STATUS[ZmId.VIEW_TASK_COMPLETED] = "COMP"; 123 ZmTaskListController.SOAP_STATUS[ZmId.VIEW_TASK_IN_PROGRESS]= "INPR"; 124 ZmTaskListController.SOAP_STATUS[ZmId.VIEW_TASK_WAITING] = "WAITING"; 125 ZmTaskListController.SOAP_STATUS[ZmId.VIEW_TASK_DEFERRED] = "DEFERRED"; 126 ZmTaskListController.SOAP_STATUS[ZmId.VIEW_TASK_TODO] = "NEED,INPR,WAITING"; 127 128 129 // reading pane options 130 ZmTaskListController.READING_PANE_TEXT = {}; 131 ZmTaskListController.READING_PANE_TEXT[ZmSetting.RP_OFF] = ZmMsg.readingPaneOff; 132 ZmTaskListController.READING_PANE_TEXT[ZmSetting.RP_BOTTOM] = ZmMsg.readingPaneAtBottom; 133 ZmTaskListController.READING_PANE_TEXT[ZmSetting.RP_RIGHT] = ZmMsg.readingPaneOnRight; 134 135 // convert key mapping to view menu item 136 ZmTaskListController.ACTION_CODE_TO_MENU_ID = {}; 137 ZmTaskListController.ACTION_CODE_TO_MENU_ID[ZmKeyMap.READING_PANE_OFF] = ZmSetting.RP_OFF; 138 ZmTaskListController.ACTION_CODE_TO_MENU_ID[ZmKeyMap.READING_PANE_BOTTOM] = ZmSetting.RP_BOTTOM; 139 ZmTaskListController.ACTION_CODE_TO_MENU_ID[ZmKeyMap.READING_PANE_RIGHT] = ZmSetting.RP_RIGHT; 140 141 ZmTaskListController.READING_PANE_ICON = {}; 142 ZmTaskListController.READING_PANE_ICON[ZmSetting.RP_OFF] = "SplitPaneOff"; 143 ZmTaskListController.READING_PANE_ICON[ZmSetting.RP_BOTTOM] = "SplitPane"; 144 ZmTaskListController.READING_PANE_ICON[ZmSetting.RP_RIGHT] = "SplitPaneVertical"; 145 146 ZmTaskListController.RP_IDS = [ZmSetting.RP_BOTTOM, ZmSetting.RP_RIGHT, ZmSetting.RP_OFF]; 147 148 // Public methods 149 150 ZmTaskListController.prototype.show = 151 function(results, folderId) { 152 153 this._folderId = folderId; 154 155 this.setList(results.getResults(ZmItem.TASK)); 156 157 // XXX: WHY? 158 // find out if we just searched for a shared tasks folder 159 var folder = appCtxt.getById(folderId); 160 this._list._isShared = folder ? folder.link : false; 161 this._list.setHasMore(results.getAttribute("more")); 162 163 ZmListController.prototype.show.call(this, results); 164 165 if (this._taskMultiView) { 166 var tlv = this._taskMultiView._taskListView; 167 tlv._saveState({selection:true}); 168 tlv.reset(); 169 } 170 //Generate view Id again as loading the read only view changes the viewId of the TaskListView 171 var viewId = [this.getCurrentViewType(), this.getSessionId()].join(ZmController.SESSION_ID_SEP); 172 173 this._setup(viewId); 174 175 // reset offset if list view has been created 176 var lv = this.getListView(); 177 if (lv) { lv.offset = 0; } 178 179 var elements = this.getViewElements(viewId, this._taskMultiView); 180 181 this._setView({ view: viewId, 182 viewType: this._currentViewType, 183 noPush: this.isSearchResults, 184 elements: elements, 185 isAppView: true}); 186 if (this.isSearchResults) { 187 // if we are switching views, make sure app view mgr is up to date on search view's components 188 appCtxt.getAppViewMgr().setViewComponents(this.searchResultsController.getCurrentViewId(), elements, true); 189 } 190 191 this._setTabGroup(this._tabGroups[viewId]); 192 this._resetNavToolBarButtons(viewId); 193 194 // do this last 195 if (!this._taskTreeController) { 196 this._taskTreeController = appCtxt.getOverviewController().getTreeController(ZmOrganizer.TASKS); 197 DBG.timePt("getting tree controller", true); 198 } 199 200 var origin = results && results.search && results.search.origin; 201 this.getListView().setTaskInputVisible((folderId != ZmOrganizer.ID_TRASH) && (origin !== "Search") && (origin !== "SearchResults")); 202 }; 203 204 ZmTaskListController.prototype.getCurrentView = 205 function() { 206 return this._taskMultiView; 207 }; 208 209 ZmTaskListController.prototype.getListView = 210 function() { 211 return this._taskListView; 212 }; 213 214 ZmTaskListController.prototype._getDefaultFocusItem = 215 function() { 216 return this.getListView(); 217 }; 218 219 /** 220 * Switches the view. 221 * 222 * @param {DwtComposite} view the view 223 */ 224 ZmTaskListController.prototype.switchView = 225 function(view) { 226 if (this._currentTaskView == view) { return; } 227 this._currentTaskView = view; 228 if (view == ZmSetting.RP_OFF || view == ZmSetting.RP_BOTTOM || view == ZmSetting.RP_RIGHT) { 229 this._taskListView._colHeaderActionMenu = null; 230 if (view != this._getReadingPanePref()) { 231 this._setReadingPanePref(view); 232 this._taskMultiView.setReadingPane(); 233 } 234 // always reset the view menu button icon to reflect the current view 235 var btn = this._toolbar[this._currentViewId].getButton(ZmOperation.VIEW_MENU); 236 btn.setImage(ZmTaskListController.READING_PANE_ICON[view]); 237 } else { 238 if(view != this._getFilterByPref() && !appCtxt.isExternalAccount()) { 239 this._setFilterByPref(ZmTaskListController.FILTERBY_SETTING[view]); 240 } 241 } 242 var sc = appCtxt.getSearchController(); 243 var soapStatus = ZmTaskListController.SOAP_STATUS[view]; 244 var currentSearch = appCtxt.getCurrentSearch(); 245 if (currentSearch) sc.redoSearch(currentSearch, false, {allowableTaskStatus:soapStatus}); 246 }; 247 248 /** 249 * Gets the task status. 250 * 251 * @return {constant} the status (see {@link ZmTaskListController.SOAP_STATUS}) 252 */ 253 ZmTaskListController.prototype.getAllowableTaskStatus = 254 function() { 255 var prefFilter = this._getFilterByPref(); 256 var id = ZmTaskListController.FILTERBY_SETTING_ID[prefFilter]; 257 return ZmTaskListController.SOAP_STATUS[id]; 258 }; 259 260 ZmTaskListController.prototype._updateViewMenu = 261 function(id) { 262 var viewBtn = this._toolbar[this._currentViewId].getButton(ZmOperation.VIEW_MENU); 263 var menu = viewBtn && viewBtn.getMenu(); 264 if (menu) { 265 var mi = menu.getItemById(ZmOperation.MENUITEM_ID, id); 266 if (mi) { 267 mi.setChecked(true, true); 268 } 269 } 270 }; 271 272 ZmTaskListController.prototype.getKeyMapName = 273 function() { 274 return ZmKeyMap.MAP_TASKS; 275 }; 276 277 ZmTaskListController.prototype.handleKeyAction = 278 function(actionCode) { 279 DBG.println(AjxDebug.DBG3, "ZmTaskListController.handleKeyAction"); 280 281 var lv = this._listView[this._currentViewId]; 282 var num = lv.getSelectionCount(); 283 var isExternalAccount = appCtxt.isExternalAccount(); 284 285 switch(actionCode) { 286 287 case ZmKeyMap.MARK_COMPLETE: 288 case ZmKeyMap.MARK_UNCOMPLETE: 289 if (isExternalAccount) { break; } 290 var task = this._listView[this._currentViewId].getSelection()[0]; 291 if ((task.isComplete() && actionCode == ZmKeyMap.MARK_UNCOMPLETE) || 292 (!task.isComplete() && actionCode == ZmKeyMap.MARK_COMPLETE)) 293 { 294 this._doCheckCompleted(task); 295 } 296 break; 297 298 case ZmKeyMap.READING_PANE_BOTTOM: 299 case ZmKeyMap.READING_PANE_RIGHT: 300 case ZmKeyMap.READING_PANE_OFF: 301 var menuId = ZmTaskListController.ACTION_CODE_TO_MENU_ID[actionCode]; 302 this._updateViewMenu(menuId); 303 this.switchView(menuId); 304 break; 305 case ZmKeyMap.MOVE_TO_TRASH: 306 if (isExternalAccount) { break; } 307 if(num) { 308 var tasks = lv.getSelection(); 309 var nId = ZmOrganizer.normalizeId(tasks[0].folderId); 310 var isTrash = nId == ZmOrganizer.ID_TRASH; 311 if(!isTrash){ 312 this._handleCancel(tasks); 313 } 314 } 315 break; 316 317 case ZmKeyMap.CANCEL: 318 if (lv && lv.isZmTaskView) { 319 lv.close(); 320 break; 321 } 322 default: 323 return ZmListController.prototype.handleKeyAction.call(this, actionCode); 324 } 325 326 return true; 327 }; 328 329 ZmTaskListController.prototype.mapSupported = 330 function(map) { 331 return (map == "list"); 332 }; 333 334 // override if reading pane is supported 335 ZmTaskListController.prototype._setupReadingPaneMenuItems = function() {}; 336 337 /** 338 * Checks if the reading pane is "on". 339 * 340 * @return {Boolean} <code>true</code> if the reading pane is "on" 341 */ 342 ZmTaskListController.prototype.isReadingPaneOn = 343 function() { 344 return (this._getReadingPanePref() != ZmSetting.RP_OFF); 345 }; 346 347 /** 348 * Checks if the reading pane is "on" right. 349 * 350 * @return {Boolean} <code>true</code> if the reading pane is "on" right. 351 */ 352 ZmTaskListController.prototype.isReadingPaneOnRight = 353 function() { 354 return (this._getReadingPanePref() == ZmSetting.RP_RIGHT); 355 }; 356 357 ZmTaskListController.prototype._getReadingPanePref = 358 function() { 359 return (this._readingPaneLoc || appCtxt.get(ZmSetting.READING_PANE_LOCATION_TASKS)); 360 }; 361 362 ZmTaskListController.prototype._setReadingPanePref = 363 function(value) { 364 if (this.isSearchResults || appCtxt.isExternalAccount()) { 365 this._readingPaneLoc = value; 366 } 367 else { 368 appCtxt.set(ZmSetting.READING_PANE_LOCATION_TASKS, value); 369 } 370 }; 371 372 ZmTaskListController.prototype._getFilterByPref = 373 function() { 374 return appCtxt.get(ZmSetting.TASKS_FILTERBY); 375 }; 376 377 ZmTaskListController.prototype._setFilterByPref = 378 function(value) { 379 appCtxt.set(ZmSetting.TASKS_FILTERBY, value); 380 }; 381 382 /** 383 * Saves the task. 384 * 385 * @param {String} name the task name 386 * @param {AjxCallback} callback the save callback 387 * 388 * @see ZmTask 389 */ 390 ZmTaskListController.prototype.quickSave = 391 function(name, callback, errCallback) { 392 var folderId = (this._activeSearch && this._activeSearch.search) ? this._activeSearch.search.folderId : null; 393 394 var folder = appCtxt.getById(folderId); 395 if (folder && folder.link) { 396 folderId = folder.getRemoteId(); 397 } 398 399 var task = new ZmTask(this._list, null, folderId); 400 401 if (folder && folder.link) { 402 // A share may not be direct - it may be via the root for a full mailbox share 403 while (folder && !folder.owner) { 404 folder = folder.parent; 405 } 406 task.setOrganizer(folder.owner); 407 task._orig = new ZmTask(this._list); 408 } 409 410 task.setName(name); 411 task.setViewMode(ZmCalItem.MODE_NEW); 412 task.location = ""; 413 task.setAllDayEvent(true); 414 415 task.save(null, callback, errCallback); 416 }; 417 418 ZmTaskListController.getDefaultViewType = 419 function() { 420 return ZmId.VIEW_TASKLIST; 421 }; 422 ZmTaskListController.prototype.getDefaultViewType = ZmTaskListController.getDefaultViewType; 423 424 ZmTaskListController.prototype._createNewView = 425 function() { 426 427 if (this._taskListView && this._dragSrc) { 428 this._taskListView.setDragSource(this._dragSrc); 429 } 430 return this._taskListView; 431 }; 432 433 ZmTaskListController.prototype._getToolBarOps = 434 function() { 435 var toolbarOps = []; 436 toolbarOps.push(ZmOperation.EDIT, 437 ZmOperation.SEP, 438 ZmOperation.DELETE, ZmOperation.MOVE_MENU, ZmOperation.TAG_MENU, 439 ZmOperation.SEP, 440 ZmOperation.PRINT, 441 ZmOperation.SEP, 442 ZmOperation.MARK_AS_COMPLETED, 443 ZmOperation.SEP, 444 ZmOperation.CLOSE 445 ); 446 447 return toolbarOps; 448 }; 449 450 ZmTaskListController.prototype._getButtonOverrides = 451 function(buttons) { 452 453 if (!(buttons && buttons.length)) { return; } 454 455 var overrides = {}; 456 var idParams = { 457 skinComponent: ZmId.SKIN_APP_TOP_TOOLBAR, 458 componentType: ZmId.WIDGET_BUTTON, 459 app: ZmId.APP_TASKS, 460 containingView: ZmId.VIEW_TASKLIST 461 }; 462 for (var i = 0; i < buttons.length; i++) { 463 var buttonId = buttons[i]; 464 overrides[buttonId] = {}; 465 idParams.componentName = buttonId; 466 var item = (buttonId === ZmOperation.SEP) ? "Separator" : buttonId + " button"; 467 var description = item + " on top toolbar for task list view"; 468 overrides[buttonId].domId = ZmId.create(idParams, description); 469 } 470 return overrides; 471 }; 472 473 ZmTaskListController.prototype._getRightSideToolBarOps = 474 function(noViewMenu) { 475 return [ZmOperation.VIEW_MENU]; 476 }; 477 478 479 ZmTaskListController.prototype._initialize = 480 function(view) { 481 // set up double pane view (which creates the TLV and TV) 482 if (!this._taskMultiView){ 483 var dpv = this._taskMultiView = new ZmTaskMultiView({parent:this._container, posStyle:Dwt.ABSOLUTE_STYLE, controller:this, dropTgt:this._dropTgt}); 484 this._taskListView = dpv.getTaskListView(); 485 } 486 487 if(view == ZmId.VIEW_TASK) { 488 this._listView[view] = new ZmTaskView(this._container, DwtControl.ABSOLUTE_STYLE, this); 489 } 490 491 ZmListController.prototype._initialize.call(this, view); 492 }; 493 494 ZmTaskListController.prototype.getTaskMultiView = 495 function() { 496 return this._taskMultiView; 497 }; 498 499 ZmTaskListController.prototype._initializeToolBar = 500 function(view) { 501 if (this._toolbar[view]) { return; } 502 503 ZmListController.prototype._initializeToolBar.call(this, view); 504 505 this._setupPrintMenu(view); 506 this._setupViewMenu(view); 507 this._setupMarkAsCompletedMenu(view); 508 509 this._toolbar[view].getButton(ZmOperation.DELETE).setToolTipContent(ZmMsg.hardDeleteTooltip); 510 511 this._toolbar[view].addFiller(); 512 this._initializeNavToolBar(view); 513 }; 514 515 ZmTaskListController.prototype._handleSyncAll = 516 function() { 517 //doesn't do anything now after I removed the appCtxt.get(ZmSetting.GET_MAIL_ACTION) == ZmSetting.GETMAIL_ACTION_DEFAULT preference stuff 518 }; 519 520 ZmTaskListController.prototype.runRefresh = 521 function() { 522 if (!appCtxt.isOffline) { 523 return; 524 } 525 //should only happen in ZD 526 527 this._syncAllListener(); 528 }; 529 530 531 ZmTaskListController.prototype._syncAllListener = 532 function(view) { 533 var callback = new AjxCallback(this, this._handleSyncAll); 534 appCtxt.accountList.syncAll(callback); 535 }; 536 537 538 ZmTaskListController.prototype._sendReceiveListener = 539 function(ev) { 540 var account = appCtxt.accountList.getAccount(ev.item.getData(ZmOperation.MENUITEM_ID)); 541 if (account) { 542 account.sync(); 543 } 544 }; 545 546 ZmTaskListController.prototype._setupMarkAsCompletedMenu = 547 function(view) { 548 var markAsCompButton = this._toolbar[view].getButton(ZmOperation.MARK_AS_COMPLETED); 549 if(!markAsCompButton) { return; } 550 551 markAsCompButton.setToolTipContent(ZmMsg.markAsCompleted); 552 markAsCompButton.addSelectionListener(this._listeners[ZmOperation.MARK_AS_COMPLETED]); 553 //markAsCompButton.noMenuBar = true; 554 } 555 556 ZmTaskListController.prototype._setupPrintMenu = 557 function(view) { 558 var printButton = this._toolbar[view].getButton(ZmOperation.PRINT); 559 if (!printButton) { return; } 560 561 printButton.setToolTipContent(ZmMsg.printMultiTooltip); 562 printButton.noMenuBar = true; 563 var menu = new ZmPopupMenu(printButton); 564 printButton.setMenu(menu); 565 566 var id = ZmOperation.PRINT_TASK; 567 var mi = menu.createMenuItem(id, {image:ZmOperation.getProp(id, "image"), text:ZmMsg[ZmOperation.getProp(id, "textKey")]}); 568 mi.setData(ZmOperation.MENUITEM_ID, id); 569 mi.addSelectionListener(this._listeners[ZmOperation.PRINT_TASK]); 570 571 id = ZmOperation.PRINT_TASKFOLDER; 572 mi = menu.createMenuItem(id, {image:ZmOperation.getProp(id, "image"), text:ZmMsg[ZmOperation.getProp(id, "textKey")]}); 573 mi.setData(ZmOperation.MENUITEM_ID, id); 574 mi.addSelectionListener(this._listeners[ZmOperation.PRINT_TASKFOLDER]); 575 }; 576 577 ZmTaskListController.prototype._setupViewMenu = 578 function(view) { 579 var btn = this._toolbar[view].getButton(ZmOperation.VIEW_MENU); 580 var menu = btn.getMenu(); 581 if (!menu) { 582 menu = new ZmPopupMenu(btn); 583 btn.setMenu(menu); 584 585 586 var pref = this._getFilterByPref(); 587 for (var i = 0; i < ZmTaskListController.SORT_BY.length; i++) { 588 var id = ZmTaskListController.SORT_BY[i]; 589 var params = { 590 image:ZmTaskListController.ICON[id], 591 text:ZmMsg[ZmTaskListController.MSG_KEY[id]], 592 style:DwtMenuItem.RADIO_STYLE, 593 radioGroupId:"TAKS_FILTER_BY" 594 }; 595 var mi = menu.createMenuItem(id, params); 596 mi.setData(ZmOperation.MENUITEM_ID, id); 597 mi.addSelectionListener(this._listeners[ZmOperation.VIEW]); 598 if (id == ZmTaskListController.FILTERBY_SETTING_ID[pref]) { // "all" is the default 599 mi.setChecked(true, true); 600 } 601 } 602 new DwtMenuItem({parent:menu, style:DwtMenuItem.SEPARATOR_STYLE}); 603 btn.setImage(ZmTaskListController.READING_PANE_ICON[pref]); 604 pref = this._getReadingPanePref(); 605 for (var i = 0; i < ZmTaskListController.RP_IDS.length; i++) { 606 var id = ZmTaskListController.RP_IDS[i]; 607 var params = { 608 image:ZmTaskListController.READING_PANE_ICON[id], 609 text:ZmTaskListController.READING_PANE_TEXT[id], 610 style:DwtMenuItem.RADIO_STYLE, 611 radioGroupId:"TASKS_READING_PANE" 612 }; 613 var mi = menu.createMenuItem(id, params); 614 mi.setData(ZmOperation.MENUITEM_ID, id); 615 mi.addSelectionListener(this._listeners[ZmOperation.VIEW]); 616 if (id == pref) { 617 mi.setChecked(true, true); 618 } 619 } 620 } 621 }; 622 623 ZmTaskListController.prototype._getActionMenuOps = 624 function() { 625 return [ 626 ZmOperation.EDIT, 627 ZmOperation.MARK_AS_COMPLETED, 628 ZmOperation.SEP, 629 ZmOperation.TAG_MENU, 630 ZmOperation.DELETE, 631 ZmOperation.MOVE, 632 ZmOperation.PRINT_TASK, 633 ZmOperation.SHOW_ORIG 634 ]; 635 }; 636 637 ZmTaskListController.prototype._getTagMenuMsg = 638 function(num) { 639 return AjxMessageFormat.format(ZmMsg.tagTasks, num); 640 }; 641 642 ZmTaskListController.prototype._resetOperations = 643 function(parent, num) { 644 ZmListController.prototype._resetOperations.call(this, parent, num); 645 646 // a valid folderId means user clicked on a task list 647 var folderId = (this._activeSearch && this._activeSearch.search) ? this._activeSearch.search.folderId : null; 648 if (folderId) { 649 var folder = appCtxt.getById(folderId); 650 var isShare = folder && folder.link; 651 var isTrash = folder && folder.id == ZmOrganizer.ID_TRASH; 652 var canEdit = !(folder && (folder.isReadOnly() || folder.isFeed())); 653 var task = this._listView[this._currentViewId].getSelection()[0]; 654 655 parent.enable([ZmOperation.MOVE, ZmOperation.MOVE_MENU, ZmOperation.DELETE], canEdit && num > 0); 656 parent.enable(ZmOperation.EDIT, !isTrash && canEdit && num == 1); 657 parent.enable(ZmOperation.MARK_AS_COMPLETED, !isTrash && canEdit && num > 0 && task && !task.isComplete()); 658 parent.enable(ZmOperation.TAG_MENU, (canEdit && num > 0)); 659 } else { 660 var task = this._listView[this._currentViewId].getSelection()[0]; 661 var canEdit = (num == 1 && !task.isReadOnly() && !ZmTask.isInTrash(task)); 662 parent.enable([ZmOperation.DELETE, ZmOperation.MOVE, ZmOperation.MOVE_MENU, ZmOperation.TAG_MENU], num > 0); 663 parent.enable(ZmOperation.EDIT, canEdit); 664 parent.enable(ZmOperation.MARK_AS_COMPLETED, canEdit && !task.isComplete()) 665 } 666 parent.setItemVisible(ZmOperation.CLOSE, false); 667 var printButton = (parent instanceof ZmButtonToolBar) ? parent.getButton(ZmOperation.PRINT) : null; 668 var printMenu = printMenu && printButton.getMenu(); 669 var printMenuItem = printMenu && printMenu.getItem(1); 670 if (printMenuItem) { 671 var text = (folderId != null) ? ZmMsg.printTaskFolder : ZmMsg.printResults; 672 printMenuItem.setText(text); 673 } 674 675 var printOp = (parent instanceof ZmActionMenu) ? ZmOperation.PRINT_TASK : ZmOperation.PRINT; 676 parent.enable(printOp, num > 0); 677 parent.enable(ZmOperation.VIEW_MENU, true) 678 parent.enable(ZmOperation.TEXT, true); 679 680 if (parent.getOp(ZmOperation.SHOW_ORIG)){ 681 var tasks = this._taskListView.getSelection(); 682 parent.enable(ZmOperation.SHOW_ORIG, num == 1 && tasks && tasks.length && tasks[0].getRestUrl() != null); 683 } 684 685 if(appCtxt.isExternalAccount()) { 686 parent.enable ([ 687 ZmOperation.EDIT, 688 ZmOperation.MARK_AS_COMPLETED, 689 ZmOperation.MOVE, 690 ZmOperation.MOVE_MENU, 691 ZmOperation.TAG_MENU, 692 ZmOperation.DELETE 693 ], false); 694 parent.setItemVisible(ZmOperation.TAG_MENU, false); 695 } 696 }; 697 698 ZmTaskListController.prototype._deleteListener = 699 function(ev) { 700 701 var tasks = this._listView[this._currentViewId].getSelection(); 702 703 if (!tasks || tasks.length == 0) return; 704 705 this._doDelete(this._listView[this._currentViewId].getSelection()); 706 }; 707 708 ZmTaskListController.prototype._deleteCallback = 709 function(dialog) { 710 dialog.popdown(); 711 // hard delete 712 this._doDelete(this._listView[this._currentViewId].getSelection()); 713 }; 714 715 ZmTaskListController.prototype._doDelete = function(tasks, hardDelete) { 716 717 /* 718 * XXX: Recurrence is not yet supported by tasks 719 * 720 if (task.isRecurring() && !task.isException) { 721 // prompt user to edit instance vs. series if recurring but not exception 722 this._showTypeDialog(task, ZmCalItem.MODE_DELETE); 723 } 724 */ 725 if (!tasks || tasks.length == 0) { 726 return; 727 } 728 729 // check to see if this is a cancel or delete 730 var nId = ZmOrganizer.normalizeId(tasks[0].folderId); 731 var isTrash = nId == ZmOrganizer.ID_TRASH; 732 733 if (isTrash || hardDelete) { 734 this._handleDelete(tasks); 735 } 736 else { 737 this._handleCancel(tasks); 738 } 739 }; 740 741 ZmTaskListController.prototype._handleDelete = 742 function(tasks) { 743 var params = { 744 items: tasks, 745 hardDelete: true, 746 finalCallback: this._handleDeleteResponse.bind(this, tasks) 747 }; 748 // NOTE: This makes the assumption that the task items to be deleted are 749 // NOTE: always in a list (which knows how to hard delete items). But since 750 // NOTE: this is the task *list* controller, I think that's a fair bet. ;) 751 tasks[0].list.deleteItems(params); 752 }; 753 754 ZmTaskListController.prototype._handleDeleteResponse = function(tasks, resp) { 755 var summary = ZmList.getActionSummary({ 756 actionTextKey: 'actionDelete', 757 numItems: tasks.length, 758 type: ZmItem.TASK 759 }); 760 appCtxt.setStatusMsg(summary); 761 }; 762 763 ZmTaskListController.prototype._doCheckCompleted = 764 function(task,ftask) { 765 var clone = ZmTask.quickClone(task); 766 clone.message = null; 767 var callback = new AjxCallback(this, this._doCheckCompletedResponse, [clone,ftask]); 768 clone.getDetails(ZmCalItem.MODE_EDIT, callback); 769 }; 770 771 ZmTaskListController.prototype._doCheckCompletedResponse = 772 function(task,ftask) { 773 var clone = ZmTask.quickClone(task); 774 clone.pComplete = task.isComplete() ? 0 : 100; 775 clone.status = task.isComplete() ? ZmCalendarApp.STATUS_NEED : ZmCalendarApp.STATUS_COMP; 776 if(!task.isComplete()) { //bug:51913 disable alarm when stats is completed 777 clone.alarm = false; 778 clone.setTaskReminder(null); 779 } 780 clone.setViewMode(ZmCalItem.MODE_EDIT); 781 var callback = new AjxCallback(this, this._markAsCompletedResponse, [clone,ftask]); 782 clone.save(null, callback); 783 }; 784 785 ZmTaskListController.prototype.isHiddenTask = 786 function(task) { 787 var pref = this._getFilterByPref(); 788 if (task.isComplete() && !(pref == ZmSetting.TASK_FILTER_ALL || pref == ZmSetting.TASK_FILTER_COMPLETED)) 789 return true; 790 791 if (task.pComplete != 0 && (pref == ZmSetting.TASK_FILTER_NOTSTARTED)) 792 return true; 793 794 return false; 795 796 }; 797 798 ZmTaskListController.prototype._markAsCompletedResponse = 799 function(task,ftask) { 800 if (task && task._orig) { 801 task._orig.message = null; 802 } 803 //Cache the item for further processing 804 task.cache(); 805 this._taskListView.updateListViewEl(task); 806 if(ftask && this.isReadingPaneOn() && !this.isHiddenTask(task)) { 807 this._taskMultiView.setTask(task); 808 } 809 }; 810 811 812 ZmTaskListController.prototype._handleCancel = 813 function(tasks) { 814 var batchCmd = new ZmBatchCommand(true, null, true); 815 var actionController = appCtxt.getActionController(); 816 var idList = []; 817 for (var i = 0; i < tasks.length; i++) { 818 var t = tasks[i]; 819 var cmd = new AjxCallback(t, t.cancel, [ZmCalItem.MODE_DELETE]); 820 batchCmd.add(cmd); 821 idList.push(t.id); 822 } 823 var actionLogItem = (actionController && actionController.actionPerformed({op: "trash", ids: idList, attrs: {l: ZmOrganizer.ID_TRASH}})) || null; 824 batchCmd.run(); 825 826 // Mark the action as complete, so that the undo in the toast message will work 827 if (actionLogItem) { 828 actionLogItem.setComplete(); 829 } 830 831 var summary = ZmList.getActionSummary({type:ZmItem.TASK, actionTextKey:"actionTrash", numItems:tasks.length}); 832 833 var undoLink = actionLogItem && actionController && actionController.getUndoLink(actionLogItem); 834 if (undoLink && actionController) { 835 actionController.onPopup(); 836 appCtxt.setStatusMsg({msg: summary+undoLink, transitions: actionController.getStatusTransitions()}); 837 } else { 838 appCtxt.setStatusMsg(summary); 839 } 840 }; 841 ZmTaskListController.prototype.isReadOnly = 842 function() { 843 var folder = appCtxt.getById(this._folderId); 844 return (folder && (folder.id == ZmOrganizer.ID_TRASH || folder.isReadOnly() || folder.isFeed())); 845 }; 846 847 ZmTaskListController.prototype._editTask = 848 function(task) { 849 var mode = ZmCalItem.MODE_EDIT; 850 851 var folder = appCtxt.getById(task.folderId); 852 var canEdit = null; 853 854 if(folder) { 855 canEdit = folder.id != ZmOrganizer.ID_TRASH && !folder.isReadOnly() && !folder.isFeed(); 856 } 857 858 if (!canEdit) { 859 if (task.isException) mode = ZmCalItem.MODE_EDIT_SINGLE_INSTANCE; 860 var clone = ZmTask.quickClone(task); 861 clone.getDetails(mode, new AjxCallback(this, this._showTaskReadOnlyView, [clone, true])); 862 } else { 863 if (task.isRecurring()) { 864 /*recurring tasks not yet supported bug 23454 865 // prompt user to edit instance vs. series if recurring but not exception 866 //if (task.isException) { 867 // mode = ZmCalItem.MODE_EDIT_SINGLE_INSTANCE; 868 //} else { 869 // this._showTypeDialog(task, ZmCalItem.MODE_EDIT); 870 // return; 871 /}*/ 872 mode = ZmCalItem.MODE_EDIT_SINGLE_INSTANCE; 873 } 874 task.message = null; //null out message so we re-fetch task next time its opened 875 task.getDetails(mode, new AjxCallback(this, this._showTaskEditView, [task, mode])); 876 } 877 }; 878 879 // All items in the list view are gone - show "No Results" 880 ZmTaskListController.prototype._handleEmptyList = 881 function(listView) { 882 listView._resetListView(); 883 listView._setNoResultsHtml(); 884 }; 885 886 ZmTaskListController.prototype._setSelectedItem = 887 function() { 888 var selCnt = this._listView[this._currentViewId].getSelectionCount(); 889 if (selCnt == 1) { 890 var task = this._listView[this._currentViewId].getSelection(); 891 } 892 }; 893 894 ZmTaskListController.prototype._showTaskReadOnlyView = 895 function(task, newTab) { 896 var viewId = ZmId.VIEW_TASK; 897 newTab = newTab || !this.isReadingPaneOn(); 898 if(newTab) { 899 var calItemView = this._listView[viewId]; 900 901 if (!calItemView) { 902 this._setup(viewId); 903 calItemView = this._listView[viewId]; 904 } 905 calItemView._newTab = true; 906 calItemView.set(task, ZmId.VIEW_TASKLIST); 907 908 this._resetOperations(this._toolbar[viewId], 1); // enable all buttons 909 910 var elements = this.getViewElements(viewId, this._listView[viewId]); 911 912 this._setView({ view: viewId, 913 elements: elements, 914 pushOnly: true}); 915 } else { 916 var calItemView = this._taskMultiView._taskView; 917 calItemView._newTab = false; 918 if(calItemView) { 919 calItemView.set(task, ZmId.VIEW_TASK); 920 } 921 } 922 if (this._toolbar[viewId]) 923 this._toolbar[viewId].setItemVisible(ZmOperation.CLOSE, newTab ); 924 }; 925 926 ZmTaskListController.prototype._showTaskEditView = 927 function(task, mode) { 928 this._app.getTaskController().show(task, mode); 929 }; 930 931 ZmTaskListController.prototype._showTypeDialog = 932 function(task, mode) { 933 if (!this._typeDialog) { 934 this._typeDialog = new ZmCalItemTypeDialog(this._shell); 935 this._typeDialog.addSelectionListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._typeOkListener, [task, mode])); 936 } 937 this._typeDialog.initialize(task, mode, ZmItem.TASK); 938 this._typeDialog.popup(); 939 }; 940 941 ZmTaskListController.prototype._typeOkListener = 942 function(task, mode, ev) { 943 var isInstance = this._typeDialog.isInstance(); 944 945 if (mode == ZmCalItem.MODE_DELETE) { 946 var delMode = isInstance 947 ? ZmCalItem.MODE_DELETE_INSTANCE 948 : ZmCalItem.MODE_DELETE_SERIES; 949 // TODO 950 } else { 951 var editMode = isInstance 952 ? ZmCalItem.MODE_EDIT_SINGLE_INSTANCE 953 : ZmCalItem.MODE_EDIT_SERIES; 954 955 task.getDetails(mode, new AjxCallback(this, this._showTaskEditView, [task, editMode])); 956 } 957 }; 958 959 ZmTaskListController.prototype._newListener = 960 function(ev, op, params) { 961 params = params || {}; 962 params.folderId = this._list.search.folderId; 963 ZmListController.prototype._newListener.call(this, ev, op, params); 964 }; 965 966 ZmTaskListController.prototype._listSelectionListener = 967 function(ev) { 968 Dwt.setLoadingTime("ZmTaskItem"); 969 ZmListController.prototype._listSelectionListener.call(this, ev); 970 971 if (ev.detail == DwtListView.ITEM_DBL_CLICKED) { 972 this._editTask(ev.item); 973 } else if(this.isReadingPaneOn()) { 974 var task = ev.item; 975 var mode = ZmCalItem.MODE_EDIT; 976 var clone = ZmTask.quickClone(task); 977 clone.getDetails(mode, new AjxCallback(this, this._showTaskReadOnlyView, [clone, false])); 978 } 979 }; 980 981 ZmTaskListController.prototype._listActionListener = 982 function(ev) { 983 ZmListController.prototype._listActionListener.call(this, ev); 984 var actionMenu = this.getActionMenu(); 985 actionMenu.popup(0, ev.docX, ev.docY); 986 }; 987 988 ZmTaskListController.prototype._editListener = 989 function(ev) { 990 var task = this._listView[this._currentViewId].getSelection()[0]; 991 this._editTask(task); 992 }; 993 994 ZmTaskListController.prototype._printTaskListener = 995 function(ev) { 996 var listView = this._listView[this._currentViewId]; 997 var items = listView.getSelection(); 998 var taskIds = []; 999 for (var i = 0; i < items.length; i++) { 1000 taskIds.push(items[i].invId); 1001 } 1002 1003 var url = ["/h/printtasks?id=", taskIds.join(",")]; 1004 if (appCtxt.isOffline) { 1005 var folderId = this._folderId || ZmFolder.ID_CONTACTS; 1006 var acctName = appCtxt.getById(folderId).getAccount().name; 1007 url.push("&acct=", acctName); 1008 } 1009 window.open([appContextPath, url.join(""), "&tz=", AjxTimezone.getServerId(AjxTimezone.DEFAULT)].join(""), "_blank"); 1010 }; 1011 1012 ZmTaskListController.prototype._markAsCompletedListener = 1013 function(ev) { 1014 var listView = this._listView[this._currentViewId]; 1015 var items = listView.getSelection(); 1016 var fItem = null; 1017 for (var i = 0; i < items.length; i++) { 1018 var task = items[i]; 1019 if (!task.isComplete()) { 1020 if(!fItem) fItem = true; 1021 this._doCheckCompleted(items[i],fItem); 1022 } 1023 } 1024 var summary = ZmList.getActionSummary({ 1025 actionTextKey: 'actionCompleted', 1026 numItems: items.length, 1027 type: ZmItem.TASK 1028 }); 1029 appCtxt.setStatusMsg(summary); 1030 }; 1031 1032 ZmTaskListController.prototype._printListener = 1033 function(ev) { 1034 this._printTaskListener(ev); 1035 }; 1036 1037 ZmTaskListController.prototype._printTaskFolderListener = 1038 function(ev) { 1039 var url = ["/h/printtasks?"]; 1040 if (this._folderId) { 1041 url.push("st=task&sfi=", this._folderId); 1042 } else { 1043 var taskIds = []; 1044 var list = this._list.getArray(); 1045 for (var i = 0; i < list.length; i++) { 1046 taskIds.push(list[i].invId); 1047 } 1048 url.push("id=", taskIds.join(",")); 1049 } 1050 if (appCtxt.isOffline) { 1051 var folderId = this._folderId || ZmFolder.ID_CONTACTS; 1052 var acctName = appCtxt.getById(folderId).getAccount().name; 1053 url.push("&acct=", acctName); 1054 } 1055 window.open([appContextPath, url.join(""), "&tz=", AjxTimezone.getServerId(AjxTimezone.DEFAULT)].join(""), "_blank"); 1056 }; 1057 1058 ZmTaskListController.prototype._setViewContents = 1059 function(view) { 1060 // load tasks into the given view and perform layout. 1061 var lv = this._taskListView; 1062 lv.set(this._list, lv._getPrefSortField()); 1063 1064 if (lv.offset == 0) { 1065 var list = this._list.getVector(); 1066 if (list.size()) { 1067 this._taskListView.setSelection(list.get(0)); 1068 } else { 1069 this._taskMultiView._taskView.reset(); 1070 } 1071 } 1072 }; 1073 1074 ZmTaskListController.prototype._getMoveDialogTitle = 1075 function(num) { 1076 return AjxMessageFormat.format(ZmMsg.moveTasks, num); 1077 }; 1078 1079 // Move stuff to a new folder. 1080 ZmTaskListController.prototype._moveCallback = 1081 function(folder) { 1082 this._doMove(this._pendingActionData, folder); 1083 this._clearDialog(appCtxt.getChooseFolderDialog()); 1084 this._pendingActionData = null; 1085 }; 1086 1087 ZmTaskListController.prototype._showOrigListener = 1088 function(ev) { 1089 var tasks = this._listView[this._currentViewId].getSelection(); 1090 if (tasks && tasks.length > 0) { 1091 setTimeout(this._showTaskSource.bind(this, tasks[0]), 100); // Other listeners are focusing the main window, so delay the window opening for just a bit 1092 } 1093 }; 1094 1095 ZmTaskListController.prototype._showTaskSource = 1096 function(task) { 1097 var apptFetchUrl = appCtxt.get(ZmSetting.CSFE_MSG_FETCHER_URI) 1098 + "&id=" + AjxStringUtil.urlComponentEncode(task.id || task.invId) 1099 +"&mime=text/plain&noAttach=1&icalAttach=none"; 1100 // create a new window w/ generated msg based on msg id 1101 window.open(apptFetchUrl, "_blank", "menubar=yes,resizable=yes,scrollbars=yes"); 1102 }; 1103 1104 /** 1105 * Gets the checked calendar folder ids. 1106 * 1107 * @param {Boolean} localOnly if <code>true</code>, include local calendars only 1108 * @return {Array} an array of folder ids 1109 */ 1110 ZmTaskListController.prototype.getTaskFolderIds = 1111 function(localOnly) { 1112 var cc = []; 1113 if(localOnly) { 1114 if(this._taskTreeController) { 1115 if (appCtxt.multiAccounts) { 1116 var overviews = this._app.getOverviewContainer().getOverviews(); 1117 for (var i in overviews) { 1118 cc = cc.concat(this._taskTreeController.getTaskFolders(i, false)); 1119 } 1120 } else { 1121 // bug fix #25512 - avoid race condition 1122 if (!this._app._overviewPanelContent) { 1123 this._app.setOverviewPanelContent(true); 1124 } 1125 cc = this._taskTreeController.getTaskFolders(this._app.getOverviewId(), false); 1126 } 1127 } else { 1128 this._app._createDeferredFolders(ZmApp.TASKS); 1129 var list = appCtxt.accountList.visibleAccounts; 1130 for (var i = 0; i < list.length; i++) { 1131 var acct = list[i]; 1132 if (!appCtxt.get(ZmSetting.TASKS_ENABLED, null, acct)) { continue; } 1133 1134 var tasks = appCtxt.getFolderTree(acct).getByType(ZmOrganizer.TASKS); 1135 for (var j = 0; j < tasks.length; j++) { 1136 if (tasks[j].nId == ZmOrganizer.ID_TRASH) { 1137 continue; 1138 } 1139 cc.push(tasks[j]); 1140 } 1141 } 1142 1143 } 1144 1145 this._taskLocalFolderIds = []; 1146 1147 for (var i = 0; i < cc.length; i++) { 1148 var cal = cc[i]; 1149 if (cal.noSuchFolder) { continue; } 1150 1151 if (cal.isRemote && !cal.isRemote()) { 1152 this._taskLocalFolderIds.push(cal.id); 1153 } 1154 } 1155 1156 // return list of checked calendars 1157 return this._taskLocalFolderIds; 1158 } 1159 }; 1160