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 share properties dialog. 30 * @class 31 * This class represents a share properties dialog. 32 * 33 * @param {DwtComposite} shell the parent 34 * @param {String} className the class name 35 * 36 * @extends DwtDialog 37 */ 38 ZmSharePropsDialog = function(shell, className) { 39 className = className || "ZmSharePropsDialog"; 40 DwtDialog.call(this, {parent:shell, className:className, title:ZmMsg.shareProperties, id:"ShareDialog"}); 41 this.setButtonListener(DwtDialog.OK_BUTTON, new AjxListener(this, this._handleOkButton)); 42 43 var aifParams = { 44 parent: this, 45 inputId: "ShareDialog_grantee" 46 } 47 48 this._grantee = new ZmAddressInputField(aifParams); 49 this._grantee.setData(Dwt.KEY_OBJECT, this); 50 Dwt.associateElementWithObject(this._grantee, this); 51 52 this._granteeInput = this._grantee.getInputElement(); 53 this._granteeInputId = this._grantee._htmlElId; 54 Dwt.associateElementWithObject(this._granteeInput, this); 55 56 // create auto-completer 57 if (appCtxt.get(ZmSetting.CONTACTS_ENABLED) || appCtxt.get(ZmSetting.GAL_ENABLED)) { 58 var params = { 59 dataClass: appCtxt.getAutocompleter(), 60 options: {massDLComplete:true}, 61 matchValue: ZmAutocomplete.AC_VALUE_EMAIL, 62 keyUpCallback: this._acKeyUpListener.bind(this), 63 contextId: this.toString() 64 }; 65 this._acAddrSelectList = new ZmAutocompleteListView(params); 66 this._acAddrSelectList.handle(this._granteeInput, this._granteeInputId); 67 this._grantee.setAutocompleteListView(this._acAddrSelectList); 68 } 69 70 // set view 71 this.setView(this._createView()); 72 }; 73 74 ZmSharePropsDialog.prototype = new DwtDialog; 75 ZmSharePropsDialog.prototype.constructor = ZmSharePropsDialog; 76 77 ZmSharePropsDialog.prototype.isZmSharePropsDialog = true; 78 ZmSharePropsDialog.prototype.toString = function() { return "ZmSharePropsDialog"; }; 79 80 // Constants 81 82 83 // modes 84 ZmSharePropsDialog.NEW = ZmShare.NEW; 85 ZmSharePropsDialog.EDIT = ZmShare.EDIT; 86 87 // roles 88 ZmSharePropsDialog.SHARE_WITH = [ 'user', 'external', 'public' ]; 89 ZmSharePropsDialog.SHARE_WITH_MSG = { 90 user: ZmMsg.shareWithUserOrGroup, 91 external: ZmMsg.shareWithGuest, 92 'public': ZmMsg.shareWithPublicLong 93 }; 94 ZmSharePropsDialog.SHARE_WITH_TYPE = { 95 user: ZmShare.TYPE_USER, 96 external: ZmShare.TYPE_GUEST, 97 'public': ZmShare.TYPE_PUBLIC 98 }; 99 100 101 // Data 102 103 ZmSharePropsDialog.prototype._mode = ZmSharePropsDialog.NEW; 104 105 106 // Public methods 107 108 109 /** 110 * Pops-up the dialog. 111 * 112 * @param {constant} mode the mode 113 * @param {ZmOrganizer} object the organizer object 114 * @param {ZmShare} share the share 115 */ 116 ZmSharePropsDialog.prototype.popup = 117 function(mode, object, share) { 118 119 this._shareMode = mode; 120 this._object = object; 121 this._share = share; 122 123 this._nameEl.innerHTML = AjxStringUtil.htmlEncode(object.name); 124 this._typeEl.innerHTML = ZmMsg[ZmOrganizer.FOLDER_KEY[this._object.type]] || ZmMsg.folder; 125 // TODO: False until server handling of the flag is added 126 //if (object.type == ZmOrganizer.FOLDER) { 127 if (false) { 128 this._markReadEl.innerHTML = object.globalMarkRead ? ZmMsg.sharingDialogGlobalMarkRead : 129 ZmMsg.sharingDialogPerUserMarkRead; 130 this._props.setPropertyVisible(this._markReadId, true) 131 } else { 132 this._props.setPropertyVisible(this._markReadId, false) 133 } 134 135 var isNewShare = (this._shareMode == ZmSharePropsDialog.NEW); 136 var isUserShare = share ? share.isUser() || share.isGroup() : true; 137 var isGuestShare = share ? share.isGuest() : false; 138 var isPublicShare = share ? share.isPublic() : false; 139 var supportsPublic = object.supportsPublicAccess(); 140 var externalEnabled = appCtxt.get(ZmSetting.SHARING_EXTERNAL_ENABLED); 141 var publicEnabled = appCtxt.get(ZmSetting.SHARING_PUBLIC_ENABLED); 142 143 this._userRadioEl.checked = isUserShare; 144 this._userRadioEl.disabled = !isNewShare; 145 this._guestRadioEl.checked = isGuestShare; 146 this._guestRadioEl.disabled = !(externalEnabled && isNewShare && supportsPublic); 147 this._publicRadioEl.checked = isPublicShare; 148 this._publicRadioEl.disabled = !(publicEnabled && isNewShare && supportsPublic && (object.type !== ZmOrganizer.FOLDER)); 149 150 var type = this._getType(isUserShare, isGuestShare, isPublicShare); 151 this._handleShareWith(type); 152 153 var grantee = "", password = ""; 154 if (share) { 155 if (isGuestShare) { 156 grantee = share.grantee.id; 157 password = share.link.pw; 158 } else { 159 grantee = (share.grantee.name || ZmMsg.userUnknown); 160 password = share.grantee.id; 161 } 162 } 163 this._grantee.clear(); 164 this._grantee.setValue(grantee, true); 165 this._grantee.setEnabled(isNewShare); 166 167 // Make all the properties visible so that their elements are in the 168 // document. Otherwise, we won't be able to get a handle on them to perform 169 // operations. 170 this._props.setPropertyVisible(this._shareWithOptsId, true); 171 //this._shareWithOptsProps.setPropertyVisible(this._passwordId, true); 172 this._props.setPropertyVisible(this._shareWithBreakId, true); 173 174 //this._passwordButton.setVisible(!isNewShare); 175 //this._shareWithOptsProps.setPropertyVisible(this._passwordId, isGuestShare); 176 //this._passwordInput.setValue(password, true); 177 178 if (this._inheritEl) { 179 this._inheritEl.checked = share ? share.link.inh : isNewShare; 180 } 181 182 var perm = share && share.link.perm; 183 184 if (perm != null) { 185 perm = perm.replace(/-./g, ""); 186 this._privateEl.checked = (perm.indexOf(ZmShare.PERM_PRIVATE) != -1); 187 perm = perm.replace(/p/g, ""); 188 var role = ZmShare._getRoleFromPerm(perm); 189 var radioEl = this._radioElByRole[role]; 190 if (radioEl) { 191 radioEl.checked = true; 192 } 193 } 194 195 this._privatePermissionEnabled = object.supportsPrivatePermission(); 196 this._privatePermission.setVisible(object.supportsPrivatePermission()); 197 198 if (perm == null || (perm == this._viewerRadioEl.value)) { 199 this._viewerRadioEl.checked = true; 200 } else if (perm == this._noneRadioEl.value) { 201 this._noneRadioEl.checked = true; 202 } else if (perm == this._managerRadioEl.value) { 203 this._managerRadioEl.checked = true; 204 } else if (perm == this._adminRadioEl.value) { 205 this._adminRadioEl.checked = true; 206 } 207 208 // Force a reply if new share 209 this._reply.setReplyType(ZmShareReply.STANDARD); 210 this._reply.setReplyNote(""); 211 212 this._populateUrls(); 213 214 DwtDialog.prototype.popup.call(this); 215 216 var size = this.getSize(); 217 Dwt.setSize(this._granteeInput, 0.6*size.x); 218 //Dwt.setSize(this._passwordInput.getInputElement(), 0.6*size.x); 219 220 this.setButtonEnabled(DwtDialog.OK_BUTTON, false); 221 if (isNewShare) { 222 this._userRadioEl.checked = true; 223 this._grantee.focus(); 224 } 225 226 if (appCtxt.multiAccounts) { 227 var acct = object.account || appCtxt.accountList.mainAccount; 228 this._acAddrSelectList.setActiveAccount(acct); 229 } 230 }; 231 232 ZmSharePropsDialog.prototype._populateUrls = 233 function() { 234 235 var acct, restUrl; 236 if (appCtxt.multiAccounts) { 237 acct = this._object.getAccount(); 238 restUrl = this._object.getRestUrl(acct); 239 } else { 240 restUrl = this._object.getRestUrl(); 241 } 242 if (appCtxt.isOffline) { 243 var remoteUri = appCtxt.get(ZmSetting.OFFLINE_REMOTE_SERVER_URI, null, acct); 244 restUrl = remoteUri + restUrl.substring((restUrl.indexOf("/",7))); 245 } 246 var url = AjxStringUtil.htmlEncode(restUrl).replace(/&/g,'%26'); 247 var text = url; 248 if (text.length > 50) { 249 var length = text.length - 50; 250 var index = (text.length - length) / 2; 251 text = text.substr(0, index) + "..." + text.substr(index + length); 252 } 253 254 var proto = (location.protocol === ZmSetting.PROTO_HTTPS) ? "webcals:" : "webcal:"; 255 var webcalURL = proto + url.substring((url.indexOf("//"))); 256 var webcalText = webcalURL; 257 if (webcalText.length > 50) { 258 var length = webcalText.length - 50; 259 var index = (webcalText.length - length) / 2; 260 webcalText = webcalText.substr(0, index) + "..." + webcalText.substr(index + length); 261 } 262 263 var isRestFolder = this._object.type != ZmOrganizer.FOLDER; 264 this._urlGroup.setVisible(isRestFolder); 265 if (isRestFolder) { 266 if (this._object.type == ZmOrganizer.CALENDAR) { 267 this._urlEl.innerHTML = [ 268 "<div>", ZmMsg.ics, ": ", 269 '<a target=_new id="SharePropsURL_ICS" href="',url,'.ics">',text,".ics</a>", 270 "</div>", 271 "<div>", ZmMsg.view, ": ", 272 '<a target=_new id="SharePropsURL_view" href="',url,'.html">',text,".html</a>", 273 "</div>", 274 "<div>", ZmMsg.outlookURL, ": ", 275 '<a target=_new id="SharePropsURL_Outlook" href="',webcalURL,'">',webcalText,"</a>", 276 "</div>" 277 ].join(""); 278 } else if (this._object.type == ZmOrganizer.TASKS) { 279 this._urlEl.innerHTML = [ 280 "<div style='padding-left:2em;'>", 281 '<a target=_new id="SharePropsURL" href="',url,'.ics">',text,".ics</a>", 282 "</div>" 283 ].join(""); 284 } else { 285 this._urlEl.innerHTML = [ 286 "<div style='padding-left:2em;'>", 287 '<a target=_new id="SharePropsURL" href="',url,'">',text,"</a>", 288 "</div>" 289 ].join(""); 290 } 291 } 292 }; 293 294 ZmSharePropsDialog.prototype.popdown = 295 function() { 296 if (this._acAddrSelectList) { 297 this._acAddrSelectList.reset(); 298 this._acAddrSelectList.show(false); 299 } 300 DwtDialog.prototype.popdown.call(this); 301 }; 302 303 // Protected methods 304 305 ZmSharePropsDialog.prototype._getType = 306 function(isUserShare, isGuestShare, isPublicShare) { 307 if (arguments.length == 0) { 308 isUserShare = this._userRadioEl.checked; 309 isGuestShare = this._guestRadioEl.checked; 310 isPublicShare = this._publicRadioEl.checked; 311 } 312 return (isUserShare && ZmShare.TYPE_USER) || 313 (isGuestShare && ZmShare.TYPE_GUEST) || 314 (isPublicShare && ZmShare.TYPE_PUBLIC); 315 }; 316 317 ZmSharePropsDialog.prototype._handleChangeButton = 318 function(event) { 319 //this._passwordButton.setVisible(false); 320 //this._passwordInput.setVisible(true); 321 //this._passwordInput.focus(); 322 }; 323 324 ZmSharePropsDialog.prototype._handleOkButton = 325 function(event) { 326 var isUserShare = this._userRadioEl.checked; 327 var isGuestShare = this._guestRadioEl.checked; 328 var isPublicShare = this._publicRadioEl.checked; 329 var shareWithMyself = false; 330 331 var parsedEmailsFromText = AjxEmailAddress.parseEmailString(this._granteeInput.value); 332 var goodEmailsFromText = parsedEmailsFromText.good.getArray(); 333 var goodEmailsFromBubbles = this._grantee.getAddresses(); 334 335 var goodEmails = goodEmailsFromBubbles.concat(goodEmailsFromText); 336 var badEmails = parsedEmailsFromText.bad.getArray(); 337 338 // validate input 339 if (!isPublicShare) { 340 var error; 341 if (badEmails.length) { 342 error = AjxMessageFormat.format(AjxMsg.invalidEmailAddrValue, AjxStringUtil.htmlEncode(this._granteeInput.value)); 343 } 344 else if (!goodEmails.length) { 345 error = AjxMsg.valueIsRequired; 346 } 347 348 if (error) { 349 var dialog = appCtxt.getErrorDialog(); 350 dialog.setMessage(error); 351 dialog.popup(null, true); 352 353 if (!goodEmails.length) { 354 return; 355 } 356 } 357 } 358 359 var replyType = this._reply.getReplyType(); 360 if (replyType != ZmShareReply.NONE) { 361 var notes = (replyType == ZmShareReply.QUICK) ? this._reply.getReplyNote() : ""; 362 } 363 364 var shares = []; 365 if (this._shareMode == ZmSharePropsDialog.NEW) { 366 var type = this._getType(isUserShare, isGuestShare, isPublicShare); 367 if (!isPublicShare) { 368 for (var i = 0; i < goodEmails.length; i++) { 369 // bug fix #26428 - exclude me from list of addresses 370 var addr = goodEmails[i]; 371 //bug#66610: allow Calendar Sharing with addresses present in zimbraAllowFromAddress 372 var allowLocal; 373 var excludeAllowFromAddress = true; 374 if (appCtxt.isMyAddress(addr, allowLocal, excludeAllowFromAddress)) { 375 shareWithMyself = true; 376 continue; 377 } 378 379 var share = this._setUpShare(); 380 share.grantee.name = addr; 381 share.grantee.type = type; 382 shares.push(share); 383 } 384 } else { 385 var share = this._setUpShare(); 386 share.grantee.type = type; 387 shares.push(share); 388 } 389 } else { 390 shares.push(this._setUpShare(this._share)); // editing perms on a share 391 } 392 393 // Since we may be sharing with multiple users, use a batch command 394 var accountName = appCtxt.multiAccounts ? this._object.getAccount().name : null; 395 var batchCmd = new ZmBatchCommand(null, accountName); 396 var perm = this._getPermsFromRole(); 397 //var pw = isGuestShare && this._passwordInput.getValue(); 398 if (shares && shares.length == 0 && shareWithMyself) { 399 var msgDlg = appCtxt.getMsgDialog(true); 400 msgDlg.setMessage(ZmMsg.sharingErrorWithSelf,DwtMessageDialog.INFO_STYLE); 401 msgDlg.setTitle(ZmMsg.sharing); 402 msgDlg.popup(); 403 return; 404 } 405 for (var i = 0; i < shares.length; i++) { 406 var share = shares[i]; 407 if (perm != share.link.perm) { 408 var cmd = new AjxCallback(share, share.grant, 409 [perm, null, notes, 410 replyType, this._shareMode]); 411 batchCmd.add(cmd); 412 } 413 } 414 if (batchCmd.size() > 0) { 415 var respCallback = !isPublicShare 416 ? (new AjxCallback(this, this._handleResponseBatchCmd, [shares])) : null; 417 batchCmd.run(respCallback); 418 } 419 420 this.popdown(); 421 }; 422 423 ZmSharePropsDialog.prototype._handleResponseBatchCmd = 424 function(shares, result) { 425 426 427 var response = result.getResponse(); 428 var batchResponse = response.BatchResponse; 429 430 //bug:67698 Do not send notification on failed share 431 if(batchResponse.Fault){ 432 appCtxt.setStatusMsg(ZmMsg.shareNotCreated,ZmStatusView.LEVEL_WARNING); 433 return false; 434 } 435 else{ 436 if (!shares || (shares && shares.length == 0)) { return; } 437 var ignore = this._getFaultyEmails(result); 438 var replyType = this._reply.getReplyType(); 439 if (replyType != ZmShareReply.NONE) { 440 var notes = (replyType == ZmShareReply.QUICK) ? this._reply.getReplyNote() : ""; 441 var guestnotes; 442 var batchCmd; 443 444 if (shares.length > 1) { 445 var accountName = appCtxt.multiAccounts ? this._object.getAccount().name : null; 446 batchCmd = new ZmBatchCommand(false, accountName, true); 447 } 448 449 for (var i = 0; i < shares.length; i++) { 450 var share = shares[i]; 451 var email = share.grantee.email || share.grantee.id; 452 if (!email) { 453 // last resort: check if grantee name is a valid email address 454 if (AjxEmailAddress.isValid(share.grantee.name)) 455 email = share.grantee.name; 456 } 457 458 if (!email || (email && ignore[email])) { continue; } 459 460 var addrs = new AjxVector(); 461 var addr = new AjxEmailAddress(email, AjxEmailAddress.TO); 462 addrs.add(addr); 463 464 var tmpShare = new ZmShare({object:share.object}); 465 466 tmpShare.grantee.id = share.grantee.id; 467 tmpShare.grantee.email = email; 468 tmpShare.grantee.name = share.grantee.name; 469 470 // REVISIT: What if you have delegated access??? 471 if (tmpShare.object.isRemote()) { 472 tmpShare.grantor.id = tmpShare.object.zid; 473 tmpShare.grantor.email = tmpShare.object.owner; 474 tmpShare.grantor.name = tmpShare.grantor.email; 475 tmpShare.link.id = tmpShare.object.rid; 476 tmpShare.link.name = tmpShare.object.oname || tmpShare.object.name; 477 } else { 478 // bug: 50936 get setting for respective account 479 // to prevent sharing the default account unintentionally 480 tmpShare.grantor.id = appCtxt.get(ZmSetting.USERID, null, this._object.getAccount()); 481 tmpShare.grantor.email = appCtxt.get(ZmSetting.USERNAME, null, this._object.getAccount()); 482 tmpShare.grantor.name = appCtxt.get(ZmSetting.DISPLAY_NAME, null, this._object.getAccount()) || tmpShare.grantor.email; 483 tmpShare.link.id = tmpShare.object.id; 484 tmpShare.link.name = tmpShare.object.name; 485 } 486 // If folder is not synced before sharing, link ID might have changed in ZD. 487 // Always get from response. 488 if(appCtxt.isOffline) { 489 var linkId = this.getLinkIdfromResp(result); 490 if(linkId) { 491 tmpShare.link.id = [tmpShare.grantor.id, linkId].join(":"); 492 } 493 } 494 495 tmpShare.link.perm = share.link.perm; 496 tmpShare.link.view = ZmOrganizer.getViewName(tmpShare.object.type); 497 tmpShare.link.inh = this._inheritEl ? this._inheritEl.checked : true; 498 499 if (this._guestRadioEl.checked) { 500 if (!this._guestFormatter) { 501 this._guestFormatter = new AjxMessageFormat(ZmMsg.shareCalWithGuestNotes); 502 } 503 504 var url = share.object.getRestUrl(); 505 url = url.replace(/&/g,'%26'); 506 if (appCtxt.isOffline) { 507 var remoteUri = appCtxt.get(ZmSetting.OFFLINE_REMOTE_SERVER_URI); 508 url = remoteUri + url.substring((url.indexOf("/",7))); 509 } 510 511 //bug:34647 added webcal url for subscribing to outlook/ical on a click 512 var webcalURL = "webcals:" + url.substring((url.indexOf("//"))); 513 514 //var password = this._passwordInput.getValue(); 515 guestnotes = this._guestFormatter.format([url, webcalURL, email, "", notes]); 516 } 517 tmpShare.notes = guestnotes || notes; 518 519 /* 520 tmpShare.sendMessage(this._shareMode, addrs, null, batchCmd); 521 */ 522 } 523 if (batchCmd) 524 batchCmd.run(); 525 526 var shareMsg = (this._shareMode==ZmSharePropsDialog.NEW)?ZmMsg.shareCreatedSubject:ZmMsg.shareModifiedSubject; 527 appCtxt.setStatusMsg(shareMsg); 528 529 } 530 } 531 }; 532 533 ZmSharePropsDialog.prototype.getLinkIdfromResp = 534 function(result){ 535 536 if (!result) { return; } 537 var resp = result.getResponse().BatchResponse.FolderActionResponse || []; 538 if (resp.length > 0 && resp[0].action) { 539 return resp[0].action.id; 540 } else { 541 return null; 542 } 543 }; 544 545 // HACK: grep the Faults in BatchResponse and sift out the bad emails 546 ZmSharePropsDialog.prototype._getFaultyEmails = 547 function(result) { 548 549 if (!result) { return; } 550 var noSuchAccount = "no such account: "; 551 var bad = {}; 552 var fault = result.getResponse().BatchResponse.Fault || []; 553 for (var i = 0; i < fault.length; i++) { 554 var reason = fault[i].Reason.Text; 555 if (reason.indexOf(noSuchAccount) == 0) { 556 bad[reason.substring(noSuchAccount.length)] = true; 557 } 558 } 559 return bad; 560 }; 561 562 ZmSharePropsDialog.prototype._setUpShare = 563 function(share) { 564 if (!share) { 565 share = new ZmShare({object:this._object}); 566 } 567 share.link.inh = (this._inheritEl && this._inheritEl.checked); 568 569 return share; 570 }; 571 572 ZmSharePropsDialog.prototype._acKeyUpListener = 573 function(event, aclv, result) { 574 ZmSharePropsDialog._enableFieldsOnEdit(this); 575 }; 576 577 ZmSharePropsDialog._handleKeyUp = 578 function(event){ 579 if (DwtInputField._keyUpHdlr(event)) { 580 return ZmSharePropsDialog._handleEdit(event); 581 } 582 return false; 583 }; 584 585 ZmSharePropsDialog._handleEdit = 586 function(event) { 587 var target = DwtUiEvent.getTarget(event); 588 var dialog = Dwt.getObjectFromElement(target); 589 if (dialog instanceof DwtInputField) { 590 dialog = dialog.getData(Dwt.KEY_OBJECT); 591 } 592 if (dialog != null) { 593 ZmSharePropsDialog._enableFieldsOnEdit(dialog); 594 } 595 return true; 596 }; 597 598 ZmSharePropsDialog._enableFieldsOnEdit = 599 function(dialog) { 600 var isEdit = dialog._mode == ZmSharePropsDialog.EDIT; 601 602 var isUserShare = dialog._userRadioEl.checked; 603 var isPublicShare = dialog._publicRadioEl.checked; 604 var isGuestShare = dialog._guestRadioEl.checked; 605 606 dialog._privatePermission.setVisible(dialog._privatePermissionEnabled && !dialog._noneRadioEl.checked && !isPublicShare); 607 if (isPublicShare) { 608 // Remove private permissions (which may have been set earlier) if the share is a public share 609 dialog._privateEl.checked = false; 610 } 611 612 var hasEmail = AjxStringUtil.trim(dialog._grantee.getValue()) != ""; 613 //var hasPassword = AjxStringUtil.trim(dialog._passwordInput.getValue()) != ""; 614 615 var enabled = isEdit || 616 isPublicShare || 617 (isUserShare && hasEmail) || 618 (isGuestShare && hasEmail); 619 dialog.setButtonEnabled(DwtDialog.OK_BUTTON, enabled); 620 }; 621 622 ZmSharePropsDialog._handleShareWith = 623 function(event) { 624 var target = DwtUiEvent.getTarget(event); 625 var dialog = Dwt.getObjectFromElement(target); 626 dialog._handleShareWith(target.value); 627 628 return ZmSharePropsDialog._handleEdit(event); 629 }; 630 631 ZmSharePropsDialog.prototype._handleShareWith = function(type) { 632 var isUserShare = type == ZmShare.TYPE_USER; 633 var isGuestShare = type == ZmShare.TYPE_GUEST; 634 var isPublicShare = type == ZmShare.TYPE_PUBLIC; 635 636 // TODO - Currently external sharing is enabled for briefcase only. 637 var guestRadioLabelEl = document.getElementById("LblShareWith_external"); 638 639 if (appCtxt.getCurrentApp().getName() === ZmId.APP_BRIEFCASE) { 640 this._rolesGroup.setVisible(isUserShare || isGuestShare); 641 guestRadioLabelEl.innerHTML = ZmMsg.shareWithExternalGuest; 642 } 643 else { 644 this._rolesGroup.setVisible(isUserShare); 645 guestRadioLabelEl.innerHTML = ZmMsg.shareWithGuest; 646 } 647 this._messageGroup.setVisible(!isPublicShare); 648 this._privatePermission.setVisible(this._privatePermissionEnabled && !isPublicShare); 649 650 var adminRadioRow = document.getElementById("ShareRole_Row_" + ZmShare.ROLE_ADMIN); 651 652 if (isGuestShare) { 653 this._reply && this._reply.setReplyOptions(ZmShareReply.EXTERNAL_USER_OPTIONS); 654 adminRadioRow.style.display = 'none'; 655 } 656 else { 657 this._reply && this._reply.setReplyOptions(ZmShareReply.DEFAULT_OPTIONS); 658 this._reply.setReplyType(ZmShareReply.STANDARD); 659 adminRadioRow.style.display = ''; 660 } 661 this._props.setPropertyVisible(this._shareWithOptsId, !isPublicShare); 662 //this._shareWithOptsProps.setPropertyVisible(this._passwordId, isGuestShare); 663 this._props.setPropertyVisible(this._shareWithBreakId, !isPublicShare); 664 this._setAutoComplete(isGuestShare); 665 666 if (!isUserShare) { 667 this._viewerRadioEl.checked = true; 668 } 669 }; 670 671 /** 672 * Returns a perms string based on the user's selection of a role and privacy. 673 */ 674 ZmSharePropsDialog.prototype._getPermsFromRole = 675 function() { 676 var role = ZmShare.ROLE_NONE; 677 if (this._viewerRadioEl.checked) { 678 role = ZmShare.ROLE_VIEWER; 679 } 680 if (this._managerRadioEl.checked) { 681 role = ZmShare.ROLE_MANAGER; 682 } 683 if (this._adminRadioEl.checked) { 684 role = ZmShare.ROLE_ADMIN; 685 } 686 var perm = ZmShare.ROLE_PERMS[role]; 687 if (perm && this._privatePermissionEnabled && this._privateEl.checked) { 688 perm += ZmShare.PERM_PRIVATE; 689 } 690 return perm; 691 }; 692 693 ZmSharePropsDialog.prototype._createView = function() { 694 695 var view = new DwtComposite(this); 696 697 // ids 698 var nameId = Dwt.getNextId(); 699 var markReadValueId = Dwt.getNextId(); 700 var typeId = Dwt.getNextId(); 701 var granteeId = Dwt.getNextId(); 702 var inheritId = Dwt.getNextId(); 703 var urlId = Dwt.getNextId(); 704 var permissionId = Dwt.getNextId(); 705 706 var shareWithRadioName = this._htmlElId + "_shareWith"; 707 var shareWith = new DwtPropertySheet(this, null, null, DwtPropertySheet.RIGHT); 708 var shareWithProperties = [], sw, label, value, swRadioId; 709 for (var i = 0; i < ZmSharePropsDialog.SHARE_WITH.length; i++) { 710 sw = ZmSharePropsDialog.SHARE_WITH[i]; 711 swRadioId = "ShareWith_" + sw; 712 label = "<label id='LblShareWith_" + sw + "'for='" + swRadioId + "'>" + ZmSharePropsDialog.SHARE_WITH_MSG[sw] + "</label>"; 713 value = "<input type='radio' id='" + swRadioId + "' name='" + shareWithRadioName + "' value='" + ZmSharePropsDialog.SHARE_WITH_TYPE[sw] + "'>"; 714 shareWith.addProperty(label, value); 715 } 716 717 this._shareWithOptsProps = new DwtPropertySheet(this); 718 this._shareWithOptsProps.addProperty(ZmMsg.emailLabel, this._grantee); 719 720 var otherHtml = [ 721 "<table class='ZCheckboxTable'>", 722 "<tr>", 723 "<td>", 724 "<input type='checkbox' id='",inheritId,"' checked>", 725 "</td>", 726 "<td>","<label for='", inheritId, "'>" , ZmMsg.inheritPerms, "</label>", "</td>", 727 "</tr>", 728 "</table>" 729 ].join(""); 730 731 this._props = new DwtPropertySheet(view); 732 this._props.addProperty(ZmMsg.nameLabel, "<span id='" + nameId + "'></span>"); 733 this._props.addProperty(ZmMsg.typeLabel, "<span id='" + typeId + "'></span>"); 734 this._markReadId = this._props.addProperty(ZmMsg.sharingDialogMarkReadLabel, "<span id='" + markReadValueId + "'></span>"); 735 var shareWithId = this._props.addProperty(ZmMsg.shareWithLabel, shareWith); 736 var otherId = this._props.addProperty(ZmMsg.otherLabel, otherHtml); 737 738 // Accessibility: set aria-labelledby for each radio button to two IDs, one is the group label, other is label for that button 739 var shareWithLabelId = this._props.getProperty(shareWithId).labelId, 740 radioId, radioEl; 741 for (var i = 0; i < ZmSharePropsDialog.SHARE_WITH.length; i++) { 742 sw = ZmSharePropsDialog.SHARE_WITH[i]; 743 radioId = 'ShareWith_' + sw; 744 radioEl = document.getElementById(radioId); 745 if (radioEl) { 746 radioEl.setAttribute('aria-labelledby', [ shareWithLabelId, 'LblShareWith_' + sw ].join(' ')); 747 } 748 } 749 750 this._inheritEl = document.getElementById(inheritId); 751 752 // XXX: for now, we are hiding this property for simplicity's sake 753 this._props.setPropertyVisible(otherId, false); 754 this._shareWithBreakId = this._props.addProperty("", "<HR>"); 755 this._shareWithOptsId = this._props.addProperty("", this._shareWithOptsProps); 756 757 // add role group 758 var idx = 0; 759 var html = []; 760 html[idx++] = "<table class='ZRadioButtonTable'>"; 761 762 this._rolesGroup = new DwtGrouper(view); 763 764 var roleRadioName = this._htmlElId + "_role"; 765 var roles = [ZmShare.ROLE_NONE, ZmShare.ROLE_VIEWER, ZmShare.ROLE_MANAGER, ZmShare.ROLE_ADMIN]; 766 for (var i = 0; i < roles.length; i++) { 767 var role = roles[i], 768 rowId = 'ShareRole_Row_' + role, 769 radioId = 'ShareRole_' + role, 770 labelId = 'LblShareRole_' + role, 771 legendId = this._rolesGroup._labelEl.id, 772 labelledBy = [ legendId, labelId ].join(' '); 773 774 html[idx++] = "<tr id='" + rowId + "'>"; 775 html[idx++] = "<td style='padding-left:10px; vertical-align:top;'>"; 776 html[idx++] = "<input type='radio' name='" + roleRadioName + "' value='" + role + "' id='" + radioId + "' aria-labelledby='" + labelledBy + "'>"; 777 html[idx++] = "</td>"; 778 html[idx++] = "<td style='font-weight:bold; padding:0 0.5em 0 .25em;'>"; 779 html[idx++] = "<label id='" + labelId + "' for='"+radioId+"' >"; 780 html[idx++] = ZmShare.getRoleName(role); 781 html[idx++] = "</label>" 782 html[idx++] = "</td>"; 783 html[idx++] = "<td style='white-space:nowrap'>"; 784 html[idx++] = ZmShare.getRoleActions(role); 785 html[idx++] = "</td></tr>"; 786 } 787 788 html[idx++] = "</table>"; 789 790 this._rolesGroup.setLabel(ZmMsg.role); 791 this._rolesGroup.setContent(html.join("")); 792 793 this._privatePermission = new DwtPropertySheet(view); 794 this._privatePermission._vAlign = "middle"; 795 this._privatePermission.addProperty("<input type='checkbox' id='" + permissionId + "'/>", "<label for='" + permissionId + "' >" + ZmMsg.privatePermission + "</label>"); 796 this._privateEl = document.getElementById(permissionId); 797 Dwt.setHandler(this._privateEl, DwtEvent.ONCLICK, ZmSharePropsDialog._handleEdit); 798 Dwt.associateElementWithObject(this._privateEl, this); 799 800 // add message group 801 this._messageGroup = new DwtGrouper(view); 802 this._messageGroup.setLabel(ZmMsg.message); 803 this._reply = new ZmShareReply({ 804 parent: view, 805 legendId: this._messageGroup._labelEl.id 806 }); 807 this._messageGroup.setView(this._reply); 808 809 // add url group 810 var urlHtml = [ 811 "<div>", 812 "<div style='margin-bottom:.25em'>",ZmMsg.shareUrlInfo,"</div>", 813 "<div style='cursor:text' id='",urlId,"'></div>", 814 "</div>" 815 ].join(""); 816 817 this._urlGroup = new DwtGrouper(view); 818 this._urlGroup.setLabel(ZmMsg.url); 819 this._urlGroup.setContent(urlHtml); 820 this._urlGroup._setAllowSelection(); 821 822 // save information elements 823 this._nameEl = document.getElementById(nameId); 824 this._typeEl = document.getElementById(typeId); 825 this._markReadEl = document.getElementById(markReadValueId); 826 this._urlEl = document.getElementById(urlId); 827 828 this._setAutoComplete(); 829 830 // add change handlers 831 if (this._inheritEl) { 832 Dwt.setHandler(this._inheritEl, DwtEvent.ONCLICK, ZmSharePropsDialog._handleEdit); 833 Dwt.associateElementWithObject(this._inheritEl, this); 834 } 835 836 var radios = ["_userRadioEl", "_guestRadioEl", "_publicRadioEl"]; 837 var radioEls = document.getElementsByName(shareWithRadioName); 838 for (var i = 0; i < radioEls.length; i++) { 839 this[radios[i]] = radioEls[i]; 840 Dwt.setHandler(radioEls[i], DwtEvent.ONCLICK, ZmSharePropsDialog._handleShareWith); 841 Dwt.associateElementWithObject(radioEls[i], this); 842 } 843 844 radios = ["_noneRadioEl", "_viewerRadioEl", "_managerRadioEl", "_adminRadioEl"]; 845 radioEls = document.getElementsByName(roleRadioName); 846 roles = [ZmShare.ROLE_NONE, ZmShare.ROLE_VIEWER, ZmShare.ROLE_MANAGER, ZmShare.ROLE_ADMIN]; 847 this._radioElByRole = {}; 848 for (var i = 0; i < radioEls.length; i++) { 849 this[radios[i]] = radioEls[i]; 850 this._radioElByRole[roles[i]] = radioEls[i]; 851 Dwt.setHandler(radioEls[i], DwtEvent.ONCLICK, ZmSharePropsDialog._handleEdit); 852 Dwt.associateElementWithObject(radioEls[i], this); 853 } 854 855 this._tabGroup.addMember(shareWith.getTabGroupMember()); 856 this._tabGroup.addMember(this._grantee); 857 this._tabGroup.addMember(this._rolesGroup.getTabGroupMember()); 858 this._tabGroup.addMember(this._messageGroup.getTabGroupMember()); 859 this._tabGroup.addMember(this._urlGroup.getTabGroupMember()); 860 this._tabGroup.addMember(this._reply.getTabGroupMember()); 861 862 return view; 863 }; 864 865 ZmSharePropsDialog.prototype._setAutoComplete = 866 function(disabled) { 867 if (!disabled && this._acAddrSelectList) { 868 this._acAddrSelectList.handle(this._granteeInput); 869 } 870 else { 871 Dwt.setHandler(this._granteeInput, DwtEvent.ONKEYUP, ZmSharePropsDialog._handleKeyUp); 872 } 873 }; 874