1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 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) 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 briefcase tree controller class.
 27  * 
 28  */
 29 
 30 /**
 31  * Creates the briefcase tree controller.
 32  * @class
 33  * This class is a controller for the tree view used by the briefcase application.
 34  *
 35  * @param	{constant}	type		the organizer (see {@link ZmOrganizer.BRIEFCASE})
 36  * 
 37  * @author Parag Shah
 38  * 
 39  * @extends		ZmFolderTreeController
 40  */
 41 ZmBriefcaseTreeController = function(type) {
 42 
 43 	ZmFolderTreeController.call(this, (type || ZmOrganizer.BRIEFCASE));
 44 
 45 	this._listeners[ZmOperation.NEW_BRIEFCASE] = new AjxListener(this, this._newListener);
 46 	this._listeners[ZmOperation.SHARE_BRIEFCASE] = new AjxListener(this, this._shareBriefcaseListener);
 47 
 48 	this._eventMgrs = {};
 49     this._app = appCtxt.getApp(ZmApp.BRIEFCASE);
 50 };
 51 
 52 ZmBriefcaseTreeController.prototype = new ZmFolderTreeController;
 53 ZmBriefcaseTreeController.prototype.constructor = ZmBriefcaseTreeController;
 54 
 55 /**
 56  * Returns a string representation of the object.
 57  * 
 58  * @return		{String}		a string representation of the object
 59  */
 60 ZmBriefcaseTreeController.prototype.toString =
 61 function() {
 62 	return "ZmBriefcaseTreeController";
 63 };
 64 
 65 // Public methods
 66 
 67 ZmBriefcaseTreeController.prototype.resetOperations =
 68 function(actionMenu, type, id) {
 69 
 70 	var rootId = ZmOrganizer.getSystemId(ZmOrganizer.ID_ROOT);
 71      if (actionMenu && id != rootId) {
 72 		var briefcase = appCtxt.getById(id);
 73 		if (!briefcase) { return; }
 74         var nId = ZmOrganizer.normalizeId(id);
 75 		var isRoot = (nId == rootId);
 76 		var isBriefcase = (nId == ZmOrganizer.getSystemId(ZmOrganizer.ID_BRIEFCASE));
 77 		var isTopLevel = (!isRoot && briefcase.parent.id == rootId);
 78 		var isLink = briefcase.link;
 79 		var isLinkOrRemote = isLink || briefcase.isRemote();
 80         var isTrash = (nId == ZmFolder.ID_TRASH);
 81         var isReadOnly = briefcase ? briefcase.isReadOnly() : false;
 82 
 83         var deleteText = ZmMsg.del;
 84 
 85         actionMenu.getOp(ZmOperation.EMPTY_FOLDER).setVisible(isTrash);
 86 
 87         if (isTrash) {
 88             var hasContent = ((briefcase.numTotal > 0) || (briefcase.children && (briefcase.children.size() > 0)));
 89             actionMenu.enableAll(false);
 90             actionMenu.enable(ZmOperation.EMPTY_FOLDER,hasContent);
 91             actionMenu.getOp(ZmOperation.EMPTY_FOLDER).setText(ZmMsg.emptyTrash);            
 92         } else {
 93             actionMenu.enableAll(true);
 94             var showEditMenu = (!isLinkOrRemote || !isReadOnly || (isLink && isTopLevel) || ZmBriefcaseTreeController.__isAllowed(briefcase.parent, ZmShare.PERM_DELETE));
 95             actionMenu.enable(ZmOperation.DELETE_WITHOUT_SHORTCUT, showEditMenu && !isBriefcase);
 96             actionMenu.enable(ZmOperation.EDIT_PROPS, showEditMenu);
 97 
 98 			var menuItem;
 99             menuItem = actionMenu.getMenuItem(ZmOperation.NEW_BRIEFCASE);
100             menuItem.setText(ZmMsg.newFolder);
101             menuItem.setImage("NewFolder");
102             menuItem.setEnabled((!isLinkOrRemote || ZmBriefcaseTreeController.__isAllowed(briefcase, ZmShare.PERM_CREATE_SUBDIR) || briefcase.isAdmin() || ZmShare.getRoleFromPerm(briefcase.perm) == ZmShare.ROLE_MANAGER));
103 
104             if (appCtxt.get(ZmSetting.SHARING_ENABLED)) {
105                 isBriefcase = (!isRoot && briefcase.parent.id == rootId) || type==ZmOrganizer.BRIEFCASE;
106                 menuItem = actionMenu.getMenuItem(ZmOperation.SHARE_BRIEFCASE);
107                 menuItem.setText(ZmMsg.shareFolder);
108                 menuItem.setImage(isBriefcase ? "SharedMailFolder" : "Section");
109                 var isShareVisible = (!isLinkOrRemote || briefcase.isAdmin());
110                 if (appCtxt.isOffline) {
111                     var acct = briefcase.getAccount();
112                     isShareVisible = !acct.isMain && acct.isZimbraAccount;
113                 }
114                 menuItem.setEnabled(isShareVisible);
115             }
116         }
117         var op = actionMenu.getOp(ZmOperation.DELETE_WITHOUT_SHORTCUT);
118         if (op) {
119             op.setText(deleteText);
120         }
121 		this._enableRecoverDeleted(actionMenu, isTrash);
122 
123         // we always enable sharing in case we're in multi-mbox mode
124         this._resetButtonPerSetting(actionMenu, ZmOperation.SHARE_BRIEFCASE, appCtxt.get(ZmSetting.SHARING_ENABLED));
125 
126 	}
127 
128 };
129 
130 ZmBriefcaseTreeController.prototype._getAllowedSubTypes =
131 function() {
132 	return ZmTreeController.prototype._getAllowedSubTypes.call(this);
133 };
134 
135 ZmBriefcaseTreeController.prototype._getSearchTypes =
136 function(ev) {
137 	return [ZmItem.BRIEFCASE_ITEM];
138 };
139 
140 ZmBriefcaseTreeController.__isAllowed =
141 function(organizer, perm) {
142 	var allowed = true;
143 	if (organizer.link || organizer.isRemote()) {
144 		allowed = false; // change assumption to not allowed
145 
146 		// REVISIT: bug 10801
147 		var share = organizer.getMainShare();
148 		if (share && !share.isPermRestricted(perm)) {
149 			allowed = share.isPermAllowed(perm);
150 		}
151 	}
152 	return allowed;
153 };
154 
155 // Returns a list of desired header action menu operations
156 ZmBriefcaseTreeController.prototype._getHeaderActionMenuOps =
157 function() {
158     var ops = [];
159     if (!appCtxt.isExternalAccount()) {
160         ops.push(ZmOperation.NEW_BRIEFCASE);
161     }
162     ops.push(ZmOperation.EXPAND_ALL);
163 	if (!appCtxt.isExternalAccount()) {
164 		ops.push(ZmOperation.FIND_SHARES);
165 	}
166 	return ops;
167 };
168 
169 // Returns a list of desired action menu operations
170 ZmBriefcaseTreeController.prototype._getActionMenuOps =
171 function() {
172 
173 	var ops = [
174 		ZmOperation.NEW_BRIEFCASE,
175 		ZmOperation.EMPTY_FOLDER,
176 		ZmOperation.RECOVER_DELETED_ITEMS
177 	];
178 	if (appCtxt.get(ZmSetting.SHARING_ENABLED)) {
179 		ops.push(ZmOperation.SHARE_BRIEFCASE);
180 	}
181 	ops.push(
182 		ZmOperation.DELETE_WITHOUT_SHORTCUT,
183 		ZmOperation.EDIT_PROPS
184 	);
185 	return ops;
186 };
187 
188 ZmBriefcaseTreeController.prototype._getNewDialog =
189 function() {
190 	return appCtxt.getNewBriefcaseDialog();
191 };
192 
193 /**
194  * Gets the tree style.
195  * 
196  * @return	{constant}	the style
197  * 
198  * @see		DwtTree.SINGLE_STYLE
199  */
200 ZmBriefcaseTreeController.prototype.getTreeStyle =
201 function() {
202 	return DwtTree.SINGLE_STYLE;
203 };
204 
205 // Method that is run when a tree item is left-clicked
206 ZmBriefcaseTreeController.prototype._itemClicked =
207 function(folder) {
208 	appCtxt.getApp(ZmApp.BRIEFCASE).search({
209         folderId:folder.id,
210         callback: new AjxCallback(this, this._handleSearchResponse, [folder])
211     });
212 };
213 
214 // Listener callbacks
215 
216 ZmBriefcaseTreeController.prototype._shareBriefcaseListener =
217 function(ev) {
218 	this._pendingActionData = this._getActionedOrganizer(ev);
219 
220 	var briefcase = this._pendingActionData;
221 	var share = null;
222 
223 	var sharePropsDialog = appCtxt.getSharePropsDialog();
224 	sharePropsDialog.popup(ZmSharePropsDialog.NEW, briefcase, share);
225 };
226 
227 ZmBriefcaseTreeController.prototype._notifyListeners =
228 function(overviewId, type, items, detail, srcEv, destEv) {
229 	if (this._eventMgrs[overviewId] && this._eventMgrs[overviewId].isListenerRegistered(type)) {
230 		if (srcEv) DwtUiEvent.copy(destEv, srcEv);
231 		destEv.items = items;
232 		if (items.length == 1) destEv.item = items[0];
233 		destEv.detail = detail;
234 		this._eventMgrs[overviewId].notifyListeners(type, destEv);
235 	}
236 };
237 
238 ZmBriefcaseTreeController.prototype._doCreate =
239 function(params) {
240 	ZmTreeController.prototype._doCreate.apply(this, [params]);
241 };
242 
243 ZmBriefcaseTreeController.prototype._getItems =
244 function(overviewId) {
245 	var treeView = this.getTreeView(overviewId);
246 	if (treeView) {
247 		var rootId = ZmOrganizer.getSystemId(ZmOrganizer.ID_ROOT);
248 		var root = treeView.getTreeItemById(rootId);
249 		if (root) {
250 			return root.getItems();
251 		}
252 	}
253 	return [];  
254 };
255 
256 ZmBriefcaseTreeController.prototype.show =
257 function(params) {
258 	params.include = {};
259 	params.include[ZmFolder.ID_TRASH] = true;
260     params.showUnread = false;
261     var treeView = ZmFolderTreeController.prototype.show.call(this, params);
262 
263     treeView._controller = this;
264     // Finder to BriefcaseTreeView drag and drop
265     this._initDragAndDrop(treeView);
266 
267     return treeView;
268 };
269 
270 
271 /**
272  * @private
273  */
274 ZmBriefcaseTreeController.prototype._createTreeView = function(params) {
275 	return new ZmBriefcaseTreeView(params);
276 };
277 
278 
279 ZmBriefcaseTreeController.prototype._handleSearchResponse =
280 function(folder, result) {
281     // bug fix #49568 - Trash is special when in Briefcase app since it
282     // is a FOLDER type in BRIEFCASE tree. So reset selection if clicked
283     if (folder.nId == ZmFolder.ID_TRASH) {
284         this._treeView[this._app.getOverviewId()].setSelected(folder, true);
285     }
286 };
287 
288 
289 ZmBriefcaseTreeController.prototype._initDragAndDrop = function(treeView) {
290 	this._dnd = new ZmDragAndDrop(treeView);
291 };
292