1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 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) 2005, 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  */
 27 
 28 /**
 29  * Creates a folder properties dialog.
 30  * @class
 31  * This class represents a folder properties dialog.
 32  * 
 33  * @param	{DwtControl}	parent		the parent
 34  * @param	{String}	className		the class name
 35  * 
 36  * @extends		DwtDialog
 37  */
 38 ZmFolderPropsDialog = function(parent, className) {
 39 	className = className || "ZmFolderPropsDialog";
 40 	var extraButtons;
 41 	if (appCtxt.get(ZmSetting.SHARING_ENABLED))	{
 42 		extraButtons = [
 43 			new DwtDialog_ButtonDescriptor(ZmFolderPropsDialog.ADD_SHARE_BUTTON, ZmMsg.addShare, DwtDialog.ALIGN_LEFT)
 44 		];
 45 	}
 46 
 47 
 48 	DwtDialog.call(this, {parent:parent, className:className, title:ZmMsg.folderProperties, extraButtons:extraButtons, id:"FolderProperties"});
 49 
 50 	this._tabViews  = [];
 51 	this._tabKeys   = [];
 52 	this._tabInUse  = [];
 53 	this._tabKeyMap = {};
 54 
 55 	if (appCtxt.get(ZmSetting.SHARING_ENABLED))	{
 56 		this.registerCallback(ZmFolderPropsDialog.ADD_SHARE_BUTTON, this._handleAddShareButton, this);
 57 	}
 58 	this.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._handleOkButton));
 59 	this.setButtonListener(DwtDialog.CANCEL_BUTTON, new AjxListener(this, this._handleCancelButton));
 60 
 61 	this._folderChangeListener = new AjxListener(this, this._handleFolderChange);
 62 
 63 	this._createView();
 64 	this._initializeTabGroup();
 65 };
 66 
 67 ZmFolderPropsDialog.prototype = new DwtDialog;
 68 ZmFolderPropsDialog.prototype.constructor = ZmFolderPropsDialog;
 69 
 70 // Constants
 71 
 72 ZmFolderPropsDialog.ADD_SHARE_BUTTON = ++DwtDialog.LAST_BUTTON;
 73 
 74 ZmFolderPropsDialog.SHARES_HEIGHT = "9em";
 75 
 76 // Tab identifiers
 77 ZmFolderPropsDialog.TABKEY_PROPERTIES	= "PROPERTIES_TAB";
 78 ZmFolderPropsDialog.TABKEY_RETENTION 	= "RETENTION_TAB";
 79 
 80 
 81 // Public methods
 82 
 83 ZmFolderPropsDialog.prototype.toString =
 84 function() {
 85 	return "ZmFolderPropsDialog";
 86 };
 87 
 88 ZmFolderPropsDialog.prototype.getTabKey =
 89 function(id) {
 90 	var index = this._tabKeyMap[id];
 91 	return this._tabKeys[index];
 92 };
 93 
 94 /**
 95  * Pops-up the properties dialog.
 96  * 
 97  * @param	{ZmOrganizer}	organizer		the organizer
 98  */
 99 ZmFolderPropsDialog.prototype.popup =
