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