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 * This file contains a dialog. 27 * 28 */ 29 30 /** 31 * Creates a dialog. 32 * @class 33 * This class is a base class for miscellaneous organizer-related dialogs. An instance 34 * of this class can be re-used to show different overviews. 35 * 36 * @author Conrad Damon 37 * 38 * @param {Hash} params a hash of parameters 39 * @param {DwtControl} params.parent the parent widget 40 * @param {DwtMsgDialog} params.msgDialog the message dialog 41 * @param {String} params.className the CSS class name 42 * @param {String} params.title the dialog title 43 * @param {Array|constant} params.standardButtons an array of standard buttons to include. Defaults to {@link DwtDialog.OK_BUTTON} and {@link DwtDialog.CANCEL_BUTTON}. 44 * @param {Array} params.extraButtons a list of {@link DwtDialog_ButtonDescriptor} objects describing custom buttons to add to the dialog 45 * @param {DwtControl} params.view the dialog contents 46 * 47 * @extends DwtDialog 48 */ 49 ZmDialog = function(params) { 50 if (arguments.length == 0) { return; } 51 52 DwtDialog.call(this, params); 53 54 if (!params.view) { 55 this.setContent(this._contentHtml()); 56 } 57 58 if (this._button[DwtDialog.OK_BUTTON]) { 59 this.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._okButtonListener)); 60 } 61 62 this._overview = {}; 63 this._opc = appCtxt.getOverviewController(); 64 65 this._baseTabGroupSize = this._tabGroup.size(); 66 }; 67 68 ZmDialog.prototype = new DwtDialog; 69 ZmDialog.prototype.constructor = ZmDialog; 70 71 ZmDialog.prototype.isZmDialog = true; 72 ZmDialog.prototype.toString = function() { return "ZmDialog"; }; 73 74 /** 75 * @private 76 */ 77 ZmDialog.prototype._contentHtml = 78 function() { 79 return ""; 80 }; 81 82 /** 83 * Sets the view for this dialog. 84 * 85 * @param {DwtComposite} newView the view 86 * @param {Boolean} noReset if <code>true</code>, do not reset the dialog; <code>false</code> otherwise 87 */ 88 ZmDialog.prototype.setView = 89 function(newView, noReset) { 90 this.reset(); 91 if (newView) { 92 var contentDiv = this._getContentDiv(); 93 var el = newView.getHtmlElement(); 94 contentDiv.parentNode.replaceChild(el, contentDiv); 95 this._contentDiv = el; 96 } 97 }; 98 99 ZmDialog.prototype.popup = 100 function() { 101 // Bug 38281: for multiuse dialogs, we need to re-add the discretionary 102 // tab stops to the base list (the dialog buttons) 103 this._tabGroup.__members._array.splice(this._baseTabGroupSize); 104 this._tabGroup.addMember(this._getTabGroupMembers()); 105 106 DwtDialog.prototype.popup.call(this); 107 if (this._focusElement) { 108 appCtxt.getKeyboardMgr().grabFocus(this._focusElement); 109 } 110 }; 111 112 ZmDialog.prototype.reset = 113 function() { 114 if (this._nameField) { 115 this._nameField.value = ""; 116 } 117 DwtDialog.prototype.reset.call(this); 118 }; 119 120 /** 121 * @private 122 */ 123 ZmDialog.prototype._okButtonListener = 124 function() { 125 this.popdown(); 126 }; 127 128 /** 129 * @private 130 */ 131 ZmDialog.prototype._setNameField = 132 function(fieldId) { 133 this._nameField = this._focusElement = document.getElementById(fieldId); 134 if (this._enterListener) { 135 this.addEnterListener(new AjxListener(this, this._enterListener)); 136 } 137 }; 138 139 /** 140 * Displays the given list of tree views in an overview, creating it if 141 * necessary, and appends the overview to an element in the dialog. Since 142 * dialogs may be reused, it is possible that it will display different 143 * overviews. That is handled by making sure that only the current overview is 144 * visible. 145 * 146 * @param params [hash] hash of params: 147 * treeIds [array] list of tree views to show 148 * omit [hash] IDs of organizers to exclude 149 * fieldId [string] DOM ID of element that contains overview 150 * overviewId [string]* ID for the overview 151 * noRootSelect [boolean]* if true, don't make root tree item(s) selectable 152 * @param forceSingle [boolean]* if true, don't make multi-account overviews 153 * @private 154 */ 155 ZmDialog.prototype._setOverview = 156 function(params, forceSingle) { 157 158 // when in multi-account mode, hide the old overview since we don't know 159 // whether we want to show an overview container or just a single-account overview. 160 if (appCtxt.multiAccounts) { 161 var oldOverview = this._opc.getOverviewContainer(this._curOverviewId) || 162 this._opc.getOverview(this._curOverviewId); 163 164 if (oldOverview) { 165 oldOverview.setVisible(false); 166 } 167 } 168 169 // multi-account uses overview container 170 if (appCtxt.multiAccounts && !forceSingle) { 171 // use overviewId as the containerId; container will assign overviewId's 172 var containerId = this._curOverviewId = params.overviewId; 173 var ovContainer = this._opc.getOverviewContainer(containerId); 174 if (!ovContainer) { 175 var overviewParams = { 176 overviewClass: "dialogOverviewContainer", 177 headerClass: "DwtTreeItem", 178 noTooltips: true, 179 treeStyle: params.treeStyle, 180 treeIds: params.treeIds, 181 overviewTrees: params.overviewTrees, 182 omit: params.omit, 183 omitPerAcct: params.omitPerAcct, 184 selectable: params.selectable 185 }; 186 var containerParams = { 187 appName: params.appName, 188 containerId: containerId 189 }; 190 ovContainer = this._opc.createOverviewContainer(containerParams, overviewParams); 191 ovContainer.setSize(Dwt.DEFAULT, "200"); 192 document.getElementById(params.fieldId).appendChild(ovContainer.getHtmlElement()); 193 } 194 195 // make overview container visible 196 ovContainer.setVisible(true); 197 198 return ovContainer; 199 } 200 201 // single-account overview handling 202 var overviewId = this._curOverviewId = params.overviewId; 203 var overview = this._opc.getOverview(overviewId); 204 if (!overview) { 205 var ovParams = { 206 overviewId: overviewId, 207 overviewClass: params.overviewClass || "dialogOverview", 208 headerClass: "DwtTreeItem", 209 noTooltips: true, 210 treeStyle: params.treeStyle, 211 dynamicWidth: params.dynamicWidth, 212 treeIds: params.treeIds, 213 account: ((appCtxt.multiAccounts && params.forceSingle) ? appCtxt.getActiveAccount() : (params.account || appCtxt.getActiveAccount())), 214 skipImplicit: true, 215 appName: params.appName 216 }; 217 overview = this._overview[overviewId] = this._opc.createOverview(ovParams); 218 this._renderOverview(overview, params.treeIds, params.omit, params.noRootSelect); 219 document.getElementById(params.fieldId).appendChild(overview.getHtmlElement()); 220 } 221 else { 222 //this might change between clients so have to update this. 223 this._setRootSelection(overview, params.treeIds, params.noRootSelect); 224 } 225 226 this._makeOverviewVisible(overviewId); 227 228 return overview; 229 }; 230 231 /** 232 * @private 233 */ 234 ZmDialog.prototype._makeOverviewVisible = 235 function(overviewId) { 236 for (var id in this._overview) { 237 this._overview[id].setVisible(id == overviewId); 238 } 239 }; 240 241 /** 242 * Renders the tree views in the overview, and makes the header items 243 * selectable (since they can generally be targets of whatever action the dialog 244 * is facilitating). 245 * 246 * @param overview [ZmOverview] the overview 247 * @param treeIds [array] list of tree views to show 248 * @param omit [hash]* IDs of organizers to exclude 249 * @param noRootSelect [boolean]* if true, don't make root tree item(s) selectable 250 * @private 251 */ 252 ZmDialog.prototype._renderOverview = 253 function(overview, treeIds, omit, noRootSelect) { 254 overview.set(treeIds, omit); 255 this._setRootSelection(overview, treeIds, noRootSelect); 256 }; 257 258 ZmDialog.prototype._setRootSelection = 259 function(overview, treeIds, noRootSelect) { 260 for (var i = 0; i < treeIds.length; i++) { 261 var treeView = overview.getTreeView(treeIds[i]); 262 var hi = treeView && treeView.getHeaderItem(); 263 if (hi) { 264 hi.enableSelection(!noRootSelect); 265 } 266 } 267 }; 268 269 270 /** 271 * @private 272 */ 273 ZmDialog.prototype._getOverview = 274 function() { 275 return this._overview[this._curOverviewId]; 276 }; 277 278 /** 279 * @private 280 */ 281 ZmDialog.prototype._getInputFields = 282 function() { 283 return (this._nameField) ? [this._nameField] : null; 284 }; 285 286 /** 287 * @private 288 */ 289 ZmDialog.prototype._showError = 290 function(msg, loc) { 291 var nLoc = loc || (new DwtPoint(this.getLocation().x + 50, this.getLocation().y + 100)); 292 var msgDialog = appCtxt.getMsgDialog(); 293 294 msgDialog.reset(); 295 msgDialog.setMessage(AjxStringUtil.htmlEncode(msg), DwtMessageDialog.CRITICAL_STYLE); 296 msgDialog.popup(nLoc); 297 }; 298 299 /** 300 * @private 301 */ 302 ZmDialog.prototype._getTabGroupMembers = 303 function() { 304 return this._nameField ? [ this._nameField ] : []; 305 }; 306