100 function(organizer) {
101 	this._organizer = organizer;
102     for (var i = 0; i < this._tabViews.length; i++) {
103         this._tabViews[i].setOrganizer(organizer);
104     }
105     // On popup, make the property view visible
106 	var tabKey = this.getTabKey(ZmFolderPropsDialog.TABKEY_PROPERTIES);
107 	this._tabContainer.switchToTab(tabKey, true);
108 
109 	organizer.addChangeListener(this._folderChangeListener);
110 
111 	this._handleFolderChange();
112 	if (appCtxt.get(ZmSetting.SHARING_ENABLED))	{
113 		var isShareable = ZmOrganizer.SHAREABLE[organizer.type];
114 
115 		var isVisible = (!organizer.link || organizer.isAdmin());
116 		this.setButtonVisible(ZmFolderPropsDialog.ADD_SHARE_BUTTON, isVisible && isShareable);
117 	}
118 
119 	DwtDialog.prototype.popup.call(this);
120 };
121 
122 ZmFolderPropsDialog.prototype.popdown =
123 function() {
124 	if (this._organizer) {
125 		this._organizer.removeChangeListener(this._folderChangeListener);
126 		this._organizer = null;
127 	}
128 	DwtDialog.prototype.popdown.call(this);
129 };
130 
131 // Protected methods
132 
133 ZmFolderPropsDialog.prototype._getSeparatorTemplate =
134 function() {
135 	return "";
136 };
137 
138 ZmFolderPropsDialog.prototype._handleEditShare =
139 function(event, share) {
140 	share = share || Dwt.getObjectFromElement(DwtUiEvent.getTarget(event));
141 	var sharePropsDialog = appCtxt.getSharePropsDialog();
142 	sharePropsDialog.popup(ZmSharePropsDialog.EDIT, share.object, share);
143 	return false;
144 };
145 
146 ZmFolderPropsDialog.prototype._handleRevokeShare =
147 function(event, share) {
148 	share = share || Dwt.getObjectFromElement(DwtUiEvent.getTarget(event));
149 	var revokeShareDialog = appCtxt.getRevokeShareDialog();
150 	revokeShareDialog.popup(share);
151 	return false;
152 };
153 
154 ZmFolderPropsDialog.prototype._handleResendShare =
155 function(event, share) {
156 
157 	AjxDispatcher.require("Share");
158 	share = share || Dwt.getObjectFromElement(DwtUiEvent.getTarget(event));
159 
160 	// create share info
161 	var tmpShare = new ZmShare({object:share.object});
162 	tmpShare.grantee.id = share.grantee.id;
163 	tmpShare.grantee.email = (share.grantee.type == "guest") ? share.grantee.id : share.grantee.name;
164 	tmpShare.grantee.name = share.grantee.name;
165     if (tmpShare.object.isRemote()) {
166 		tmpShare.grantor.id = tmpShare.object.zid;
167 		tmpShare.grantor.email = tmpShare.object.owner;
168 		tmpShare.grantor.name = tmpShare.grantor.email;
169 		tmpShare.link.id = tmpShare.object.rid;
170 	} else {
171 		tmpShare.grantor.id = appCtxt.get(ZmSetting.USERID);
172 		tmpShare.grantor.email = appCtxt.get(ZmSetting.USERNAME);
173 		tmpShare.grantor.name = appCtxt.get(ZmSetting.DISPLAY_NAME) || tmpShare.grantor.email;
174 		tmpShare.link.id = tmpShare.object.id;
175 	}
176 
177 	tmpShare.link.name = share.object.name;
178 	tmpShare.link.view = ZmOrganizer.getViewName(share.object.type);
179 	tmpShare.link.perm = share.link.perm;
180 
181 	if (share.grantee.type == "guest") {
182         // Pass action as ZmShare.NEW even for resend for external user
183         tmpShare._sendShareNotification(tmpShare.grantee.email, tmpShare.link.id, "", ZmShare.NEW);
184 	}
185     else {
186 	    tmpShare.sendMessage(ZmShare.NEW);
187     }
188 	appCtxt.setStatusMsg(ZmMsg.resentShareMessage);
189 
190 	return false;
191 };
192 
193 ZmFolderPropsDialog.prototype._handleAddShareButton =
194 function(event) {
195 	var sharePropsDialog = appCtxt.getSharePropsDialog();
196 	sharePropsDialog.popup(ZmSharePropsDialog.NEW, this._organizer, null);
197 };
198 
199 ZmFolderPropsDialog.prototype._handleOkButton =
200 function(event) {
201 
202 	// New batch command, stop on error
203 	var batchCommand = new ZmBatchCommand(null, null, true);
204     var saveState = {
205         commandCount: 0,
206         errorMessage: []
207     };
208     for (var i = 0; i < this._tabViews.length; i++) {
209         if (this._tabInUse[i]) {
210             // Save all in use tabs
211             this._tabViews[i].doSave(batchCommand, saveState);
212         }
213     }
214 
215     if (saveState.errorMessage.length > 0) {
216         var msg = saveState.errorMessage.join("<br>");
217         var dialog = appCtxt.getMsgDialog();
218         dialog.reset();
219         dialog.setMessage(msg, DwtMessageDialog.WARNING_STYLE);
220         dialog.popup();
221     }  else if (saveState.commandCount > 0) {
222         var callback = new AjxCallback(this, this.popdown);
223         batchCommand.run(callback);
224     } else {
225         this.popdown();
226     }
227 };
228 
229 
230 
231 ZmFolderPropsDialog.prototype._handleError =
232 function(response) {
233 	// Returned 'not handled' so that the batch command will preform the default
234 	// ZmController._handleException
235 	return false;
236 };
237 
238 
239 ZmFolderPropsDialog.prototype._handleCancelButton =
240 function(event) {
241 	this.popdown();
242 };
243 
244 ZmFolderPropsDialog.prototype._handleFolderChange =
245 function(event) {
246 	var organizer = this._organizer;
247 
248     // Get the components that will be hidden or displayed
249     var tabBar = this._tabContainer.getTabBar();
250     var tabKey = this.getTabKey(ZmFolderPropsDialog.TABKEY_RETENTION);
251     var retentionTabButton = this._tabContainer.getTabButton(tabKey);
252     var retentionIndex = this._tabKeyMap[ZmFolderPropsDialog.TABKEY_RETENTION];
253 
254     if ((organizer.type != ZmOrganizer.FOLDER) || organizer.link) {
255         // Not a folder, or shared - hide the retention view (and possibly the toolbar)
256         this._tabInUse[retentionIndex] = false;
257         if (this._tabViews.length > 2) {
258             // More than two tabs, hide the retention tab, leave the toolbar intact
259             tabBar.setVisible(true);
260             retentionTabButton.setVisible(false);
261         } else {
262             // Two or fewer tabs.  Hide the toolbar, just let the properties view display standalone
263             // (On popup, the display defaults to the property view)
264             tabBar.setVisible(false);
265         }
266     } else {
267         // Using the retention tab view - show the toolbar and all tabs
268         this._tabInUse[retentionIndex] = true;
269         retentionTabButton.setVisible(true);
270         tabBar.setVisible(true);
271     }
272 
273     for (var i = 0; i < this._tabViews.length; i++) {
274         if (this._tabInUse[i]) {
275             // Update all in use tabs to use the specified folder
276             this._tabViews[i]._handleFolderChange(event);
277         }
278     }
279 
280 	if (appCtxt.get(ZmSetting.SHARING_ENABLED))	{
281 		this._populateShares(organizer);
282 	}
283 
284 };
285 
286 ZmFolderPropsDialog.prototype._populateShares =
287 function(organizer) {
288 
289 	this._sharesGroup.setContent("");
290 
291 	var displayShares = this._getDisplayShares(organizer);
292 
293 	var getFolder = false;
294 	if (displayShares.length) {
295 		for (var i = 0; i < displayShares.length; i++) {
296 			var share = displayShares[i];
297 			if (!(share.grantee && share.grantee.name)) {
298 				getFolder = true;
299 			}
300 		}
301 	}
302 
303 	if (getFolder) {
304 		var respCallback = new AjxCallback(this, this._handleResponseGetFolder, [displayShares]);
305 		organizer.getFolder(respCallback);
306 	} else {
307 		this._handleResponseGetFolder(displayShares);
308 	}
309 
310 
311 	this._sharesGroup.setVisible(displayShares.length > 0);
312 };
313 
314 ZmFolderPropsDialog.prototype._getDisplayShares =
315 function(organizer) {
316 
317 	var shares = organizer.shares;
318 	var displayShares = [];
319 	if ((!organizer.link || organizer.isAdmin()) && shares && shares.length > 0) {
320 		AjxDispatcher.require("Share");
321 		var userZid = appCtxt.accountList.mainAccount.id;
322 		// if a folder was shared with us with admin rights, a share is created since we could share it;
323 		// don't show any share that's for us in the list
324 		for (var i = 0; i < shares.length; i++) {
325 			var share = shares[i];
326 			if (share.grantee) {
327 				var granteeId = share.grantee.id;
328 				if ((share.grantee.type != ZmShare.TYPE_USER) || (share.grantee.id != userZid)) {
329 					displayShares.push(share);
330 				}
331 			}
332 		}
333 	}
334 
335 	return displayShares;
336 };
337 
338 ZmFolderPropsDialog.prototype._handleResponseGetFolder =
339 function(displayShares, organizer) {
340 
341 	if (organizer) {
342 		displayShares = this._getDisplayShares(organizer);
343 	}
344 
345 	if (displayShares.length) {
346 		var table = document.createElement("TABLE");
347 		table.className = "ZPropertySheet";
348 		table.cellSpacing = "6";
349 		for (var i = 0; i < displayShares.length; i++) {
350 			var share = displayShares[i];
351 			var row = table.insertRow(-1);
352 			var nameEl = row.insertCell(-1);
353 			nameEl.style.paddingRight = "15px";
354 			var nameText = share.grantee && share.grantee.name;
355 			if (share.isAll()) {
356 				nameText = ZmMsg.shareWithAll;
357 			} else if (share.isPublic()) {
358 				nameText = ZmMsg.shareWithPublic;
359 			} else if (share.isGuest()){
360 				nameText = nameText || (share.grantee && share.grantee.id);
361 			}
362 			nameEl.innerHTML = AjxStringUtil.htmlEncode(nameText);
363 
364 			var roleEl = row.insertCell(-1);
365 			roleEl.style.paddingRight = "15px";
366 			roleEl.innerHTML = ZmShare.getRoleName(share.link.role);
367 
368 			this.__createCmdCells(row, share);
369 		}
370 		this._sharesGroup.setElement(table);
371 
372 		var width = Dwt.DEFAULT;
373 		var height = displayShares.length > 5 ? ZmFolderPropsDialog.SHARES_HEIGHT : Dwt.CLEAR;
374 
375 		var insetElement = this._sharesGroup.getInsetHtmlElement();
376 		Dwt.setScrollStyle(insetElement, Dwt.SCROLL);
377 		Dwt.setSize(insetElement, width, height);
378 	}
379 
380 	this._sharesGroup.setVisible(displayShares.length > 0);
381 };
382 
383 ZmFolderPropsDialog.prototype.__createCmdCells =
384 function(row, share) {
385 	var type = share.grantee.type;
386 	if (type == ZmShare.TYPE_DOMAIN || !share.link.role) {
387 		var cell = row.insertCell(-1);
388 		cell.colSpan = 3;
389 		cell.innerHTML = ZmMsg.configureWithAdmin;
390 		return;
391 	}
392 
393 	var actions = [ZmShare.EDIT, ZmShare.REVOKE, ZmShare.RESEND];
394 	var handlers = [this._handleEditShare, this._handleRevokeShare, this._handleResendShare];
395 
396 	for (var i = 0; i < actions.length; i++) {
397 		var action = actions[i];
398 		var cell = row.insertCell(-1);
399 
400 		// public shares have no editable fields, and sent no mail
401 		var isAllShare = share.grantee && (share.grantee.type == ZmShare.TYPE_ALL);
402         // Fix for bug: 76685. Removed share.isGuest() from the condition and it adds edit cmd link
403 		if (((isAllShare || share.isPublic()) && (action == ZmShare.EDIT)) ||
404             ((isAllShare || share.isPublic()) && action == ZmShare.RESEND)) { continue; }
405 
406 		var link = document.createElement("A");
407 		link.href = "#";
408 		link.innerHTML = ZmShare.ACTION_LABEL[action];
409 
410 		Dwt.setHandler(link, DwtEvent.ONCLICK, handlers[i]);
411 		Dwt.associateElementWithObject(link, share);
412 		this._sharesGroup.getTabGroupMember().addMember(link);
413 
414 		cell.appendChild(link);
415 	}
416 };
417 
418 ZmFolderPropsDialog.prototype.addTab =
419 function(index, id, tabViewPage) {
420 	if (!this._tabContainer || !tabViewPage) { return null; }
421 
422 	this._tabViews[index] = tabViewPage;
423 	this._tabKeys[index]  = this._tabContainer.addTab(tabViewPage.getTitle(), tabViewPage);
424 	this._tabInUse[index] = true;
425 	this._tabKeyMap[id] = index;
426 	return this._tabKeys[index];
427 };
428 
429 ZmFolderPropsDialog.prototype._initializeTabView =
430 function(view) {
431     this._tabContainer = new DwtTabView(view, null, Dwt.STATIC_STYLE);
432 
433 	//ZmFolderPropertyView handle things such as color and type. (in case you're searching for "color" and can't find in this file. I know I did)
434     this.addTab(0, ZmFolderPropsDialog.TABKEY_PROPERTIES, new ZmFolderPropertyView(this, this._tabContainer));
435     this.addTab(1, ZmFolderPropsDialog.TABKEY_RETENTION,  new ZmFolderRetentionView(this, this._tabContainer));
436 
437 	// setup shares group
438 	if (appCtxt.get(ZmSetting.SHARING_ENABLED))	{
439         this._sharesGroup = new DwtGrouper(view, "DwtGrouper ZmFolderPropSharing");
440 		this._sharesGroup.setLabel(ZmMsg.folderSharing);
441 		this._sharesGroup.setVisible(false);
442 		this._sharesGroup.setScrollStyle(Dwt.SCROLL);
443         view.getHtmlElement().appendChild(this._sharesGroup.getHtmlElement());
444 	}
445 };
446 
447 // This creates the tab views managed by this dialog, the tabToolbar, and
448 // the share buttons and view components
449 ZmFolderPropsDialog.prototype._createView =
450 function() {
451     this._baseContainerView = new DwtComposite({parent:this, className:"ZmFolderPropertiesDialog-container "});
452     this._initializeTabView(this._baseContainerView);
453     this.setView(this._baseContainerView);
454 };
455 
456 ZmFolderPropsDialog.prototype._initializeTabGroup = function() {
457 
458 	if (this._sharesGroup) {
459 		this._tabGroup.addMember(this._sharesGroup.getTabGroupMember(), 0);
460 	}
461 	this._tabGroup.addMember(this._tabContainer.getTabGroupMember(), 0);
462 };
463