1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2010, 2011, 2012, 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) 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * Creates a preferences page for displaying notifications. 26 * 27 * @param {DwtControl} parent the containing widget 28 * @param {Object} section the page 29 * @param {ZmPrefController} controller the prefs controller 30 * 31 * @extends ZmPreferencesPage 32 */ 33 ZmNotificationsPage = function(parent, section, controller) { 34 if (arguments.length == 0) return; 35 ZmPreferencesPage.apply(this, arguments); 36 }; 37 ZmNotificationsPage.prototype = new ZmPreferencesPage; 38 ZmNotificationsPage.prototype.constructor = ZmNotificationsPage; 39 40 ZmNotificationsPage.prototype.toString = function() { 41 return "ZmNotificationsPage"; 42 }; 43 44 // 45 // Constants 46 // 47 48 // device email data 49 50 ZmNotificationsPage.REGIONS = {}; 51 ZmNotificationsPage.CARRIERS = {}; 52 53 // 54 // DwtControl methods 55 // 56 57 ZmNotificationsPage.prototype.getTabGroupMember = function() { 58 return this._form.getTabGroupMember(); 59 }; 60 61 ZmNotificationsPage.prototype._getValidatedDevice = function() { 62 var acct = appCtxt.multiAccounts && appCtxt.getActiveAccount(); 63 return appCtxt.get(ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ADDRESS, null, acct); 64 }; 65 66 ZmNotificationsPage.prototype._getEmailAddress = function() { 67 var acct = appCtxt.multiAccounts && appCtxt.getActiveAccount(); 68 return appCtxt.get(ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS, null, acct); 69 }; 70 71 72 // 73 // ZmPreferencesPage methods 74 // 75 76 ZmNotificationsPage.prototype.showMe = function() { 77 // default processing 78 var initialize = !this.hasRendered; 79 ZmPreferencesPage.prototype.showMe.apply(this, arguments); 80 81 // setup controls 82 var status = this._getValidatedDevice() ? 83 ZmNotificationsPageForm.CONFIRMED : ZmNotificationsPageForm.UNCONFIRMED; 84 this._form.setValue("DEVICE_EMAIL_CODE_STATUS_VALUE", status); 85 this._form.setValue("EMAIL", this._getEmailAddress()); 86 this._form.update(); 87 88 // load SMS data, if needed 89 if (initialize && this._form.getControl("DEVICE_EMAIL_REGION") != null) { 90 var locid = window.appRequestLocaleId ? "&locid=" + window.appRequestLocaleId : ""; 91 var includes = [ 92 [ appContextPath, 93 "/res/ZmSMS.js", 94 "?v=",cacheKillerVersion, 95 locid, 96 appDevMode ? "&debug=1" : "" 97 ].join("") 98 ]; 99 var baseurl = null; 100 var callback = new AjxCallback(this, this._smsDataLoaded); 101 var proxy = null; 102 AjxInclude(includes, baseurl, callback, proxy); 103 } 104 }; 105 106 /** 107 * <strong>Note:</strong> 108 * Only the email field is a preference that the user can set directly. 109 * 110 * @private 111 */ 112 ZmNotificationsPage.prototype.isDirty = function() { 113 return this._form.getValue("EMAIL") != this._getEmailAddress(); 114 }; 115 116 /** 117 * <strong>Note:</strong> 118 * Only the email field is a preference that the user can set directly. 119 * 120 * @private 121 */ 122 ZmNotificationsPage.prototype.validate = function() { 123 return this._form.isValid("EMAIL"); 124 }; 125 126 ZmNotificationsPage.prototype.setFormValue = function(id, value, setup, control) { 127 value = ZmPreferencesPage.prototype.setFormValue.apply(this, arguments); 128 if (id == ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS) { 129 this._form.setValue("EMAIL", value); 130 this._form.update(); 131 } 132 return value; 133 }; 134 135 ZmNotificationsPage.prototype.getFormValue = function(id, setup, control) { 136 if (id == ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS) { 137 var value = this._form.getValue("EMAIL"); 138 return setup && setup.valueFunction ? setup.valueFunction(value) : value; 139 } 140 return ZmPreferencesPage.prototype.getFormValue.apply(this, arguments); 141 }; 142 143 /** 144 * This class compleletely overrides the ZmPreferencePage's page 145 * creation in order to use DwtForm for easier page creation. By 146 * using DwtForm, we can get automatic control creation, tab group 147 * ordering, and interactivity dependencies. 148 * 149 * @private 150 */ 151 ZmNotificationsPage.prototype._createPageTemplate = function() { 152 DBG.println(AjxDebug.DBG2, "rendering preferences page " + this._section.id); 153 this._cleanup(); 154 this.setVisible(false); // hide until ready 155 }; 156 157 ZmNotificationsPage.prototype._cleanup = 158 function() { 159 this.setContent(""); 160 } 161 162 ZmNotificationsPage.prototype._createControls = function() { 163 164 //cleanup 165 this._cleanup(); 166 167 // the following part is to do stuff that ZmPreferencesPage does (setting the origValue of the preference), 168 // but simplified for this case (since we are not using all the stuff from ZmPreferencesPage, we are using DwtForm instead) 169 var email = this._getEmailAddress(); 170 var settings = appCtxt.getSettings(); 171 var emailPrefId = ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS; 172 var pref = settings.getSetting(emailPrefId); 173 // save the current value (for checking later if it changed) 174 pref.origValue = email; 175 176 // create form controls 177 this._form = this._setupCustomForm(); 178 this._form.reparentHtmlElement(this.getContentHtmlElement()); 179 180 // make it look like email notification pref control is present 181 // NOTE: This is needed so that the default pref saving works. 182 // NOTE: This is used in conjunction with set/getFormValue. 183 if (this._form.getControl("EMAIL")) { 184 this._prefPresent = {}; 185 this._prefPresent[emailPrefId] = true; 186 } 187 188 // finish setup 189 this.setVisible(true); 190 this.hasRendered = true; 191 }; 192 193 ZmNotificationsPage.prototype._resetPageListener = function() { 194 ZmPreferencesPage.prototype._resetPageListener.apply(this, arguments); 195 this._form.reset(); 196 }; 197 198 // 199 // Protected methods 200 // 201 202 ZmNotificationsPage.prototype._setupCustomForm = function() { 203 return new ZmNotificationsPageForm({parent:this, sectionTemplate:this._section.templateId, id:"ZmNotificationsPage"}); 204 }; 205 206 ZmNotificationsPage.prototype._smsDataLoaded = function() { 207 if (!window.ZmSMS) return; 208 this._form.setSMSData(window.ZmSMS); 209 }; 210 211 // 212 // Classes 213 // 214 215 ZmNotificationsPageForm = function(params) { 216 if (arguments.length == 0) return; 217 params.form = this._getFormParams(params.sectionTemplate); 218 DwtForm.apply(this, arguments); 219 220 // hide DwtSelect options which overflow the container 221 var select = this.getControl("DEVICE_EMAIL_CARRIER"); 222 if (select) { 223 select.dynamicButtonWidth(); 224 } 225 226 this._regionSelectionListener = new AjxListener(this, this._handleRegionSelection); 227 228 // listen to CAL_DEVICE_EMAIL_REMINDERS_ADDRESS changes 229 // NOTE: We can't actually listen to changes in this value because 230 // NOTE: ZmSetting doesn't notify the listeners when the value is 231 // NOTE: set *if* it has an actual LDAP name. 232 }; 233 ZmNotificationsPageForm.prototype = new DwtForm; 234 ZmNotificationsPageForm.prototype.constructor = ZmNotificationsPageForm; 235 236 ZmNotificationsPageForm.prototype.toString = function() { 237 return "ZmNotificationsPageForm"; 238 }; 239 240 // Constants: special region/carrier ids 241 242 ZmNotificationsPageForm.CUSTOM = "Custom"; 243 ZmNotificationsPageForm.UNKNOWN = "Unknown"; 244 245 // Constants: code status values; also doubles as element class names 246 247 ZmNotificationsPageForm.CONFIRMED = "DeviceCodeConfirmed"; 248 ZmNotificationsPageForm.PENDING = "DeviceCodePending"; 249 ZmNotificationsPageForm.UNCONFIRMED = "DeviceCodeUnconfirmed"; 250 251 // Constants: private 252 253 ZmNotificationsPageForm.__letters2NumbersMap = { 254 a:2,b:2,c:2,d:3,e:3,f:3, 255 g:4,h:4,i:4, j:5,k:5,l:5,m:6,n:6,o:6, 256 p:7,q:7,r:7,s:7,t:8,u:8,v:8,w:9,x:9,y:9,z:9 257 }; 258 259 // Public 260 261 ZmNotificationsPageForm.prototype.setSMSData = function(data) { 262 this._smsData = data; 263 264 // setup regions control 265 var regionMap = this._defineRegions(data); 266 var button = this.getControl("DEVICE_EMAIL_REGION"); 267 var menu = this.__createRegionsMenu(button, regionMap); 268 if (menu == null) { 269 // always have at least one region 270 menu = new DwtMenu({parent:button}); 271 this.__createRegionMenuItem(menu, ZmNotificationsPageForm.UNKNOWN, ZmMsg.unknown); 272 } 273 menu.addSelectionListener(this._regionSelectionListener); 274 button.setMenu(menu); 275 276 // set default region 277 this.setRegion(data.defaultRegionId); 278 }; 279 280 ZmNotificationsPageForm.prototype.setRegion = function(regionId) { 281 // decorate the region button 282 var region = ZmNotificationsPage.REGIONS[regionId] || { id:ZmNotificationsPageForm.UNKNOWN, label:ZmMsg.unknown }; 283 var button = this.getControl("DEVICE_EMAIL_REGION"); 284 button.setText(region.label); 285 button.setImage(region.image); 286 button.setData(Dwt.KEY_ID, region.id); 287 288 // update the form 289 this.setCarriers(regionId); 290 this.setValue("DEFAULT_EMAIL_REGION", regionId); 291 if (regionId == this._smsData.defaultRegionId && this._smsData.defaultCarrierId) { 292 this.setValue("DEVICE_EMAIL_CARRIER", this._smsData.defaultCarrierId); 293 } 294 this.update(); 295 }; 296 297 ZmNotificationsPageForm.prototype.setCarriers = function(regionId) { 298 var select = this.getControl("DEVICE_EMAIL_CARRIER"); 299 select.clearOptions(); 300 var region = ZmNotificationsPage.REGIONS[regionId] || {}; 301 var carriers = ZmNotificationsPageForm.__getRegionCarriers(region, true); 302 carriers.sort(ZmNotificationsPageForm.__byLabel); 303 for (var i = 0; i < carriers.length; i++) { 304 var carrier = carriers[i]; 305 var image = carrier.image || carrier.region.image; 306 select.addOption({displayValue:carrier.label, value:carrier.id, image:image}); 307 } 308 select.addOption({displayValue:ZmMsg.custom, value:ZmNotificationsPageForm.CUSTOM, image:null}); 309 }; 310 311 ZmNotificationsPageForm.prototype.isCustom = function() { 312 // user selected "Custom" 313 var carrierId = this.getValue("DEVICE_EMAIL_CARRIER"); 314 if (carrierId == ZmNotificationsPageForm.CUSTOM) return true; 315 316 // any entry w/o an email pattern is also custom 317 var carrier = ZmNotificationsPage.CARRIERS[carrierId]; 318 var hasPattern = Boolean(carrier && carrier.pattern); 319 return !hasPattern; 320 }; 321 322 ZmNotificationsPageForm.prototype.getEmailAddress = function() { 323 if (this.isCustom()) { 324 var number = this.getValue("DEVICE_EMAIL_CUSTOM_NUMBER"); 325 var address = this.getValue("DEVICE_EMAIL_CUSTOM_ADDRESS"); 326 return number && address ? [number,address].join("@") : ""; 327 } 328 329 var phone = ZmNotificationsPageForm.normalizePhoneNumber(this.getValue("DEVICE_EMAIL_PHONE")); 330 var carrier = ZmNotificationsPage.CARRIERS[this.getValue("DEVICE_EMAIL_CARRIER")]; 331 return phone ? AjxMessageFormat.format(carrier.pattern, [phone]) : ""; 332 }; 333 334 ZmNotificationsPageForm.prototype.getCodeStatus = function() { 335 // is there anything to do? 336 var control = this.getControl("DEVICE_EMAIL_CODE_STATUS"); 337 if (!control) return ""; 338 339 // remove other status class names 340 var controlEl = control.getHtmlElement(); 341 Dwt.delClass(controlEl, ZmNotificationsPageForm.CONFIRMED); 342 Dwt.delClass(controlEl, ZmNotificationsPageForm.PENDING); 343 Dwt.delClass(controlEl, ZmNotificationsPageForm.UNCONFIRMED); 344 345 // add appropriate class name 346 var status = this.get("DEVICE_EMAIL_CODE_STATUS_VALUE"); 347 Dwt.addClass(controlEl, status); 348 349 // format status text 350 if (status == ZmNotificationsPageForm.CONFIRMED) { 351 var email = this._getValidatedDevice(); 352 if (email) { 353 var pattern = ZmMsg.deviceEmailNotificationsVerificationStatusConfirmed; 354 return AjxMessageFormat.format(pattern, [email]); 355 } 356 // default back to unconfirmed 357 Dwt.delClass(controlEl, status, ZmNotificationsPageForm.UNCONFIRMED); 358 } 359 return status == ZmNotificationsPageForm.PENDING ? 360 ZmMsg.deviceEmailNotificationsVerificationStatusPending : 361 ZmMsg.deviceEmailNotificationsVerificationStatusUnconfirmed 362 ; 363 }; 364 365 ZmNotificationsPageForm.prototype.getPhoneHint = function() { 366 var carrierId = this.getValue("DEVICE_EMAIL_CARRIER"); 367 var carrier = ZmNotificationsPage.CARRIERS[carrierId]; 368 var carrierHint = carrier && carrier.hint; 369 var email = this.getEmailAddress(); 370 var emailHint = email && AjxMessageFormat.format(ZmMsg.deviceEmailNotificationsPhoneNumber, [email]); 371 if (carrierHint || emailHint) { 372 if (!carrierHint) return emailHint; 373 if (!emailHint) return carrierHint; 374 return AjxMessageFormat.format(ZmMsg.deviceEmailNotificationsCarrierEmailHint, [emailHint,carrierHint]); 375 } 376 return ""; 377 }; 378 379 ZmNotificationsPageForm.normalizePhoneNumber = function(phone) { 380 if (phone) { 381 phone = phone.replace(/[a-z]/gi, ZmNotificationsPageForm.__letters2Numbers); 382 phone = phone.replace(/[^+#\*0-9]/g, ""); 383 } 384 return phone; 385 }; 386 387 // Protected 388 389 ZmNotificationsPageForm.prototype._getFormParams = function(templateId) { 390 return { 391 template: templateId, 392 items: [ 393 // default pref page controls 394 { id: "REVERT_PAGE", type: "DwtButton", label: ZmMsg.restorePage, 395 onclick: "this.parent._resetPageListener()" 396 }, 397 // email 398 { id: "EMAIL", type: "DwtInputField", hint: ZmMsg.exampleEmailAddr, cols:100 }, 399 // device email (aka SMS) 400 { id: "DEVICE_EMAIL_REGION", type: "DwtButton", 401 enabled: "this._smsData", 402 onclick: this._handleRegionClick 403 }, 404 { id: "DEVICE_EMAIL_CARRIER", type: "DwtSelect", value: ZmNotificationsPageForm.CUSTOM, 405 enabled: this._isCarrierEnabled 406 }, 407 { id: "DEVICE_EMAIL_PHONE", type: "DwtInputField", 408 hint: ZmMsg.deviceEmailNotificationsPhoneHint, 409 visible: "!this.isCustom()", 410 onchange: this._handleCarrierChange 411 }, 412 { id: "DEVICE_EMAIL_PHONE_HINT", type: "DwtText", 413 getter: this.getPhoneHint, 414 visible: "get('DEVICE_EMAIL_PHONE_HINT')" // NOTE: only show if there's a value 415 }, 416 { id: "DEVICE_EMAIL_PHONE_SEND_CODE", type: "DwtButton", 417 label: ZmMsg.deviceEmailNotificationsVerificationCodeSend, 418 visible: "!this.isCustom()", 419 enabled: "get('DEVICE_EMAIL_PHONE')", 420 onclick: this._handleSendCode 421 }, 422 { id: "DEVICE_EMAIL_CUSTOM_NUMBER", type: "DwtInputField", 423 visible: "this.isCustom()" 424 }, 425 { id: "DEVICE_EMAIL_CUSTOM_ADDRESS", type: "DwtInputField", 426 visible: "this.isCustom()" 427 }, 428 { id: "DEVICE_EMAIL_CUSTOM_SEND_CODE", type: "DwtButton", 429 label: ZmMsg.deviceEmailNotificationsVerificationCodeSend, 430 visible: "this.isCustom()", 431 enabled: "get('DEVICE_EMAIL_CUSTOM_NUMBER') && get('DEVICE_EMAIL_CUSTOM_ADDRESS')", 432 onclick: this._handleSendCode 433 }, 434 { id: "DEVICE_EMAIL_CODE", type: "DwtInputField", 435 hint: ZmMsg.deviceEmailNotificationsVerificationCodeHint 436 }, 437 { id: "DEVICE_EMAIL_CODE_VALIDATE", type: "DwtButton", 438 label: ZmMsg.deviceEmailNotificationsVerificationCodeValidate, 439 enabled: "get('DEVICE_EMAIL_CODE') && this.getEmailAddress()", 440 onclick: this._handleValidateCode 441 }, 442 { id: "DEVICE_EMAIL_CODE_INVALIDATE", type: "DwtButton", 443 label: ZmMsg.deviceEmailNotificationsVerificationCodeInvalidate, 444 visible: "this._getValidatedDevice()", 445 onclick: this._handleInvalidateDevice 446 }, 447 { id: "DEVICE_EMAIL_CODE_STATUS", type: "DwtText", 448 className: "DeviceCode", getter: this.getCodeStatus 449 }, 450 // NOTE: This holds the current code status 451 { id: "DEVICE_EMAIL_CODE_STATUS_VALUE", value: ZmNotificationsPageForm.UNCONFIRMED } 452 ] 453 }; 454 }; 455 456 ZmNotificationsPageForm.prototype._isCarrierEnabled = function() { 457 var control = this.getControl('DEVICE_EMAIL_CARRIER'); 458 return control && control.getOptionCount() > 0; 459 }; 460 461 ZmNotificationsPageForm.prototype._defineRegions = function(data) { 462 // define regions 463 var regionMap = {}; 464 for (var id in data) { 465 // do we care about this entry? 466 if (!id.match(/^region_/)) continue; 467 468 // take apart message key 469 var parts = id.split(/[_\.]/); 470 var prop = parts[parts.length - 1]; 471 472 // set region info 473 var regions = regionMap; 474 var regionIds = parts[1].split("/"), region; 475 for (var i = 0; i < regionIds.length; i++) { 476 var regionId = regionIds[i]; 477 if (!regions[regionId]) { 478 regions[regionId] = ZmNotificationsPage.REGIONS[regionId] = { id: regionId }; 479 } 480 region = regions[regionId]; 481 if (i < regionIds.length - 1 && !region.regions) { 482 region.regions = {}; 483 } 484 regions = region.regions; 485 } 486 487 // store property 488 region[prop] = data[id]; 489 } 490 491 // define carriers 492 this._defineCarriers(data); 493 494 return regionMap; 495 }; 496 497 ZmNotificationsPageForm.prototype._defineCarriers = function(data) { 498 for (var id in data) { 499 // do we care about this entry? 500 if (!id.match(/^carrier_/)) continue; 501 502 // take apart message key 503 var s = id.split(/[_\.]/); 504 var prop = s[s.length - 1]; 505 506 // set carrier info 507 var carrierId = s.slice(1, 3).join("_"); 508 var carrier = ZmNotificationsPage.CARRIERS[carrierId]; 509 if (!carrier) { 510 var regionId = s[1]; 511 var region = ZmNotificationsPage.REGIONS[regionId]; 512 if (!region.carriers) { 513 region.carriers = {}; 514 } 515 carrier = region.carriers[carrierId] = ZmNotificationsPage.CARRIERS[carrierId] = { 516 id: carrierId, region: region 517 }; 518 } 519 520 // store property 521 carrier[prop] = data[id]; 522 } 523 return ZmNotificationsPage.CARRIERS; 524 }; 525 526 ZmNotificationsPageForm.prototype._handleRegionClick = function() { 527 var button = this.getControl("DEVICE_EMAIL_REGION"); 528 var menu = button.getMenu(); 529 if (menu.isPoppedUp()) { 530 menu.popdown(); 531 } 532 else { 533 button.popup(); 534 } 535 }; 536 537 ZmNotificationsPageForm.prototype._handleCarrierChange = function() { 538 var controlId = this.isCustom() ? "DEVICE_EMAIL_NUMBER" : "DEVICE_EMAIL_PHONE"; 539 var control = this.getControl(controlId); 540 if (control && control.focus) { 541 control.focus(); 542 } 543 }; 544 545 ZmNotificationsPageForm.prototype._handleSendCode = function() { 546 var params = { 547 jsonObj: { 548 SendVerificationCodeRequest: { 549 _jsns: "urn:zimbraMail", 550 a: this.getEmailAddress() 551 } 552 }, 553 asyncMode: true, 554 callback: new AjxCallback(this, this._handleSendCodeResponse) 555 }; 556 appCtxt.getAppController().sendRequest(params); 557 }; 558 559 ZmNotificationsPageForm.prototype._handleSendCodeResponse = function(resp) { 560 appCtxt.setStatusMsg(ZmMsg.deviceEmailNotificationsVerificationCodeSendSuccess); 561 562 this.setValue("DEVICE_EMAIL_CODE_STATUS_VALUE", ZmNotificationsPageForm.PENDING); 563 this.update(); 564 565 var dialog = appCtxt.getMsgDialog(); 566 var email = appCtxt.get(ZmSetting.USERNAME); 567 var message = AjxMessageFormat.format(ZmMsg.deviceEmailNotificationsVerificationCodeSendNote, [email]); 568 dialog.setMessage(message); 569 dialog.popup(); 570 }; 571 572 ZmNotificationsPageForm.prototype._handleRegionSelection = function(event) { 573 var regionId = event.item.getData(Dwt.KEY_ID); 574 this.setRegion(regionId); 575 }; 576 577 ZmNotificationsPageForm.prototype._handleValidateCode = function() { 578 var params = { 579 jsonObj: { 580 VerifyCodeRequest: { 581 _jsns: "urn:zimbraMail", 582 a: this.getEmailAddress(), 583 code: this.getValue("DEVICE_EMAIL_CODE") 584 } 585 }, 586 asyncMode: true, 587 callback: new AjxCallback(this, this._handleValidateCodeResponse) 588 }; 589 appCtxt.getAppController().sendRequest(params); 590 }; 591 592 ZmNotificationsPageForm.prototype._handleValidateCodeResponse = function(resp) { 593 var success = AjxUtil.get(resp.getResponse(), "VerifyCodeResponse", "success") == "1"; 594 var params = { 595 msg: success ? 596 ZmMsg.deviceEmailNotificationsVerificationCodeValidateSuccess : 597 ZmMsg.deviceEmailNotificationsVerificationCodeValidateFailure, 598 level: success ? ZmStatusView.LEVEL_INFO : ZmStatusView.LEVEL_CRITICAL 599 }; 600 appCtxt.setStatusMsg(params); 601 602 // NOTE: Since the preference values only come in at launch time, 603 // NOTE: manually set the confirmed email address so that we can 604 // NOTE: display the correct confirmed code status text 605 if (success) { 606 appCtxt.set(ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ADDRESS, this.getEmailAddress()); 607 } 608 609 var status = success ? ZmNotificationsPageForm.CONFIRMED : ZmNotificationsPageForm.UNCONFIRMED; 610 this.setValue("DEVICE_EMAIL_CODE_STATUS_VALUE", status); 611 this.update(); 612 }; 613 614 615 ZmNotificationsPageForm.prototype._getValidatedDevice = function() { 616 return this.parent._getValidatedDevice(); 617 }; 618 619 620 ZmNotificationsPageForm.prototype._handleInvalidateDevice = function() { 621 var params = { 622 jsonObj: { 623 InvalidateReminderDeviceRequest: { 624 _jsns: "urn:zimbraMail", 625 a: this._getValidatedDevice() 626 } 627 }, 628 asyncMode: true, 629 callback: new AjxCallback(this, this._handleInvalidateDeviceResponse) 630 }; 631 appCtxt.getAppController().sendRequest(params); 632 }; 633 634 ZmNotificationsPageForm.prototype._handleInvalidateDeviceResponse = function(resp) { 635 var dummy = resp.getResponse(); //to get the exception thrown if there was some unexpected error. 636 var params = { 637 msg: ZmMsg.deviceEmailNotificationsVerificationCodeInvalidateSuccess, 638 level: ZmStatusView.LEVEL_INFO 639 }; 640 appCtxt.setStatusMsg(params); 641 642 appCtxt.set(ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ADDRESS, null); 643 this.setValue("DEVICE_EMAIL_CODE_STATUS_VALUE", ZmNotificationsPageForm.UNCONFIRMED); 644 this.update(); 645 }; 646 647 648 // Private 649 650 ZmNotificationsPageForm.prototype.__createRegionsMenu = function(parent, regionMap, parentRegion) { 651 var regions = AjxUtil.values(regionMap, ZmNotificationsPageForm.__acceptRegion); 652 if (regions.length == 0) return null; 653 654 var menu = new DwtMenu({parent:parent}); 655 656 regions.sort(ZmNotificationsPageForm.__byLabel); 657 for (var i = 0; i < regions.length; i++) { 658 var region = regions[i]; 659 // add entry for this region 660 var image = parent instanceof DwtMenuItem ? region.image : null; 661 var menuItem = this.__createRegionMenuItem(menu, region.id, region.label, image); 662 // add sub-regions 663 var subMenu = region.regions && this.__createRegionsMenu(menuItem, region.regions, region); 664 if (subMenu && subMenu.getItemCount() > 0) { 665 subMenu.addSelectionListener(this._regionSelectionListener); 666 menuItem.setMenu(subMenu); 667 } 668 } 669 670 // NOTE: Since only the call to this method *within* this method 671 // NOTE: passes in a parentRegion, we'll only add a general entry for 672 // NOTE: the parent region at a sub-level and never at the top level. 673 if (parentRegion) { 674 var hasCarriers = parentRegion.carriers && parentRegion.carriers.length > 0; 675 var menuItemCount = menu.getItemCount(); 676 if (hasCarriers || menuItemCount > 1) { 677 this.__createRegionMenuItem(menu, parentRegion.id, parentRegion.label, parentRegion.image, 0); 678 if (menuItemCount > 1) { 679 new DwtMenuItem({parent:menu,style:DwtMenuItem.SEPARATOR_STYLE,index:1}); 680 } 681 } 682 } 683 684 return menu; 685 }; 686 687 ZmNotificationsPageForm.prototype.__createRegionMenuItem = function(parent, id, label, image, index) { 688 var menuItem = new DwtMenuItem({parent:parent,index:index}); 689 menuItem.setText(label); 690 menuItem.setImage(image); 691 menuItem.setData(Dwt.KEY_ID, id); 692 return menuItem; 693 }; 694 695 ZmNotificationsPageForm.__acceptRegion = function(regionId, regionMap) { 696 var region = regionMap[regionId]; 697 var hasRegions = false; 698 for (var id in region.regions) { 699 if (ZmNotificationsPageForm.__acceptRegion(id, region.regions)) { 700 hasRegions = true; 701 break; 702 } 703 } 704 var hasCarriers = ZmNotificationsPageForm.__getRegionCarriers(region).length > 0; 705 return hasRegions || hasCarriers; 706 }; 707 708 ZmNotificationsPageForm.__getRegionCarriers = function(region, recurse) { 709 if (region.carriers && !(region.carriers instanceof Array)) { 710 region.carriers = AjxUtil.values(region.carriers); 711 region.carriers.sort(ZmNotificationsPageForm.__byLabel); 712 } 713 var carriers = region.carriers || []; 714 if (recurse && region.regions) { 715 for (var regionId in region.regions) { 716 carriers = carriers.concat(ZmNotificationsPageForm.__getRegionCarriers(region.regions[regionId], true)); 717 } 718 } 719 return carriers; 720 }; 721 722 ZmNotificationsPageForm.__byLabel = AjxCallback.simpleClosure(AjxUtil.byStringProp, window, "label"); 723 724 ZmNotificationsPageForm.__letters2Numbers = function($0) { 725 return ZmNotificationsPageForm.__letters2NumbersMap[$0.toLowerCase()]; 726 }; 727