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 * Creates an empty preferences page of the given type. 26 * @constructor 27 * @class 28 * This class represents a single page of preferences available by selecting one of the 29 * preference tabs. During construction, skeletal HTML is created. The preferences 30 * are not added until the page becomes visible. 31 * 32 * @author Conrad Damon 33 * 34 * @param {DwtControl} parent the containing widget 35 * @param {object} section the page 36 * @param {ZmPrefController} controller the prefs controller 37 * 38 * @extends DwtTabViewPage 39 */ 40 ZmPreferencesPage = function(parent, section, controller, id) { 41 if (arguments.length == 0) return; 42 43 id = id || ("Prefs_Pages_" + section.id); 44 DwtTabViewPage.call(this, parent, "ZmPreferencesPage", null, id); 45 46 this._section = section; 47 this._controller = controller; 48 49 this.setScrollStyle(Dwt.SCROLL_Y); 50 51 this._title = [ZmMsg.zimbraTitle, controller.getApp().getDisplayName(), section.title].join(": "); 52 53 this._dwtObjects = {}; 54 this._tabGroup = new DwtTabGroup(id); 55 this._rendered = false; // used by DwtTabViewPage 56 }; 57 58 ZmPreferencesPage.prototype = new DwtTabViewPage; 59 ZmPreferencesPage.prototype.constructor = ZmPreferencesPage; 60 61 ZmPreferencesPage.prototype.toString = 62 function () { 63 return "ZmPreferencesPage"; 64 }; 65 66 // 67 // Constants 68 // 69 70 ZmPreferencesPage.IMPORT_FIELD_NAME = "importUpload"; 71 ZmPreferencesPage.IMPORT_TIMEOUT = 300; 72 73 // 74 // Public methods 75 // 76 77 ZmPreferencesPage.prototype._replaceControlElement = 78 function(elemOrId, control) { 79 control.replaceElement(elemOrId); 80 }; 81 82 ZmPreferencesPage.prototype._enterTabScope = 83 function() { 84 if (!this._tabScopeStack) { 85 this._tabScopeStack = []; 86 } 87 var scope = {}; 88 this._tabScopeStack.push(scope); 89 return scope; 90 }; 91 92 ZmPreferencesPage.prototype._getCurrentTabScope = 93 function() { 94 var stack = this._tabScopeStack; 95 return stack && stack[stack.length - 1]; 96 }; 97 98 ZmPreferencesPage.prototype._exitTabScope = 99 function() { 100 var stack = this._tabScopeStack; 101 return stack && stack.pop(); 102 }; 103 104 ZmPreferencesPage.prototype._addControlTabIndex = 105 function(elemOrId, control) { 106 }; 107 108 ZmPreferencesPage.prototype._addTabLinks = 109 function(elemOrId) { 110 var elem = Dwt.byId(elemOrId); 111 if (!elem) return; 112 113 var links = elem.getElementsByTagName("A"); 114 for (var i = 0; i < links.length; i++) { 115 var link = links[i]; 116 if (!link.href) continue; 117 this._addControlTabIndex(link, link); 118 } 119 }; 120 121 /** 122 * Fills the page with preferences that belong to this page, if that has not been done 123 * already. Note this method is only called when the tab 124 * is selected and the page becomes visible. 125 * 126 */ 127 ZmPreferencesPage.prototype.showMe = 128 function() { 129 DwtTabViewPage.prototype.showMe.call(this); 130 131 Dwt.setTitle(this._title); 132 this._controller._resetOperations(this._controller._toolbar, this._section.id); 133 134 if (this.hasRendered) { 135 if (this._controller.isDirty(this._section.id)) { 136 this._controller.setDirty(this._section.id, false); 137 } 138 return; 139 } 140 141 this._dwtObjects = {}; // always reset in case account has changed 142 this._createPageTemplate(); 143 this._createControls(); 144 145 // find option headers and sections 146 var elements = this.getHtmlElement().children; 147 148 AjxUtil.foreach(elements, function(el) { 149 if (Dwt.hasClass(el, 'prefHeader')) { 150 var header = el; 151 header.setAttribute('role', 'heading'); 152 header.setAttribute('aria-level', 1); 153 header.id = Dwt.getNextId('prefHeader') 154 } else if (Dwt.hasClass(el, 'ZOptionsSectionTable')) { 155 var sectiontable = el; 156 var header = Dwt.getPreviousElementSibling(sectiontable); 157 var sections = Dwt.byClassName('ZOptionsSectionMain', sectiontable); 158 159 if (!Dwt.hasClass(header, 'prefHeader')) { 160 DBG.println(AjxDebug.DBG1, "pref section has no prefHeader:\n" + 161 sectiontable.outerHTML); 162 return; 163 } 164 165 // we only expect one section, but iterate over them, just in case 166 AjxUtil.foreach(sections, function(section) { 167 section.setAttribute('aria-labelledby', header.id); 168 section.setAttribute('role', 'region'); 169 }); 170 } 171 }); 172 173 // find option fields 174 var fields = Dwt.byClassName('ZOptionsField', this.getHtmlElement()); 175 176 AjxUtil.foreach(fields, function(field) { 177 field.setAttribute('role', 'group'); 178 179 // find the label corresponding to this item and assign it as an ARIA 180 // label 181 var label = Dwt.getPreviousElementSibling(field); 182 183 if (!label) { 184 DBG.println(AjxDebug.DBG1, "option field has no label " + Dwt.getId(field)); 185 return; 186 } 187 188 label.setAttribute('role', 'heading'); 189 label.setAttribute('aria-level', 2); 190 191 field.setAttribute('aria-labelledby', 192 Dwt.getId(label, 'ZOptionsLabel')); 193 }); 194 195 // find focusable children -- i.e. links and widgets -- but in the DOM 196 // order, not in the order they were added as children 197 var selector = [ 198 '[parentid="', 199 this.getHTMLElId(), 200 '"],', 201 'A' 202 ].join(''); 203 var elements = this.getHtmlElement().querySelectorAll(selector); 204 205 for (var i = 0; i < elements.length; i++) { 206 var element = elements[i]; 207 var control = DwtControl.fromElement(element); 208 209 // add the child to our tab group 210 if (control && control.parent == this) { 211 this._tabGroup.addMember(control.getTabGroupMember()); 212 } else if (DwtControl.findControl(element) === this) { 213 this._makeFocusable(element); 214 this._tabGroup.addMember(element); 215 } 216 217 // find the ZOptionsField corresponding to this item and assign it as 218 // an ARIA label 219 var ancestors = Dwt.getAncestors(element, this.getHtmlElement()); 220 var field = null, label = null; 221 222 for (var j = 0; j < ancestors.length; j++) { 223 var ancestor = ancestors[j]; 224 var ancestorSibling = Dwt.getPreviousElementSibling(ancestor); 225 226 // are we looking at an option field with a corresponding label? 227 // please note that labels can have multiple classes, all of them 228 // starting with ZOptionsLabel 229 if (Dwt.hasClass(ancestor, 'ZOptionsField')) { 230 field = ancestor; 231 } 232 } 233 234 if (!field) { 235 DBG.println(AjxDebug.DBG1, "no field found for:\n" + 236 element.outerHTML); 237 continue; 238 } 239 240 var label = Dwt.getPreviousElementSibling(field); 241 242 if (!label || !label.className.match(/\bZOptionsLabel/)) { 243 DBG.println(AjxDebug.DBG1, "option field has no label:\n" + 244 field.outerHTML); 245 continue; 246 } 247 248 if (!label.id) { 249 label.id = Dwt.getNextId(); 250 } 251 252 label.setAttribute('role', 'heading'); 253 label.setAttribute('aria-level', 2); 254 } 255 }; 256 257 ZmPreferencesPage.prototype._createPageTemplate = 258 function() { 259 // expand template 260 DBG.println(AjxDebug.DBG2, "rendering preferences page " + this._section.id); 261 var templateId = this._section.templateId; 262 this._createPageHtml(templateId, this._getTemplateData()); 263 this.setVisible(false); // hide until ready 264 }; 265 266 ZmPreferencesPage.prototype._getTemplateData = 267 function() { 268 var data = { 269 id: this._htmlElId, 270 isEnabled: AjxCallback.simpleClosure(this._isEnabled, this), 271 activeAccount: appCtxt.getActiveAccount() 272 }; 273 data.expandField = AjxCallback.simpleClosure(this._expandField, this, data); 274 275 return data; 276 }; 277 278 ZmPreferencesPage.prototype._createControls = 279 function() { 280 // create controls for prefs, if present in template 281 this._prefPresent = {}; 282 this._enterTabScope(); 283 try { 284 // add links to tab control list 285 this._addTabLinks(this.getHtmlElement()); 286 287 // add preference controls 288 var prefs = this._section.prefs || []; 289 var settings = appCtxt.getSettings(); 290 291 for (var i = 0; i < prefs.length; i++) { 292 var id = prefs[i]; 293 if (!id) { continue; } 294 var pref = settings.getSetting(id); 295 296 // ignore if there is no container element 297 var elem = document.getElementById([this._htmlElId, id].join("_")); 298 if (!elem) { continue; } 299 300 // ignore if doesn't meet pre-condition 301 var setup = ZmPref.SETUP[id]; 302 303 if (!setup || !appCtxt.checkPrecondition(setup.precondition, setup.preconditionAny)) { 304 continue; 305 } 306 307 // perform load function 308 if (setup.loadFunction) { 309 setup.loadFunction(setup); 310 if (setup.options.length <= 1) { continue; } 311 } 312 313 // save the current value (for checking later if it changed) 314 pref.origValue = this._getPrefValue(id); 315 var value = this._getPrefValue(id, false); 316 317 this._prefPresent[id] = true; 318 DBG.println(AjxDebug.DBG3, "adding pref " + pref.name + " / " + value); 319 320 // create form controls 321 this._initControl(id, setup, value); 322 323 var control = null; 324 var type = setup ? setup.displayContainer : null; 325 if (type == ZmPref.TYPE_CUSTOM) { 326 control = this._setupCustom(id, setup, value); 327 } 328 else if (type == ZmPref.TYPE_SELECT) { 329 control = this._setupSelect(id, setup, value); 330 } 331 else if (type == ZmPref.TYPE_COMBOBOX) { 332 control = this._setupComboBox(id, setup, value); 333 } 334 else if (type == ZmPref.TYPE_RADIO_GROUP) { 335 control = this._setupRadioGroup(id, setup, value); 336 } 337 else if (type == ZmPref.TYPE_CHECKBOX) { 338 control = this._setupCheckbox(id, setup, value); 339 } 340 else if (type == ZmPref.TYPE_INPUT || type == ZmPref.TYPE_TEXTAREA) { 341 if (type == ZmPref.TYPE_TEXTAREA) { 342 setup.rows = elem.getAttribute("rows") || setup.rows || 4; 343 setup.cols = elem.getAttribute("cols") || setup.cols || 60; 344 setup.wrap = elem.getAttribute("wrap") || setup.wrap || "on"; 345 } 346 control = this._setupInput(id, setup, value); 347 } 348 else if (type == ZmPref.TYPE_STATIC) { 349 control = this._setupStatic(id, setup, value); 350 } 351 else if (type == ZmPref.TYPE_COLOR) { 352 control = this._setupColor(id, setup, value); 353 } 354 else if (type == ZmPref.TYPE_LOCALES) { 355 //Fix for bug# 80762 - Based on multiple locale availability set the view as dropdown or label 356 if(ZmLocale.hasChoices()) { 357 control = this._setupLocales(id, setup, value); 358 } 359 else { 360 //Part of bug# 80762. Sets view for a single locale and displays as a label 361 control = this._setupLocaleLabel(id, setup, value); 362 } 363 } 364 else if (type == ZmPref.TYPE_FONT) { 365 control = this._setupMenuButton(id, value, ZmPreferencesPage.fontMap); 366 } 367 else if (type == ZmPref.TYPE_FONT_SIZE) { 368 control = this._setupMenuButton(id, value, ZmPreferencesPage.fontSizeMap); 369 } 370 else if (type == ZmPref.TYPE_PASSWORD) { 371 this._addButton(elem, setup.displayName, 50, new AjxListener(this, this._changePasswordListener), "CHANGE_PASSWORD"); 372 } 373 else if (type == ZmPref.TYPE_IMPORT) { 374 this._addImportWidgets(elem, id, setup); 375 } 376 else if (type == ZmPref.TYPE_EXPORT) { 377 this._addExportWidgets(elem, id, setup); 378 } 379 380 if (!control) { 381 control = this.getFormObject(id); 382 } 383 384 // add control to form 385 if (control && control.isDwtControl) { 386 this._replaceControlElement(elem, control); 387 if (setup.initFunction) { 388 setup.initFunction(control, value); 389 } 390 if (setup.changeFunction) { 391 if (control.addChangeListener) { 392 control.addChangeListener(setup.changeFunction); 393 } else if (control.addSelectionListener) { 394 control.addSelectionListener(setup.changeFunction); 395 } 396 } 397 } 398 } 399 400 // create special page buttons 401 var defaultsRestore = document.getElementById([this._htmlElId,"DEFAULTS_RESTORE"].join("_")); 402 if (defaultsRestore) { 403 this._addButton(defaultsRestore, ZmMsg.restoreDefaults, 110, new AjxListener(this, this._resetListener)); 404 } 405 406 // create tab-group for all controls on the page 407 this._addControlsToTabGroup(this._tabGroup); 408 } 409 finally { 410 this._exitTabScope(); 411 } 412 413 // finish setup 414 this.setVisible(true); 415 this.hasRendered = true; 416 }; 417 418 ZmPreferencesPage.prototype._addControlsToTabGroup = 419 function(tabGroup) { 420 }; 421 422 ZmPreferencesPage.prototype.setFormObject = 423 function(id, object) { 424 this._dwtObjects[id] = object; 425 }; 426 427 ZmPreferencesPage.prototype.getFormObject = 428 function(id) { 429 return this._dwtObjects[id]; 430 }; 431 432 /** 433 * Gets the value of the preference control. 434 * 435 * @param {String} id the preference id 436 * @param {Object} [setup] the preference descriptor 437 * @param {DwtControl} [control] the preference control 438 * @return {String} the value 439 */ 440 ZmPreferencesPage.prototype.getFormValue = 441 function(id, setup, control) { 442 setup = setup || ZmPref.SETUP[id]; 443 var value = null; 444 var type = setup ? setup.displayContainer : null; 445 if (type == ZmPref.TYPE_SELECT || type == ZmPref.TYPE_COMBOBOX || 446 type == ZmPref.TYPE_CHECKBOX || 447 type == ZmPref.TYPE_RADIO_GROUP || type == ZmPref.TYPE_COLOR || 448 type == ZmPref.TYPE_INPUT || type == ZmPref.TYPE_LOCALES || 449 type === ZmPref.TYPE_FONT || type === ZmPref.TYPE_FONT_SIZE) { 450 var object = control || this.getFormObject(id); 451 if (object) { 452 if (type == ZmPref.TYPE_COLOR) { 453 value = object.getColor(); 454 } 455 else if (type == ZmPref.TYPE_CHECKBOX) { 456 value = object.isSelected(); 457 if (setup.options) { 458 value = setup.options[Number(value)]; 459 } 460 } 461 else if (type == ZmPref.TYPE_RADIO_GROUP) { 462 value = object.getSelectedValue(); 463 if (value == "true" || value == "false") { 464 value = (value == "true"); 465 } 466 } 467 else if (type == ZmPref.TYPE_LOCALES) { 468 value = object._localeId; 469 } 470 else if (type === ZmPref.TYPE_FONT || type === ZmPref.TYPE_FONT_SIZE) { 471 value = object._itemId; 472 } 473 else if (type == ZmPref.TYPE_COMBOBOX) { 474 value = object.getValue() || object.getText(); 475 } 476 else { 477 value = object.getValue(); 478 } 479 } 480 } 481 else { 482 var prefId = [this._htmlElId, id].join("_"); 483 var element = document.getElementById(prefId); 484 if (!element) return null; 485 value = element.value; 486 } 487 return setup && setup.valueFunction ? setup.valueFunction(value) : value; 488 }; 489 490 /** 491 * Sets the value of the preference control. 492 * 493 * @param {String} id the preference id 494 * @param {Object} value the preference value 495 * @param {Object} [setup] the preference descriptor 496 * @param {DwtControl} [control] the preference control 497 */ 498 ZmPreferencesPage.prototype.setFormValue = 499 function(id, value, setup, control) { 500 setup = setup || ZmPref.SETUP[id]; 501 if (setup && setup.displayFunction) { 502 value = setup.displayFunction(value); 503 } 504 if (setup && setup.approximateFunction) { 505 value = setup.approximateFunction(value); 506 } 507 var type = setup ? setup.displayContainer : null; 508 if (type == ZmPref.TYPE_SELECT || type == ZmPref.TYPE_COMBOBOX || 509 type == ZmPref.TYPE_CHECKBOX || 510 type == ZmPref.TYPE_RADIO_GROUP || 511 type == ZmPref.TYPE_COLOR) { 512 var object = control || this.getFormObject(id); 513 if (!object) { return value; } 514 515 if (type == ZmPref.TYPE_COLOR) { 516 object.setColor(value); 517 } else if (type == ZmPref.TYPE_CHECKBOX) { 518 if (id == ZmSetting.OFFLINE_IS_MAILTO_HANDLER) { 519 try { // add try/catch - see bug #33870 520 if (window.platform && !window.platform.isRegisteredProtocolHandler("mailto")) { 521 object.setSelected(false); 522 523 // this pref might have been set to true before. so we must set origValue = false 524 // so that when user selects the checkbox, it will be considered "dirty" 525 var setting = appCtxt.getSettings(appCtxt.accountList.mainAccount).getSetting(id); 526 setting.origValue = false; 527 } else { 528 object.setSelected(true); 529 } 530 object.setEnabled(true); 531 } catch(ex) { 532 object.setEnabled(false); 533 object.setSelected(false); 534 } 535 } else { 536 object.setSelected(value); 537 } 538 } else if (type == ZmPref.TYPE_RADIO_GROUP) { 539 object.setSelectedValue(value); 540 } else if (type == ZmPref.TYPE_COMBOBOX) { 541 object.setValue(value); 542 } else { 543 var curValue = object.getValue(); 544 if (value != null && (curValue != value)) { 545 object.setSelectedValue(value); 546 } 547 } 548 } else if (type == ZmPref.TYPE_INPUT) { 549 var object = control || this.getFormObject(id); 550 if (!object) { return value; } 551 552 var curValue = object.getValue(); 553 if (value != null && (curValue != value)) { 554 object.setValue(value); 555 } 556 } else if (type == ZmPref.TYPE_LOCALES) { 557 var object = this._dwtObjects[ZmSetting.LOCALE_NAME]; 558 if (!object) { return value; } 559 this._showLocale(value, object); 560 } else if (type == ZmPref.TYPE_FONT) { 561 var object = this._dwtObjects[ZmSetting.FONT_NAME]; 562 if (!object) { return value; } 563 this._showItem(value, ZmPreferencesPage.fontMap, object); 564 } else if (type == ZmPref.TYPE_FONT_SIZE) { 565 var object = this._dwtObjects[ZmSetting.FONT_SIZE]; 566 if (!object) { return value; } 567 this._showItem(value, ZmPreferencesPage.fontSizeMap, object); 568 } else { 569 var prefId = [this._htmlElId, id].join("_"); 570 var element = control || document.getElementById(prefId); 571 if (!element || element.value == value) { return value; } 572 573 element.value = value || ""; 574 } 575 return value; 576 }; 577 578 /** 579 * Gets the title. 580 * 581 * @return {String} the title 582 */ 583 ZmPreferencesPage.prototype.getTitle = 584 function() { 585 return this._title; 586 }; 587 588 ZmPreferencesPage.prototype.hasResetButton = 589 function() { 590 return true; 591 }; 592 593 594 ZmPreferencesPage.prototype.getTabGroupMember = 595 function() { 596 return this._tabGroup; 597 }; 598 599 ZmPreferencesPage.prototype.reset = 600 function(useDefaults) { 601 var settings = appCtxt.getSettings(); 602 var prefs = this._section.prefs || []; 603 for (var i = 0; i < prefs.length; i++) { 604 var id = prefs[i]; 605 if (!id) { continue; } 606 var setup = ZmPref.SETUP[id]; 607 if (!setup) { continue; } 608 var type = setup.displayContainer; 609 if (type == ZmPref.TYPE_PASSWORD) { continue; } // ignore non-form elements 610 var pref = settings.getSetting(id); 611 var newValue = this._getPrefValue(id, useDefaults); 612 this.setFormValue(id, newValue); 613 } 614 615 if (!useDefaults) { 616 this._controller.setDirty(this._section.id, false); 617 } 618 }; 619 620 ZmPreferencesPage.prototype.resetOnAccountChange = 621 function() { 622 this.hasRendered = false; 623 }; 624 625 /** 626 * Checks if the data is dirty. 627 * 628 * @return {Boolean} <code>true</code> if the data is dirty 629 */ 630 ZmPreferencesPage.prototype.isDirty = function() { return false; }; 631 ZmPreferencesPage.prototype.validate = function() { return true; }; 632 633 /** 634 * Adds the modify command to the given batch command. 635 * 636 * @param {ZmBatchCommand} batchCmd the batch command 637 */ 638 ZmPreferencesPage.prototype.addCommand = function(batchCmd) {}; 639 640 // 641 // Protected methods 642 // 643 644 ZmPreferencesPage.prototype._createPageHtml = 645 function(templateId, data) { 646 if (AjxTemplate.require(templateId)) { 647 this.getContentHtmlElement().innerHTML = AjxTemplate.expand(templateId, data); 648 } 649 }; 650 651 /** 652 * Returns the value of the specified pref, massaging it if necessary. 653 * 654 * @param id [constant] pref ID 655 * @param useDefault [boolean] if true, use pref's default value 656 * 657 * @private 658 */ 659 ZmPreferencesPage.prototype._getPrefValue = 660 function(id, useDefault) { 661 var pref = appCtxt.getSettings().getSetting(id); 662 return useDefault ? pref.getDefaultValue() : pref.getValue(); 663 }; 664 665 // Add a button to the preferences page 666 ZmPreferencesPage.prototype._addButton = 667 function(parentIdOrElem, text, width, listener, id) { 668 var params = {parent: this}; 669 if (id) { 670 params.id = id; 671 } 672 var button = new DwtButton(params); 673 button.setSize(width, Dwt.DEFAULT); 674 button.setText(text); 675 button.addSelectionListener(listener); 676 this._replaceControlElement(parentIdOrElem, button); 677 return button; 678 }; 679 680 ZmPreferencesPage.prototype._prepareValue = 681 function(id, setup, value) { 682 if (setup.displayFunction) { 683 value = setup.displayFunction(value); 684 } 685 if (setup.approximateFunction) { 686 value = setup.approximateFunction(value); 687 } 688 return value; 689 }; 690 691 ZmPreferencesPage.prototype._initControl = 692 function(id, setup, value) { 693 // sub-classes can override this to provide initialization 694 // code *before* the actual control is constructed. 695 }; 696 697 ZmPreferencesPage.prototype._setupStatic = 698 function(id, setup, value) { 699 var text = new DwtText(this); 700 this.setFormObject(id, text); 701 text.setText(value); 702 return text; 703 }; 704 705 ZmPreferencesPage.prototype._setupSelect = 706 function(id, setup, value) { 707 value = this._prepareValue(id, setup, value); 708 709 var params = {parent: this, id: "Prefs_Select_" + id}; 710 for (var p in setup.displayParams) { 711 params[p] = setup.displayParams[p]; 712 } 713 var selObj = new DwtSelect(params); 714 this.setFormObject(id, selObj); 715 716 var options = setup.options || setup.displayOptions || setup.choices || []; 717 var isChoices = Boolean(setup.choices); 718 for (var j = 0; j < options.length; j++) { 719 var optValue = isChoices ? options[j].value : options[j]; 720 var optLabel = isChoices ? options[j].label : setup.displayOptions[j]; 721 optLabel = ZmPreferencesPage.__formatLabel(optLabel, optValue); 722 var optImage = setup.images ? setup.images[j] : null; 723 var data = new DwtSelectOptionData(optValue, optLabel, false, null, optImage); 724 selObj.addOption(data); 725 } 726 727 selObj.setName(id); 728 selObj.setSelectedValue(value); 729 selObj.dynamicButtonWidth(); 730 731 return selObj; 732 }; 733 734 ZmPreferencesPage.prototype._setupComboBox = 735 function(id, setup, value) { 736 value = this._prepareValue(id, setup, value); 737 738 var params = {parent: this, id: "Prefs_ComboBox_" + id}; 739 740 var cboxObj = new DwtComboBox(params); 741 this.setFormObject(id, cboxObj); 742 743 var options = setup.options || setup.displayOptions || setup.choices || []; 744 var isChoices = Boolean(setup.choices); 745 for (var j = 0; j < options.length; j++) { 746 var optValue = isChoices ? options[j].value : options[j]; 747 var optLabel = isChoices ? options[j].label : setup.displayOptions[j]; 748 optLabel = ZmPreferencesPage.__formatLabel(optLabel, optValue); 749 cboxObj.add(optLabel, optValue, optValue == value); 750 } 751 752 cboxObj.setValue(value); 753 754 return cboxObj; 755 }; 756 757 ZmPreferencesPage.prototype._setupRadioGroup = 758 function(id, setup, value) { 759 value = this._prepareValue(id, setup, value); 760 761 var params = {parent: this, id: "Prefs_RadioGroup_" + id}; 762 var container = new DwtComposite(params); 763 764 // build horizontally-oriented radio group, if needed 765 var orient = setup.orientation || ZmPref.ORIENT_VERTICAL; 766 var isHoriz = orient == ZmPref.ORIENT_HORIZONTAL; 767 if (isHoriz) { 768 var table, row, cell; 769 770 table = document.createElement("TABLE"); 771 table.className = "ZmRadioButtonGroupHoriz"; 772 table.border = 0; 773 table.cellPadding = 0; 774 table.cellSpacing = 0; 775 container.getHtmlElement().appendChild(table); 776 777 row = table.insertRow(-1); 778 } 779 780 // add options 781 var options = setup.options || setup.displayOptions || setup.choices; 782 var isChoices = setup.choices; 783 var isDisplayString = AjxUtil.isString(setup.displayOptions); 784 var inputId = setup.inputId; 785 786 var radioIds = {}; 787 var selectedId; 788 var name = Dwt.getNextId(); 789 for (var i = 0; i < options.length; i++) { 790 var optValue = isChoices ? options[i].value : options[i]; 791 var optLabel = isChoices ? options[i].label : (isDisplayString ? setup.displayOptions : setup.displayOptions[i]); 792 optLabel = ZmPreferencesPage.__formatLabel(optLabel, optValue); 793 var isSelected = value == optValue; 794 795 var automationId = AjxUtil.isArray(inputId) && inputId[i] ? inputId[i] : Dwt.getNextId(); 796 var radioBtn = new DwtRadioButton({parent:container, name:name, checked:isSelected, id: automationId}); 797 radioBtn.setText(optLabel); 798 radioBtn.setValue(optValue); 799 800 var radioId = radioBtn.getInputElement().id; 801 radioIds[radioId] = radioBtn; 802 if (isSelected) { 803 radioBtn.setSelected(true); 804 selectedId = radioId; 805 } 806 807 if (setup.validationFunction) { 808 var valueToCheck = setup.valueFunction ? setup.valueFunction(optValue) : optValue; 809 if (!setup.validationFunction(valueToCheck)) { 810 radioBtn.setEnabled(false); 811 } 812 } 813 814 if (isHoriz) { 815 cell = row.insertCell(-1); 816 cell.className = "ZmRadioButtonGroupCell"; 817 radioBtn.appendElement(cell); 818 } 819 } 820 821 // store radio button group 822 this.setFormObject(id, new DwtRadioButtonGroup(radioIds, selectedId)); 823 824 return container; 825 }; 826 827 ZmPreferencesPage.prototype._setupCheckbox = 828 function(id, setup, value) { 829 var params = {parent: this, checked: value, id: "Prefs_Checkbox_" + id}; 830 var checkbox = new DwtCheckbox(params); 831 this.setFormObject(id, checkbox); 832 var text = setup.displayFunc ? setup.displayFunc() : setup.displayName; 833 var cboxLabel = ZmPreferencesPage.__formatLabel(text, value); 834 checkbox.setText(cboxLabel); 835 checkbox.setSelected(value); 836 837 // TODO: Factor this out 838 if (id == ZmSetting.MAIL_LOCAL_DELIVERY_DISABLED) { 839 this._handleDontKeepCopyChange(); 840 checkbox.addSelectionListener(new AjxListener(this, this._handleDontKeepCopyChange)); 841 } 842 843 return checkbox; 844 }; 845 846 ZmPreferencesPage.prototype._setupInput = 847 function(id, setup, value) { 848 value = this._prepareValue(id, setup, value); 849 var params = { 850 parent: this, 851 type: setup.type || DwtInputField.STRING, 852 initialValue: value, 853 size: setup.cols || 40, 854 rows: setup.rows, 855 wrap: setup.wrap, 856 maxLen:setup.maxLen, 857 hint: setup.hint, 858 label: setup.label, 859 id: "Prefs_Input_" + id 860 }; 861 var input = new DwtInputField(params); 862 this.setFormObject(id, input); 863 // TODO: Factor this out 864 if (id == ZmSetting.MAIL_FORWARDING_ADDRESS) { 865 this._handleDontKeepCopyChange(); 866 } 867 868 return input; 869 }; 870 871 ZmPreferencesPage.prototype._addImportWidgets = 872 function(containerDiv, settingId, setup) { 873 var uri = appCtxt.get(ZmSetting.CSFE_UPLOAD_URI); 874 875 var importDivId = this._htmlElId+"_import"; 876 var isAddrBookImport = settingId == ZmSetting.IMPORT; 877 var data = { 878 id: importDivId, 879 action: uri, 880 name: ZmPreferencesPage.IMPORT_FIELD_NAME, 881 label: isAddrBookImport ? ZmMsg.importFromCSVLabel : ZmMsg.importFromICSLabel 882 }; 883 containerDiv.innerHTML = AjxTemplate.expand("prefs.Pages#Import", data); 884 885 this._uploadFormId = importDivId+"_form"; 886 this._attInputId = importDivId+"_input"; 887 888 // setup pseudo tab group 889 this._enterTabScope(); 890 var tabGroup = new DwtTabGroup(importDivId+"_x-tabgroup"); 891 try { 892 // set up import button 893 var buttonDiv = document.getElementById(importDivId+"_button"); 894 var btnLabel = setup ? setup.displayName : ZmMsg._import; 895 this._importBtn = this._addButton(buttonDiv, btnLabel, 100, new AjxListener(this, this._importButtonListener)); 896 if (settingId) { 897 this._importBtn.setData(Dwt.KEY_ID, settingId); 898 } 899 900 // add other controls 901 var inputEl = document.getElementById(this._attInputId); 902 if (inputEl) { 903 this._addControlTabIndex(inputEl, inputEl); 904 } 905 this._addTabLinks(containerDiv); 906 907 // add pseudo tab group 908 this._addControlsToTabGroup(tabGroup); 909 } 910 finally { 911 this._exitTabScope(); 912 this._addControlTabIndex(containerDiv, new ZmPreferencesPage.__hack_TabGroupControl(tabGroup)); 913 } 914 }; 915 916 ZmPreferencesPage.__hack_TabGroupControl = 917 function(tabGroup) { 918 this.getTabGroupMember = function() { return tabGroup; }; 919 }; 920 921 ZmPreferencesPage.prototype._setupColor = 922 function(id, setup, value) { 923 924 var params = {parent: this, id: "Prefs_ColorPicker_" + id}; 925 var picker = new DwtButtonColorPicker(params); 926 picker.setImage("FontColor"); 927 picker.showColorDisplay(true); 928 picker.setToolTipContent(ZmMsg.fontColor); 929 picker.setColor(value); 930 931 this.setFormObject(id, picker); 932 933 return picker; 934 }; 935 936 ZmPreferencesPage.prototype._addExportWidgets = 937 function(containerDiv, settingId, setup) { 938 var exportDivId = this._htmlElId+"_export"; 939 containerDiv.innerHTML = AjxTemplate.expand("prefs.Pages#Export", exportDivId); 940 941 //Export Options 942 var format = settingId == "CAL_EXPORT" ? "ics" : "csv"; 943 var selFormat = null; 944 var optionsDiv = document.getElementById(exportDivId+"_options"); 945 if(optionsDiv && (setup.options && setup.options.length > 0) ) { 946 var selFormat = this._setupSelect(settingId, setup); 947 this._replaceControlElement(optionsDiv, selFormat); 948 } 949 950 //Export Button 951 var buttonDiv = document.getElementById(exportDivId+"_button"); 952 buttonDiv.setAttribute("tabindex", containerDiv.getAttribute("tabindex")); 953 954 var btnLabel = setup.displayName || ZmMsg._export; 955 var btn = this._addButton(buttonDiv, btnLabel, 110, new AjxListener(this, this._exportButtonListener, [format, selFormat])); 956 btn.setData(Dwt.KEY_ID, settingId); 957 }; 958 959 ZmPreferencesPage.prototype._setupCustom = 960 function(id, setup, value) { 961 DBG.println("TODO: override ZmPreferences#_setupCustom"); 962 }; 963 964 ZmPreferencesPage.prototype._setupLocales = 965 function(id, setup, value) { 966 var params = {parent: this, id: "Prefs_Locale_" + id}; 967 var button = new DwtButton(params); 968 button.setSize(60, Dwt.DEFAULT); 969 button.setMenu(new AjxListener(this, this._createLocalesMenu, [setup])); 970 this._showLocale(value, button); 971 972 this._dwtObjects[id] = button; 973 974 return button; 975 }; 976 977 //Part of bug# 80762 - Display the single locale item as a read-only label 978 ZmPreferencesPage.prototype._setupLocaleLabel = 979 function(id, setup, value) { 980 var label = new DwtLabel({parent:this}); 981 label.setSize(60, Dwt.DEFAULT); 982 this._showLocale(value, label); 983 this._dwtObjects[id] = label; 984 return label; 985 }; 986 987 ZmPreferencesPage.prototype._setupMenuButton = 988 function(id, value, itemMap) { 989 var button = new DwtButton({parent:this}); 990 button.setSize(60, Dwt.DEFAULT); 991 button.setMenu(new AjxListener(this, this._createMenu, [button, itemMap])); 992 this._showItem(value, itemMap, button); 993 994 this._dwtObjects[id] = button; 995 996 return button; 997 }; 998 999 ZmPreferencesPage.prototype._showLocale = 1000 function(localeId, button) { 1001 var locale = ZmLocale.localeMap[localeId] || ZmLocale.localeMap[localeId.substr(0, 2)]; 1002 button.setImage(locale ? locale.getImage() : null); 1003 button.setText(locale ? locale.getNativeAndLocalName() : ""); 1004 button._localeId = localeId; 1005 }; 1006 1007 ZmPreferencesPage.prototype._createMenu = 1008 function(button, itemMap) { 1009 1010 var menu = new DwtMenu({parent:button}); 1011 1012 var listener = this._itemSelectionListener.bind(this, button, itemMap); 1013 1014 for (var id in itemMap) { 1015 var item = itemMap[id]; 1016 this._createMenuItem(menu, item.id, item.name, listener); 1017 } 1018 return menu; 1019 }; 1020 1021 ZmPreferencesPage.prototype._createLocalesMenu = 1022 function(setup) { 1023 1024 var button = this._dwtObjects[ZmSetting.LOCALE_NAME]; 1025 var result = new DwtMenu({parent:button}); 1026 1027 var listener = new AjxListener(this, this._localeSelectionListener); 1028 for (var language in ZmLocale.languageMap) { 1029 var languageObj = ZmLocale.languageMap[language]; 1030 var locales = languageObj.locales; 1031 if (!locales) { 1032 this._createLocaleItem(result, languageObj, listener); 1033 } 1034 else if (locales.length > 0) { 1035 /* show submenu even if just one item, for cases such as Portugeuse (Brasil), since we want country (locale) specific items in the submenu level */ 1036 var menuItem = new DwtMenuItem({parent:result, style:DwtMenuItem.CASCADE_STYLE}); 1037 menuItem.setText(ZmLocale.languageMap[language].getNativeAndLocalName()); 1038 var subMenu = new DwtMenu({parent:result, style:DwtMenu.DROPDOWN_STYLE}); 1039 menuItem.setMenu(subMenu); 1040 for (var i = 0, count = locales.length; i < count; i++) { 1041 this._createLocaleItem(subMenu, locales[i], listener); 1042 } 1043 } 1044 } 1045 return result; 1046 }; 1047 1048 ZmPreferencesPage.prototype._createMenuItem = 1049 function(parent, id, text, listener) { 1050 var item = new DwtMenuItem({parent:parent}); 1051 item.setText(text); 1052 item._itemId = id; 1053 item.addSelectionListener(listener); 1054 return item; 1055 }; 1056 1057 ZmPreferencesPage.prototype._createLocaleItem = 1058 function(parent, locale, listener) { 1059 var result = new DwtMenuItem({parent:parent}); 1060 result.setText(locale.getNativeAndLocalName()); 1061 if (locale.getImage()) { 1062 result.setImage(locale.getImage()); 1063 } 1064 result._localeId = locale.id; 1065 result.addSelectionListener(listener); 1066 return result; 1067 }; 1068 1069 ZmPreferencesPage.prototype._showItem = 1070 function(itemId, itemMap, button) { 1071 var item = itemMap[itemId]; 1072 button.setImage(item && item.image || null); 1073 button.setText(item && item.name || ""); 1074 button._itemId = itemId; 1075 }; 1076 1077 ZmPreferencesPage.prototype._itemSelectionListener = 1078 function(button, itemMap, ev) { 1079 var item = ev.dwtObj; 1080 this._showItem(item._itemId, itemMap, button); 1081 }; 1082 1083 ZmPreferencesPage.prototype._localeSelectionListener = 1084 function(ev) { 1085 var item = ev.dwtObj; 1086 var button = this._dwtObjects[ZmSetting.LOCALE_NAME]; 1087 this._showLocale(item._localeId, button); 1088 this._showComposeDirection(item._localeId); 1089 }; 1090 1091 ZmPreferencesPage.prototype._handleDontKeepCopyChange = function(ev) { 1092 var input = this.getFormObject(ZmSetting.MAIL_FORWARDING_ADDRESS); 1093 var checkbox = this.getFormObject(ZmSetting.MAIL_LOCAL_DELIVERY_DISABLED); 1094 if (input && checkbox) { 1095 input.setRequired(checkbox.isSelected()); 1096 } 1097 }; 1098 1099 // Popup the change password dialog. 1100 ZmPreferencesPage.prototype._changePasswordListener = 1101 function(ev) { 1102 appCtxt.getChangePasswordWindow(ev); 1103 }; 1104 1105 ZmPreferencesPage.prototype._exportButtonListener = 1106 function(format, formatSelectObj, ev) { 1107 var settingId = ev.dwtObj.getData(Dwt.KEY_ID); 1108 1109 //Get Format 1110 var subFormat = formatSelectObj? formatSelectObj.getValue() : null; 1111 1112 var dialog = appCtxt.getChooseFolderDialog(); 1113 dialog.reset(); 1114 dialog.registerCallback(DwtDialog.OK_BUTTON, this._exportOkCallback, this, [dialog, format, subFormat]); 1115 1116 var omit = {}; 1117 omit[ZmFolder.ID_TRASH] = true; 1118 var overviewId = dialog.getOverviewId(settingId); 1119 1120 if (settingId == ZmSetting.EXPORT) { 1121 AjxDispatcher.require(["ContactsCore", "Contacts"]); 1122 dialog.popup({treeIds: [ZmOrganizer.ADDRBOOK], 1123 overviewId: overviewId, 1124 omit: omit, 1125 title: ZmMsg.chooseAddrBook, 1126 hideNewButton: true, 1127 appName: ZmApp.CONTACTS, 1128 description: ZmMsg.chooseAddrBookToExport}); 1129 } else { 1130 AjxDispatcher.require(["MailCore", "CalendarCore", "Calendar", "CalendarAppt"]); 1131 dialog.popup({treeIds: [ZmOrganizer.CALENDAR], 1132 overviewId: overviewId, 1133 omit: omit, 1134 title: ZmMsg.chooseCalendar, 1135 hideNewButton: true, 1136 appName: ZmApp.CALENDAR, 1137 description: ZmMsg.chooseCalendarToExport}); 1138 } 1139 }; 1140 1141 ZmPreferencesPage.prototype._importButtonListener = 1142 function(ev) { 1143 var settingId = this._importBtn.getData(Dwt.KEY_ID); 1144 var fileInput = document.getElementById(this._attInputId); 1145 var val = fileInput ? AjxStringUtil.trim(fileInput.value) : null; 1146 1147 if (val) { 1148 var dialog = appCtxt.getChooseFolderDialog(); 1149 dialog.reset(); 1150 dialog.setTitle(ZmMsg._import); 1151 dialog.registerCallback(DwtDialog.OK_BUTTON, this._importOkCallback, this, dialog); 1152 1153 var overviewId = [this.toString(), settingId].join("-"); 1154 if (settingId == ZmSetting.IMPORT) { 1155 AjxDispatcher.require(["ContactsCore", "Contacts"]); 1156 var noNew = !appCtxt.get(ZmSetting.NEW_ADDR_BOOK_ENABLED); 1157 var omit = {}; 1158 omit[ZmFolder.ID_TRASH] = true; 1159 dialog.popup({treeIds:[ZmOrganizer.ADDRBOOK], title:ZmMsg.chooseAddrBook, overviewId: overviewId, 1160 description:ZmMsg.chooseAddrBookToImport, skipReadOnly:true, hideNewButton:noNew, omit:omit}); 1161 } else { 1162 AjxDispatcher.require(["MailCore", "CalendarCore", "Calendar"]); 1163 dialog.popup({treeIds:[ZmOrganizer.CALENDAR], title:ZmMsg.chooseCalendar, overviewId: overviewId, description:ZmMsg.chooseCalendarToImport, skipReadOnly:true}); 1164 } 1165 } 1166 else { 1167 var params = { 1168 msg: ZmMsg.importErrorMissingFile, 1169 level: ZmStatusView.LEVEL_CRITICAL 1170 }; 1171 appCtxt.setStatusMsg(params); 1172 } 1173 }; 1174 1175 ZmPreferencesPage.prototype._importOkCallback = 1176 function(dialog, folder) { 1177 var rootId = ZmOrganizer.getSystemId(ZmOrganizer.ID_ROOT); 1178 if (folder && folder.id && folder.id != rootId) { 1179 dialog.popdown(); 1180 this._importBtn.setEnabled(false); 1181 1182 var callback = new AjxCallback(this, this._importDoneCallback, folder.id); 1183 var um = appCtxt.getUploadManager(); 1184 window._uploadManager = um; 1185 try { 1186 um.execute(callback, document.getElementById(this._uploadFormId)); 1187 } catch (ex) { 1188 if (ex.msg) { 1189 var d = appCtxt.getMsgDialog(); 1190 d.setMessage(ex.msg, DwtMessageDialog.CRITICAL_STYLE); 1191 d.popup(); 1192 } 1193 1194 this._importBtn.setEnabled(true); 1195 return true; 1196 } 1197 } 1198 }; 1199 1200 ZmPreferencesPage.prototype._importDoneCallback = 1201 function(folderId, status, aid) { 1202 var appCtlr = appCtxt.getAppController(); 1203 var settingId = this._importBtn.getData(Dwt.KEY_ID); 1204 1205 if (status == 200) { 1206 appCtlr.setStatusMsg(ZmMsg.importingContacts); 1207 1208 // send the import request w/ the att Id to the server per import setting 1209 if (settingId == ZmSetting.IMPORT) 1210 { 1211 var soapDoc = AjxSoapDoc.create("ImportContactsRequest", "urn:zimbraMail"); 1212 var method = soapDoc.getMethod(); 1213 method.setAttribute("ct", "csv"); // always "csv" for now 1214 method.setAttribute("l", folderId); 1215 var content = soapDoc.set("content", ""); 1216 content.setAttribute("aid", aid); 1217 } else { 1218 var soapDoc = AjxSoapDoc.create("ImportAppointmentsRequest", "urn:zimbraMail"); 1219 var method = soapDoc.getMethod(); 1220 method.setAttribute("ct", "ics"); 1221 method.setAttribute("l", folderId); 1222 var content = soapDoc.set("content", ""); 1223 content.setAttribute("aid", aid); 1224 } 1225 var respCallback = new AjxCallback(this, this._handleResponseFinishImport, [aid, settingId]); 1226 var errorCallback = new AjxCallback(this, this._handleErrorFinishImport); 1227 appCtxt.getAppController().sendRequest({soapDoc:soapDoc, asyncMode:true, 1228 callback:respCallback, errorCallback:errorCallback, 1229 timeout:ZmPreferencesPage.IMPORT_TIMEOUT}); 1230 } else { 1231 var msg = (status == AjxPost.SC_NO_CONTENT) 1232 ? ZmMsg.errorImportNoContent 1233 : (AjxMessageFormat.format(ZmMsg.errorImportStatus, status)); 1234 appCtlr.setStatusMsg(msg, ZmStatusView.LEVEL_CRITICAL); 1235 this._importBtn.setEnabled(true); 1236 } 1237 }; 1238 1239 ZmPreferencesPage.prototype._handleResponseFinishImport = 1240 function(aid, settingId, result) { 1241 var msg; 1242 if (settingId == ZmSetting.IMPORT) { 1243 var resp = result.getResponse().ImportContactsResponse.cn[0]; 1244 msg = AjxMessageFormat.format(ZmMsg.contactsImportedResult, Number(resp.n)); 1245 } else { 1246 var resp = result.getResponse().ImportAppointmentsResponse.appt[0]; 1247 msg = AjxMessageFormat.format(ZmMsg.apptsImportedResult, Number(resp.n)); 1248 } 1249 appCtxt.getAppController().setStatusMsg(msg); 1250 this._importBtn.setEnabled(true); 1251 }; 1252 1253 ZmPreferencesPage.prototype._handleErrorFinishImport = 1254 function(ex) { 1255 this._importBtn.setEnabled(true); 1256 1257 if (ex.code == ZmCsfeException.MAIL_UNABLE_TO_IMPORT_CONTACTS || 1258 ex.code == ZmCsfeException.MAIL_UNABLE_TO_IMPORT_APPOINTMENTS) 1259 { 1260 var errDialog = appCtxt.getErrorDialog(); 1261 errDialog.setMessage(ex.getErrorMsg(), ex.msg, DwtMessageDialog.WARNING_STYLE); 1262 errDialog.popup(); 1263 return true; 1264 } 1265 return false; 1266 }; 1267 1268 ZmPreferencesPage.prototype._exportOkCallback = 1269 function(dialog, format, subFormat, folder) { 1270 var rootId = ZmOrganizer.getSystemId(ZmOrganizer.ID_ROOT); 1271 if (folder && folder.id && folder.id != rootId) { 1272 var portPrefix = (location.port == "" || location.port == "80") 1273 ? "" 1274 : (":" + location.port); 1275 var folderName = folder._systemName || AjxStringUtil.urlEncode(folder.getPath()); 1276 var username = appCtxt.multiAccounts ? (AjxStringUtil.urlComponentEncode(appCtxt.get(ZmSetting.USERNAME))) : "~"; 1277 var uri = [ 1278 location.protocol, "//", location.hostname, portPrefix, "/service/home/", 1279 username, "/", folderName, 1280 "?auth=co&fmt=", format, 1281 subFormat ? "&"+format+"fmt="+subFormat : "" // e.g. csvfmt=zimbra-csv 1282 ].join(""); 1283 window.open(uri, "_blank"); 1284 1285 dialog.popdown(); 1286 } 1287 }; 1288 1289 // Reset the form values to the pref defaults. Note that the pref defaults aren't the 1290 // values that the user last had, they're the values that the prefs have before the 1291 // user ever touches them. 1292 ZmPreferencesPage.prototype._resetListener = 1293 function(ev) { 1294 this.reset(true); 1295 appCtxt.setStatusMsg(ZmMsg.defaultsRestored); 1296 }; 1297 1298 /** 1299 * Returns true if any of the specified prefs are enabled (or have no preconditions). 1300 */ 1301 ZmPreferencesPage.prototype._isEnabled = function(prefId1 /* ..., prefIdN */) { 1302 1303 for (var i = 0; i < arguments.length; i++) { 1304 var prefId = arguments[i]; 1305 1306 // setting not created (its app is disabled) 1307 if (!prefId) { return false; } 1308 1309 if (!appCtxt.getActiveAccount().isMain && ZmSetting.IS_GLOBAL[prefId]) { 1310 return false; 1311 } 1312 1313 var setup = ZmPref.SETUP[prefId], 1314 prefPrecondition = setup && setup.precondition; 1315 if (appCtxt.checkPrecondition(prefPrecondition, prefPrecondition && setup.preconditionAny)) { 1316 return true; 1317 } 1318 } 1319 return false; 1320 }; 1321 1322 ZmPreferencesPage.prototype._expandField = 1323 function(data, prefId) { 1324 var templateId = this._section.templateId.replace(/#.*$/, "#"+prefId); 1325 return AjxTemplate.expand(templateId, data); 1326 }; 1327 1328 ZmPreferencesPage.prototype._showComposeDirection = 1329 function(localeId) { 1330 var button = this._dwtObjects[ZmSetting.COMPOSE_INIT_DIRECTION]; 1331 var checkbox = this._dwtObjects[ZmSetting.SHOW_COMPOSE_DIRECTION_BUTTONS]; 1332 if ( ZmLocale.RTLLANGUAGES.hasOwnProperty(localeId) ){ 1333 button.setSelectedValue(ZmSetting.RTL); 1334 checkbox.setSelected(true); 1335 } 1336 else { 1337 button.setSelectedValue(ZmSetting.LTR); 1338 checkbox.setSelected(false); 1339 } 1340 }; 1341 // 1342 // Private functions 1343 // 1344 1345 /** 1346 * Formats a label. If the label contains a replacement parameter (e.g. {0}), 1347 * then it is formatted using AjxMessageFormat with the current value for this 1348 * label. 1349 * 1350 * @private 1351 */ 1352 ZmPreferencesPage.__formatLabel = 1353 function(prefLabel, prefValue) { 1354 prefLabel = prefLabel || ""; 1355 return prefLabel.match(/\{/) ? AjxMessageFormat.format(prefLabel, prefValue) : prefLabel; 1356 }; 1357 1358 ZmPreferencesPage.fontMap = {}; 1359 1360 ZmPreferencesPage._createMenuItem = 1361 function(id, name, itemMap) { 1362 return itemMap[id] = {id: id, name: name}; 1363 }; 1364 1365 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_SYSTEM, ZmMsg.fontSystem, ZmPreferencesPage.fontMap); 1366 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_MODERN, ZmMsg.fontModern, ZmPreferencesPage.fontMap); 1367 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_CLASSIC, ZmMsg.fontClassic, ZmPreferencesPage.fontMap); 1368 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_WIDE, ZmMsg.fontWide, ZmPreferencesPage.fontMap); 1369 1370 ZmPreferencesPage.fontSizeMap = {}; 1371 1372 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_SIZE_SMALL, ZmMsg.fontSizeSmall, ZmPreferencesPage.fontSizeMap); 1373 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_SIZE_NORMAL, ZmMsg.fontSizeNormal, ZmPreferencesPage.fontSizeMap); 1374 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_SIZE_LARGE, ZmMsg.fontSizeLarge, ZmPreferencesPage.fontSizeMap); 1375 ZmPreferencesPage._createMenuItem(ZmSetting.FONT_SIZE_LARGER, ZmMsg.fontSizeExtraLarge, ZmPreferencesPage.fontSizeMap); 1376