1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013, 2014, 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, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  * This file defines the search tree controller.
 27  *
 28  */
 29 
 30 /**
 31  * Creates a search tree controller.
 32  * @class
 33  * This class controls a tree display of saved searches.
 34  *
 35  * @author Conrad Damon
 36  * 
 37  * @extends		ZmFolderTreeController
 38  */
 39 ZmSearchTreeController = function() {
 40 
 41 	ZmFolderTreeController.call(this, ZmOrganizer.SEARCH);
 42 
 43 	this._listeners[ZmOperation.RENAME_SEARCH] = this._renameListener.bind(this);
 44 };
 45 
 46 ZmSearchTreeController.prototype = new ZmFolderTreeController;
 47 ZmSearchTreeController.prototype.constructor = ZmSearchTreeController;
 48 
 49 ZmSearchTreeController.prototype.isZmSearchTreeController = true;
 50 ZmSearchTreeController.prototype.toString = function() { return "ZmSearchTreeController"; };
 51 
 52 ZmSearchTreeController.APP_JOIN_CHAR = "-";
 53 
 54 // Public methods
 55 
 56 /**
 57  * Shows the tree of this type.
 58  *
 59  * @param	{Hash}	params		a hash of parameters
 60  * @param	{String}	params.overviewId		the overview ID
 61  * @param	{Boolean}	params.showUnread		if <code>true</code>, unread counts will be shown
 62  * @param	{Array}	params.omit				a hash of organizer IDs to ignore
 63  * @param	{Boolean}	params.forceCreate	if <code>true</code>, tree view will be created
 64  * @param	{ZmZimbraAccount}	params.account	the account to show tree for (if not currently active account)
 65  * 
 66  */
 67 ZmSearchTreeController.prototype.show =
 68 function(params) {
 69 	var id = params.overviewId;
 70 	if (!this._treeView[id] || params.forceCreate) {
 71 		this._treeView[id] = this._setup(id);
 72 	}
 73     var dataTree = this.getDataTree(params.account);
 74     if (dataTree) {
 75 		params.dataTree = dataTree;
 76 		params.searchTypes = {};
 77 		params.omit = params.omit || {};
 78 		params.omit[ZmFolder.ID_TRASH] = true;
 79 		params.omitParents = true;
 80 		var setting = ZmOrganizer.OPEN_SETTING[this.type];
 81 		params.collapsed = !(!setting || (appCtxt.get(setting, null, params.account) !== false));
 82 		var overview = this._opc.getOverview(id);
 83 		if (overview && overview.showNewButtons)
 84 			this._setupOptButton(params);
 85 		this._treeView[id].set(params);
 86 		this._checkTreeView(id);
 87 	}
 88 	
 89 	return this._treeView[id];
 90 };
 91 
 92 /**
 93  * Gets the tree style.
 94  * 
 95  * @return	{Object}	the tree style or <code>null</code> if not set
 96  */
 97 ZmSearchTreeController.prototype.getTreeStyle =
 98 function() {
 99 	return null;
100 };
101 
102 /**
103 * Resets and enables/disables operations based on context.
104 *
105 * @param {ZmControl}	parent		the widget that contains the operations
106 * @param {constant}	type		the type
107 * @param {String}	id			the currently selected/activated organizer
108 */
109 ZmSearchTreeController.prototype.resetOperations =
110 function(parent, type, id) {
111 	parent.enableAll(true);
112 	var search = appCtxt.getById(id);
113 	parent.enable(ZmOperation.EXPAND_ALL, (search.size() > 0));
114 };
115 
116 
117 
118 // Private methods
119 
120 /**
121  * Returns ops available for "Searches" container.
122  * 
123  * @private
124  */
125 ZmSearchTreeController.prototype._getHeaderActionMenuOps =
126 function() {
127 	return [ZmOperation.EXPAND_ALL];
128 };
129 
130 /**
131  * Returns ops available for saved searches.
132  * 
133  * @private
134  */
135 ZmSearchTreeController.prototype._getActionMenuOps =
136 function() {
137 
138 	return [
139 		ZmOperation.MOVE,
140 		ZmOperation.DELETE_WITHOUT_SHORTCUT,
141 		ZmOperation.RENAME_SEARCH,
142 		ZmOperation.EDIT_PROPS,
143 		ZmOperation.OPEN_IN_TAB,
144 		ZmOperation.EXPAND_ALL
145 	];
146 };
147 
148 /**
149  * override the ZmFolderTreeController override.
150  * 
151  * @private
152  */
153 ZmSearchTreeController.prototype._getAllowedSubTypes =
154 function() {
155 	return ZmTreeController.prototype._getAllowedSubTypes.call(this);
156 };
157 
158 /**
159  * Returns a "New Saved Search" dialog.
160  * 
161  * @private
162  */
163 ZmSearchTreeController.prototype._getNewDialog =
164 function() {
165 	return appCtxt.getNewSearchDialog();
166 };
167 
168 /**
169  * Called when a left click occurs (by the tree view listener). The saved
170  * search will be run.
171  *
172  * @param {ZmSearchFolder}		searchFolder		the search that was clicked
173  * 
174  * @private
175  */
176 ZmSearchTreeController.prototype._itemClicked = function(searchFolder, openInTab) {
177 
178 	if (searchFolder._showFoldersCallback) {
179 		searchFolder._showFoldersCallback.run();
180 		return;
181 	}
182 
183 	appCtxt.getSearchController().redoSearch(searchFolder.search, false, {
184 		getHtml:        appCtxt.get(ZmSetting.VIEW_AS_HTML),
185 		userInitiated:  openInTab,
186 		origin:         ZmId.SEARCH
187 	});
188 };
189 
190 // Miscellaneous
191 
192 /**
193  * Returns a title for moving a saved search.
194  * 
195  * @private
196  */
197 ZmSearchTreeController.prototype._getMoveDialogTitle =
198 function() {
199 	return AjxMessageFormat.format(ZmMsg.moveSearch, this._pendingActionData.name);
200 };
201 
202 /**
203  * Shows or hides the tree view. It is hidden only if there are no saved
204  * searches that belong to the owning app, and we have been told to hide empty
205  * tree views of this type.
206  * 
207  * @param {constant}	overviewId		the overview ID
208  * 
209  * @private
210  */
211 ZmSearchTreeController.prototype._checkTreeView =
212 function(overviewId) {
213 	var treeView = this._treeView[overviewId];
214 	if (!overviewId || !treeView) { return; }
215 
216 	var account = this._opc.getOverview(overviewId).account;
217 	var rootId = (appCtxt.multiAccounts && !account.isMain)
218 		? (ZmOrganizer.getSystemId(ZmOrganizer.ID_ROOT, account))
219 		: ZmOrganizer.ID_ROOT;
220 	var hide = ZmOrganizer.HIDE_EMPTY[this.type] && !treeView.getTreeItemById(rootId).getItemCount();
221 	this._treeView[overviewId].setVisible(!hide);
222 };
223