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 */ 27 28 /** 29 * Creates a new organizer dialog. 30 * @class 31 * This class represents a new organizer dialog. 32 * 33 * @param {DwtControl} parent the parent 34 * @param {String} className the class name 35 * @param {String} title the title 36 * @param {constant} type the organizer type 37 * 38 * @extends ZmDialog 39 */ 40 ZmNewOrganizerDialog = function(parent, className, title, type, extraButtons) { 41 if (arguments.length == 0) return; 42 43 this._organizerType = type; 44 ZmDialog.call(this, {parent:parent, className:className, title:title, id:"CreateNewFolderDialog", extraButtons: extraButtons}); 45 this._setupControls(); 46 }; 47 48 ZmNewOrganizerDialog.prototype = new ZmDialog; 49 ZmNewOrganizerDialog.prototype.constructor = ZmNewOrganizerDialog; 50 51 ZmNewOrganizerDialog.prototype.isZmNewOrganizerDialog = true; 52 ZmNewOrganizerDialog.prototype.toString = function() { return "ZmNewOrganizerDialog"; }; 53 54 //override the following if needed 55 ZmNewOrganizerDialog.prototype._folderLocationLabel = ZmMsg.newFolderParent; 56 ZmNewOrganizerDialog.prototype._folderNameAlreadyExistsMsg = ZmMsg.errorAlreadyExists; 57 58 // Public methods 59 60 /** 61 * Pops-up the dialog. 62 * 63 * @param {ZmOrganizer|hash} params popup parameters 64 * @param {ZmAccount} account the account 65 */ 66 ZmNewOrganizerDialog.prototype.popup = 67 function(params, account) { 68 69 params = params || {}; 70 var folder = params instanceof ZmOrganizer ? params : (params && params.organizer); 71 72 var parentLabelCell = document.getElementById(this._htmlElId + '_parentLabel'); 73 var parentValueCell = document.getElementById(this._htmlElId + '_parentValue'); 74 this._parentFolder = null; 75 76 // if the user has already implicitly selected a parent folder, don't show overview 77 if (folder && folder.id != ZmOrganizer.ID_ROOT) { 78 this._parentFolder = folder; 79 this._makeOverviewVisible(); // hide all overviews 80 if (parentLabelCell) { 81 parentLabelCell.colSpan = 1; 82 parentLabelCell.innerHTML = ZmMsg.parentFolderLabel; 83 parentValueCell.innerHTML = folder.getName(); 84 } 85 } 86 else { 87 if (this._folderTreeCellId) { 88 if (parentLabelCell) { 89 parentLabelCell.innerHTML = this._folderLocationLabel; 90 parentLabelCell.colSpan = 2; 91 parentValueCell.innerHTML = ''; 92 } 93 var overviewParams = { 94 appName: params.appName, 95 overviewId: this.toString() + (params.appName || ""), 96 treeIds: this._treeIds, 97 omit: this._omit, 98 fieldId: this._folderTreeCellId, 99 overviewTrees: [this._organizerType], 100 treeStyle: this._treeStyle 101 }; 102 var overview = this._setOverview(overviewParams); 103 overview.removeAttribute('aria-label'); 104 overview.setAttribute('aria-labelledby', this._htmlElId + '_parentLabel'); 105 106 if (this._folderTreeView) { 107 // bug #18533 - always make sure header item is visible in "New" dialog 108 this._folderTreeView.getHeaderItem().setVisible(true, true); 109 110 if (!folder || this._omit[folder.nId] || folder.nId == ZmOrganizer.ID_ROOT) { 111 folder = appCtxt.getFolderTree().root; //default to root if no folder passed, the folder is omitted from the overview. (I don't get the last option, but it was there so I keep it - it's already root) 112 } 113 var ti = this._folderTreeView.getTreeItemById(folder.id); 114 if (ti) { 115 this._folderTreeView.setSelection(ti, true, null, true); 116 } 117 if (folder.nId == ZmOrganizer.ID_ROOT) { 118 var sid = ZmOrganizer.getSystemId(folder.id); 119 var ti = this._folderTreeView.getTreeItemById(sid); 120 if (ti) { 121 ti.setExpanded(true); 122 } 123 } 124 } 125 } 126 } 127 128 if (this._colorSelect) { 129 var defaultColorCode = ZmOrganizer.DEFAULT_COLOR[this._organizerType], 130 defaultColor = ZmOrganizer.COLOR_VALUES[defaultColorCode], 131 colorMenu = this._colorSelect.getMenu(), 132 moreColorMenu; 133 if(colorMenu) { 134 moreColorMenu = (colorMenu.toString() == "ZmMoreColorMenu") ? colorMenu : colorMenu._getMoreColorMenu(); 135 if(moreColorMenu) moreColorMenu.setDefaultColor(defaultColor); 136 } 137 138 var icon = null; 139 var orgType = this._organizerType; 140 var orgClass = ZmOrganizer.ORG_CLASS[orgType]; 141 if (orgClass) { 142 //to fix bug 55320 - got rid of the calling getIcon on the prototype hack - that caused isRemote to set _isRemote on the prototype thus causing every object to have it by default set. 143 //bug 55491: pass tmp. organizer id to make sure this._isRemote is not true by default. 144 var sample = new window[orgClass]({id:Dwt.getNextId()}); //get a sample object just for the icon 145 icon = sample.getIcon(); 146 } 147 148 this._colorSelect.setImage(icon); 149 this._colorSelect.setValue(ZmOrganizer.DEFAULT_COLOR[orgType]); 150 } 151 152 var ovContainer = appCtxt.multiAccounts && this._opc.getOverviewContainer(this.toString()); 153 if (ovContainer) { 154 if (!folder || (folder && folder.nId == ZmOrganizer.ID_ROOT)) { 155 var acct = account || appCtxt.getActiveAccount(); 156 ovContainer.setSelection(ovContainer.getHeaderItem(acct)); 157 } else { 158 var overviewId = appCtxt.getOverviewId(this.toString(), account); 159 var overview = ovContainer.getOverview(overviewId); 160 var treeView = overview && overview.getTreeView(this._organizerType); 161 if (treeView) { 162 ovContainer.deselectAll(); 163 var ti = treeView.getTreeItemById(folder.id); 164 treeView.setSelection(ti); 165 } 166 } 167 168 ovContainer.expandAccountOnly(account); 169 } 170 171 ZmDialog.prototype.popup.call(this); 172 }; 173 174 /** 175 * Resets the dialog. 176 * 177 * @param {ZmAccount} account the account 178 */ 179 ZmNewOrganizerDialog.prototype.reset = function(account) { 180 181 ZmDialog.prototype.reset.apply(this, arguments); 182 183 if (this._remoteCheckboxField) { 184 this._remoteCheckboxField.checked = false; 185 var urlRow = document.getElementById(this._remoteCheckboxFieldId + "URLrow"); 186 if (urlRow) { 187 urlRow.style.display = "none"; 188 } 189 } 190 191 if (this._urlField) { 192 this._urlField.value = ""; 193 this._urlField.noTab = true; 194 } 195 196 if (appCtxt.multiAccounts) { 197 this._account = account; 198 } else { 199 this._account = null; 200 } 201 }; 202 203 204 // 205 // Protected methods 206 // 207 208 ZmNewOrganizerDialog.prototype._getRemoteLabel = 209 function() { 210 return ZmMsg.subscribeToFeed; 211 }; 212 213 // create html 214 215 ZmNewOrganizerDialog.prototype._contentHtml = 216 function() { 217 var html = []; 218 var idx = 0; 219 html[idx++] = "<table class='ChooserDialog ZPropertySheet' cellspacing='6' >"; 220 idx = this._createStandardContentHtml(html, idx); 221 idx = this._createExtraContentHtml(html, idx); 222 html[idx++] = "</table>"; 223 return html.join(""); 224 }; 225 226 ZmNewOrganizerDialog.prototype._createStandardContentHtml = 227 function(html, idx) { 228 idx = this._createNameContentHtml(html, idx); 229 if (this._organizerType != ZmOrganizer.FOLDER || (this._organizerType == ZmOrganizer.FOLDER && appCtxt.get(ZmSetting.MAIL_FOLDER_COLORS_ENABLED))) { 230 idx = this._createColorContentHtml(html, idx); 231 } 232 return idx; 233 }; 234 235 ZmNewOrganizerDialog.prototype._createNameContentHtml = 236 function(html, idx) { 237 this._nameFieldId = this._htmlElId + "_name"; 238 html[idx++] = AjxTemplate.expand("share.Dialogs#ZmNewOrgDialogName", {id:this._htmlElId}); 239 return idx; 240 }; 241 242 ZmNewOrganizerDialog.prototype._createColorContentHtml = 243 function(html, idx) { 244 this._colorSelectId = this._htmlElId + "_colorSelect"; 245 html[idx++] = AjxTemplate.expand("share.Dialogs#ZmNewOrgDialogColor", {id:this._htmlElId}); 246 return idx; 247 }; 248 249 ZmNewOrganizerDialog.prototype._createExtraContentHtml = 250 function(html, idx) { 251 idx = this._createRemoteContentHtml(html, idx); 252 idx = this._createFolderContentHtml(html, idx); 253 return idx; 254 }; 255 256 ZmNewOrganizerDialog.prototype._createRemoteContentHtml = function(html, idx) { 257 258 this._remoteCheckboxFieldId = this._htmlElId + "_remote"; 259 260 var subs = { 261 id: this._htmlElId, 262 remoteLabel: this._getRemoteLabel() 263 }; 264 html[idx++] = AjxTemplate.expand("share.Dialogs#ZmNewOrgDialogRemote", subs); 265 return idx; 266 }; 267 268 ZmNewOrganizerDialog.prototype._createFolderContentHtml = 269 function(html, idx) { 270 this._folderTreeCellId = this._htmlElId + "_folderTree"; 271 html[idx++] = AjxTemplate.expand("share.Dialogs#ZmNewOrgDialogFolder", {id:this._htmlElId}); 272 return idx; 273 }; 274 275 // setup dwt controls 276 277 ZmNewOrganizerDialog.prototype._setupControls = 278 function() { 279 this._setupStandardControls(); 280 this._setupExtraControls(); 281 }; 282 283 ZmNewOrganizerDialog.prototype._setupStandardControls = 284 function() { 285 this._setupNameControl(); 286 this._setupColorControl(); 287 }; 288 289 ZmNewOrganizerDialog.prototype._setupNameControl = 290 function() { 291 this._setNameField(this._nameFieldId); 292 }; 293 294 ZmNewOrganizerDialog.prototype._setupColorControl = 295 function() { 296 var el = document.getElementById(this._colorSelectId); 297 this._colorSelect = new ZmColorButton({ 298 parent: this, 299 parentElement: el, 300 labelId: this._htmlElId + '_lblColor' 301 }); 302 }; 303 304 ZmNewOrganizerDialog.prototype._setupExtraControls = 305 function() { 306 this._setupRemoteControl(); 307 this._setupFolderControl(); 308 }; 309 310 ZmNewOrganizerDialog.prototype._setupRemoteControl = 311 function() { 312 this._remoteCheckboxField = document.getElementById(this._remoteCheckboxFieldId); 313 if (this._remoteCheckboxField) { 314 this._urlField = document.getElementById(this._remoteCheckboxFieldId + "URLfield"); 315 Dwt.setHandler(this._remoteCheckboxField, DwtEvent.ONCLICK, this._handleCheckbox.bind(this)); 316 } 317 }; 318 319 ZmNewOrganizerDialog.prototype._setupFolderControl = 320 function() { 321 if (!this._folderTreeCellId) { return; } 322 323 this._treeIds = [this._organizerType]; 324 325 this._omit = {}; 326 this._omit[ZmFolder.ID_SPAM] = true; 327 this._omit[ZmFolder.ID_DRAFTS] = true; 328 this._omit[ZmFolder.ID_SYNC_FAILURES] = true; 329 this._omit[ZmFolder.ID_OUTBOX] = true; 330 331 //Bug#68799: no special handling needed for sync issues folder 332 /*var folderTree = appCtxt.getFolderTree(); 333 var syncIssuesFolder = folderTree ? folderTree.getByName(ZmFolder.SYNC_ISSUES) : null; 334 if (syncIssuesFolder) { 335 this._omit[syncIssuesFolder.id] = true; 336 }*/ 337 this._omit[ZmOrganizer.ID_ZIMLET] = true; 338 }; 339 340 // other 341 342 ZmNewOrganizerDialog.prototype._renderOverview = 343 function(overview, treeIds, omit, noRootSelect) { 344 this._setupFolderControl(); // reset in case we changed accounts (family mailbox) 345 ZmDialog.prototype._renderOverview.apply(this, arguments); 346 this._folderTreeView = overview.getTreeView(this._organizerType); 347 }; 348 349 ZmNewOrganizerDialog.prototype._getOverviewOrOverviewContainer = 350 function() { 351 if (appCtxt.multiAccounts) { 352 return this._opc.getOverviewContainer(this.toString()); 353 } 354 return this._opc.getOverview(this._curOverviewId); 355 356 }; 357 358 359 /** 360 * Checks the input for validity and returns the following array of values: 361 * <ul> 362 * <li> parentFolder 363 * <li> name 364 * <li> color 365 * <li> URL 366 * </ul> 367 */ 368 ZmNewOrganizerDialog.prototype._getFolderData = 369 function() { 370 // make sure a parent was selected 371 var ov = this._getOverviewOrOverviewContainer(); 372 373 var parentFolder = this._parentFolder || (ov && ov.getSelected()) || appCtxt.getFolderTree(this._account).root; 374 375 if (this._isGlobalSearch) { 376 //special case for global search (only possible if this is ZmNewSearchDialog 377 parentFolder = appCtxt.getById(ZmOrganizer.ID_ROOT); 378 } 379 380 // check name for presence and validity 381 var name = AjxStringUtil.trim(this._nameField.value); 382 var msg = ZmFolder.checkName(name, parentFolder); 383 384 // make sure parent doesn't already have a child by this name 385 if (!msg && parentFolder.hasChild(name)) { 386 var folderType = appCtxt.getFolderTree(appCtxt.getActiveAccount()).getFolderTypeByName(name); 387 msg = AjxMessageFormat.format(this._folderNameAlreadyExistsMsg, [name,ZmMsg[folderType.toLowerCase()]]); 388 } 389 390 var color = null; 391 if (!msg && this._colorSelectId) { 392 color = this._colorSelect.getValue(); 393 } 394 395 var url = null; 396 if (!msg && this._remoteCheckboxField) { 397 url = this._remoteCheckboxField.checked ? this._urlField.value : null; 398 if (url || url != null) { 399 msg = ZmOrganizer.checkUrl(url); 400 } 401 } 402 403 if (!msg && parentFolder.disallowSubFolder) { 404 msg = AjxMessageFormat.format(ZmMsg.errorSubFolderNotAllowed, parentFolder.name); 405 } 406 407 if (msg) { 408 return this._showError(msg); 409 } 410 411 var account = appCtxt.multiAccounts ? parentFolder.getAccount() : null; 412 var params = {l:parentFolder.id, name:name, color:color, url:url, account:account}; 413 if (String(color).match(/^#/)) { 414 params.rgb = color; 415 delete params.color; 416 } 417 return params; 418 }; 419 420 ZmNewOrganizerDialog.prototype._getTabGroupMembers = 421 function() { 422 var list = [this._nameField]; 423 if (this._colorSelect) { 424 list.push(this._colorSelect); 425 } 426 if (this._remoteCheckboxField) { 427 list.push(this._remoteCheckboxField); 428 if (this._urlField) { 429 list.push(this._urlField); 430 } 431 } 432 if (this._overview[this._curOverviewId]) { 433 list.push(this._overview[this._curOverviewId]); 434 } 435 return list; 436 }; 437 438 // dwt event listeners 439 440 ZmNewOrganizerDialog.prototype._okButtonListener = 441 function(ev) { 442 var results = this._getFolderData(); 443 if (results) { 444 DwtDialog.prototype._buttonListener.call(this, ev, results); 445 } 446 }; 447 448 ZmNewOrganizerDialog.prototype._enterListener = 449 function(ev) { 450 var results = this._getFolderData(); 451 if (results) { 452 this._runEnterCallback(results); 453 } 454 }; 455 456 457 // html event handlers 458 459 ZmNewOrganizerDialog.prototype._handleCheckbox = function(event) { 460 461 event = event || window.event; 462 var target = DwtUiEvent.getTarget(event); 463 var urlRow = document.getElementById(target.id + "URLrow"); 464 urlRow.style.display = target.checked ? (AjxEnv.isIE ? "block" : "table-row") : "none"; 465 if (this._urlField) { 466 if (target.checked) { 467 this._urlField.focus(); 468 } 469 this._urlField.noTab = !target.checked; 470 } 471 }; 472 473 ZmNewOrganizerDialog.prototype.setRemoteURL = 474 function(url) { 475 this._remoteCheckboxField.checked = true; 476 this._urlField.value = url; 477 var urlRow = document.getElementById(this._remoteCheckboxFieldId + "URLrow"); 478 var urlField= document.getElementById(this._remoteCheckboxFieldId + "URLfield"); 479 urlRow.style.display = AjxEnv.isIE ? "block" : "table-row"; 480 481 }; 482