1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 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) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 ZmMailPrefsPage = function(parent, section, controller) { 25 ZmPreferencesPage.apply(this, arguments); 26 27 this._initialized = false; 28 }; 29 30 ZmMailPrefsPage.prototype = new ZmPreferencesPage; 31 ZmMailPrefsPage.prototype.constructor = ZmMailPrefsPage; 32 33 ZmMailPrefsPage.prototype.isZmMailPrefsPage = true; 34 ZmMailPrefsPage.prototype.toString = function() { return "ZmMailPrefsPage"; }; 35 36 // 37 // ZmPreferencesPage methods 38 // 39 40 ZmMailPrefsPage.prototype.showMe = 41 function() { 42 ZmPreferencesPage.prototype.showMe.call(this); 43 if(appCtxt.isOffline){ 44 if(this._initializedAcctId != appCtxt.getActiveAccount().id) { 45 this._initialized = false; 46 this._initializedAcctId = appCtxt.getActiveAccount().id; 47 } 48 } 49 if (!this._initialized) { 50 this._initialized = true; 51 if (this._blackListControl && this._whiteListControl) { 52 var soapDoc = AjxSoapDoc.create("GetWhiteBlackListRequest", "urn:zimbraAccount"); 53 var callback = new AjxCallback(this, this._handleResponseLoadWhiteBlackList); 54 appCtxt.getRequestMgr().sendRequest({soapDoc:soapDoc, asyncMode:true, callback:callback}); 55 } 56 } 57 }; 58 59 ZmMailPrefsPage.prototype.reset = 60 function(useDefaults) { 61 ZmPreferencesPage.prototype.reset.apply(this, arguments); 62 63 this._duration = 0; 64 var noDuration = true; 65 if (this._startDateVal) { 66 noDuration = (this._startDateVal.value == null || this._startDateVal.value == ""); 67 this._initStartEndDisplayFields(); 68 } 69 70 71 var cbox = this.getFormObject(ZmSetting.VACATION_MSG_ENABLED); 72 if (cbox) { 73 this._handleEnableVacationMsg(cbox, noDuration); 74 // HandleEnableVacationMsg will alter other (non-persisted) settings - update 75 // their 'original' values so the section will not be thought dirty upon exit 76 this._updateOriginalValue(ZmSetting.VACATION_DURATION_ENABLED); 77 this._updateOriginalValue(ZmSetting.VACATION_CALENDAR_ENABLED); 78 } 79 this._initialAllDayFlag = this._allDayCheckbox ? this._allDayCheckbox.isSelected() : true; 80 this._updateOriginalValue(ZmSetting.VACATION_DURATION_ALL_DAY); 81 82 83 this._setPopDownloadSinceControls(); 84 85 if (this._blackListControl && this._whiteListControl) { 86 this._blackListControl.reset(); 87 this._whiteListControl.reset(); 88 } 89 }; 90 91 ZmMailPrefsPage.prototype.isDirty = 92 function() { 93 var isDirty = ZmPreferencesPage.prototype.isDirty.call(this); 94 return (!isDirty) ? this.isWhiteBlackListDirty() : isDirty; 95 }; 96 97 ZmMailPrefsPage.prototype.isWhiteBlackListDirty = 98 function() { 99 if (this._blackListControl && this._whiteListControl) { 100 return this._blackListControl.isDirty() || 101 this._whiteListControl.isDirty(); 102 } 103 return false; 104 }; 105 106 ZmMailPrefsPage.prototype.addCommand = 107 function(batchCmd) { 108 if (this.isWhiteBlackListDirty()) { 109 var soapDoc = AjxSoapDoc.create("ModifyWhiteBlackListRequest", "urn:zimbraAccount"); 110 this._blackListControl.setSoapContent(soapDoc, "blackList"); 111 this._whiteListControl.setSoapContent(soapDoc, "whiteList"); 112 113 var respCallback = new AjxCallback(this, this._handleResponseModifyWhiteBlackList); 114 batchCmd.addNewRequestParams(soapDoc, respCallback); 115 } 116 }; 117 118 ZmMailPrefsPage.prototype._handleResponseModifyWhiteBlackList = 119 function(result) { 120 this._blackListControl.saveLocal(); 121 this._whiteListControl.saveLocal(); 122 }; 123 124 ZmMailPrefsPage.prototype._setPopDownloadSinceControls = 125 function() { 126 var popDownloadSinceValue = this.getFormObject(ZmSetting.POP_DOWNLOAD_SINCE_VALUE); 127 var value = appCtxt.get(ZmSetting.POP_DOWNLOAD_SINCE); 128 if (popDownloadSinceValue && value) { 129 var date = AjxDateFormat.parse("yyyyMMddHHmmss'Z'", value); 130 date.setMinutes(date.getMinutes() - date.getTimezoneOffset()); 131 132 popDownloadSinceValue.setText(AjxMessageFormat.format(ZmMsg.externalAccessPopCurrentValue, date)); 133 popDownloadSinceValue.setVisible(true); 134 } else if( popDownloadSinceValue ) { 135 popDownloadSinceValue.setVisible(false); 136 } 137 138 var popDownloadSince = this.getFormObject(ZmSetting.POP_DOWNLOAD_SINCE); 139 if (popDownloadSince) { 140 popDownloadSince.setSelectedValue(appCtxt.get(ZmSetting.POP_DOWNLOAD_SINCE)); 141 } 142 }; 143 144 ZmMailPrefsPage.prototype._createControls = 145 function() { 146 AjxDispatcher.require(["MailCore", "CalendarCore"]); 147 ZmPreferencesPage.prototype._createControls.apply(this, arguments); 148 149 this._sId = this._htmlElId + "_startMiniCal"; 150 this._eId = this._htmlElId + "_endMiniCal"; 151 152 153 this._startDateField = Dwt.byId(this._htmlElId + "_VACATION_FROM1"); 154 this._endDateField = Dwt.byId(this._htmlElId + "_VACATION_UNTIL1"); 155 156 if (this._startDateField && this._endDateField) { 157 this._startDateVal = Dwt.byId(this._htmlElId + "_VACATION_FROM"); 158 this._endDateVal = Dwt.byId(this._htmlElId + "_VACATION_UNTIL"); 159 if(this._startDateVal.value.length < 15){ 160 this._startDateVal.value = appCtxt.get(ZmSetting.VACATION_FROM); 161 } 162 if(this._endDateVal.value.length < 15){ 163 this._endDateVal.value = appCtxt.get(ZmSetting.VACATION_UNTIL); 164 } 165 166 this._formatter = new AjxDateFormat("yyyyMMddHHmmss'Z'"); 167 168 var timeSelectListener = new AjxListener(this, this._timeChangeListener); 169 this._startTimeSelect = new DwtTimeInput(this, DwtTimeInput.START); 170 this._startTimeSelect.reparentHtmlElement(this._htmlElId + "_VACATION_FROM_TIME"); 171 this._endTimeSelect = new DwtTimeInput(this, DwtTimeInput.END); 172 this._endTimeSelect.reparentHtmlElement(this._htmlElId + "_VACATION_UNTIL_TIME"); 173 this._startTimeSelect.addChangeListener(timeSelectListener); 174 this._endTimeSelect.addChangeListener(timeSelectListener); 175 176 var noDuration = (this._startDateVal.value == null || this._startDateVal.value == ""); 177 this._initStartEndDisplayFields(); 178 179 var dateButtonListener = new AjxListener(this, this._dateButtonListener); 180 var dateCalSelectionListener = new AjxListener(this, this._dateCalSelectionListener); 181 var dateFieldListener = AjxCallback.simpleClosure(this._dateFieldListener, this); 182 183 this._startDateButton = ZmCalendarApp.createMiniCalButton(this, this._sId, dateButtonListener, dateCalSelectionListener); 184 this._endDateButton = ZmCalendarApp.createMiniCalButton(this, this._eId, dateButtonListener, dateCalSelectionListener); 185 186 Dwt.setHandler(this._startDateField, DwtEvent.ONBLUR, dateFieldListener); 187 Dwt.setHandler(this._endDateField, DwtEvent.ONBLUR, dateFieldListener); 188 189 this._durationCheckbox = this.getFormObject(ZmSetting.VACATION_DURATION_ENABLED); 190 this._allDayCheckbox = this.getFormObject(ZmSetting.VACATION_DURATION_ALL_DAY); 191 // Base initial _allDayCheckbox.checked on whether the start is Midnight and end 192 // is 23:59:59 (which fortunately cannot be directly specified by the user). 193 // Do this because we do not have any linkage to the OOO appt. 194 var prefStartDate = this._getPrefDate(ZmSetting.VACATION_FROM); 195 var prefEndDate = this._getPrefDate(ZmSetting.VACATION_UNTIL); 196 if ((prefStartDate != null) && (prefEndDate != null)) { 197 var startDate = new Date(prefStartDate); 198 startDate.setHours(0, 0, 0, 0); //we set this just to compare - took me a while to figure out 199 var endDate = new Date(prefEndDate); 200 endDate.setHours(23, 59, 59, 0); //we set this just to compare. 201 this._initialAllDayFlag = ((prefStartDate.getTime() == startDate.getTime()) && 202 (prefEndDate.getTime() == endDate.getTime())); 203 } else { 204 this._initialAllDayFlag = true; 205 } 206 this._allDayCheckbox.setSelected(this._initialAllDayFlag); 207 this._updateOriginalValue(ZmSetting.VACATION_DURATION_ALL_DAY); 208 } 209 210 211 212 var cbox = this.getFormObject(ZmSetting.VACATION_MSG_ENABLED); 213 if (cbox) { 214 this._handleEnableVacationMsg(cbox, noDuration); 215 // HandleEnableVacationMsg will alter other (non-persisted) settings - update 216 // their 'orginal' values so the section will not be thought dirty upon exit 217 this._updateOriginalValue(ZmSetting.VACATION_DURATION_ENABLED); 218 this._updateOriginalValue(ZmSetting.VACATION_CALENDAR_ENABLED); 219 } 220 221 // enable downloadSince appropriately based on presence of downloadSinceEnabled 222 var downloadSinceCbox = this.getFormObject(ZmSetting.POP_DOWNLOAD_SINCE_ENABLED); 223 if (downloadSinceCbox) { 224 var downloadSince = this.getFormObject(ZmSetting.POP_DOWNLOAD_SINCE); 225 if (downloadSince) { 226 var enabled = downloadSince.getValue() != ""; 227 downloadSinceCbox.setSelected(enabled); 228 downloadSince.setEnabled(enabled); 229 } 230 } 231 232 // Following code makes child nodes as siblings to separate the 233 // event-handling between labels and input 234 var inputId = DwtId.makeId(ZmId.WIDGET_INPUT, ZmId.OP_MARK_READ); 235 var inputPlaceholder = Dwt.byId(inputId); 236 237 if (inputPlaceholder) { 238 var radioButton = DwtControl.findControl(inputPlaceholder); 239 var index = AjxUtil.indexOf(radioButton.parent.getChildren(), 240 radioButton); 241 var inputControl = new DwtInputField({ 242 parent: radioButton.parent, 243 index: index + 1, 244 id: inputId, 245 size: 4, 246 hint: '0', 247 }); 248 inputControl.replaceElement(inputPlaceholder); 249 inputControl.setDisplay(Dwt.DISPLAY_INLINE); 250 251 // Toggle the setting when editing the time input; it already recieves 252 // focus on click, so this is mainly for keyboard navigation. (Except 253 // on IE8, where the 'oninput' event doesn't work.) 254 inputControl.setHandler(DwtEvent.ONINPUT, function(ev) { 255 if (inputControl.getValue()) { 256 this.setFormValue(ZmSetting.MARK_MSG_READ, 257 ZmSetting.MARK_READ_TIME); 258 } 259 }.bind(this)); 260 261 // If pref's value is number of seconds, populate the input 262 var value = appCtxt.get(ZmSetting.MARK_MSG_READ); 263 if (value > 0) { 264 inputControl.setValue(value); 265 } 266 } 267 268 var composeMore = Dwt.byId(this.getHTMLElId() + '_compose_more'); 269 if (composeMore) { 270 var links = AjxUtil.toArray(composeMore.getElementsByTagName('A')); 271 272 for (var i = 0; i < links.length; i++) { 273 var link = links[i]; 274 var accountsText = new DwtText({ 275 parent: this, 276 className: 'FakeAnchor' 277 }); 278 accountsText.setContent(AjxUtil.getInnerText(link)); 279 accountsText.setDisplay(Dwt.DISPLAY_INLINE); 280 accountsText.replaceElement(link); 281 accountsText._setEventHdlrs([DwtEvent.ONCLICK]); 282 accountsText.addListener(DwtEvent.ONCLICK, 283 skin.gotoPrefs.bind(skin, "ACCOUNTS")); 284 } 285 } 286 287 this._setPopDownloadSinceControls(); 288 }; 289 290 291 ZmMailPrefsPage.prototype._getPrefDate = 292 function(settingName) { 293 var prefDate = null; 294 var prefDateText = appCtxt.get(settingName); 295 if (prefDateText && (prefDateText != "")) { 296 prefDate = this._formatter.parse(AjxDateUtil.dateGMT2Local(prefDateText)); 297 } 298 return prefDate; 299 } 300 301 ZmMailPrefsPage.prototype._initStartEndDisplayFields = 302 function() { 303 var startDate = new Date(); 304 startDate.setHours(0,0,0,0); 305 this._initDateTimeDisplayField(this._startDateVal, this._startTimeSelect, 306 this._startDateField, startDate); 307 308 var endDate = new Date(startDate); 309 // Defaulting to 11:59 PM. Ignored for all day 310 endDate.setHours(23,59,0,0); 311 this._initDateTimeDisplayField(this._endDateVal, this._endTimeSelect, 312 this._endDateField, endDate); 313 314 this._calcDuration(); 315 } 316 317 ZmMailPrefsPage.prototype._initDateTimeDisplayField = 318 function(dateVal, timeSelect, dateField, date) { 319 var dateValue = (dateVal.value != null && dateVal.value != "") 320 ? (this._formatter.parse(dateVal.value)) : date; 321 timeSelect.set(dateValue); 322 dateValue = timeSelect.getValue(dateValue); 323 dateVal.value = this._formatter.format(dateValue); 324 dateField.value = AjxDateUtil.simpleComputeDateStr(dateValue); 325 } 326 327 ZmMailPrefsPage.prototype._updateOriginalValue = 328 function(id) { 329 var cbox = this.getFormObject(id); 330 if (cbox) { 331 var pref = appCtxt.getSettings().getSetting(id); 332 pref.origValue = cbox.isSelected(); 333 pref.value = pref.origValue; 334 } 335 }; 336 337 ZmMailPrefsPage.prototype._dateButtonListener = 338 function(ev) { 339 var calDate = ev.item == this._startDateButton 340 ? this._fixAndGetValidDateFromField(this._startDateField) 341 : this._fixAndGetValidDateFromField(this._endDateField); 342 343 var menu = ev.item.getMenu(); 344 var cal = menu.getItem(0); 345 cal.setDate(calDate, true); 346 ev.item.popup(); 347 }; 348 349 ZmMailPrefsPage.prototype._fixAndGetValidDateFromField = 350 function(field) { 351 var d = AjxDateUtil.simpleParseDateStr(field.value); 352 if (!d || isNaN(d)) { 353 d = new Date(); 354 field.value = AjxDateUtil.simpleComputeDateStr(d); 355 } 356 return d; 357 }; 358 359 ZmMailPrefsPage.prototype._dateCalSelectionListener = 360 function(ev) { 361 var parentButton = ev.item.parent.parent; 362 363 var newDate = AjxDateUtil.simpleComputeDateStr(ev.detail); 364 365 if (parentButton == this._startDateButton) { 366 this._startDateField.value = newDate; 367 } else { 368 if (ev.detail < new Date()) { return; } 369 this._endDateField.value = newDate; 370 } 371 372 var sd = this._fixAndGetValidDateFromField(this._startDateField); 373 var ed = this._fixAndGetValidDateFromField(this._endDateField); 374 if(this._startTimeSelect && this._endTimeSelect){ 375 sd = this._startTimeSelect.getValue(sd); 376 ed = this._endTimeSelect.getValue(ed); 377 } 378 379 380 this._fixDates(sd, ed, parentButton == this._endDateButton); 381 this._calcDuration(); 382 383 if (this._durationCheckbox.isSelected()) { 384 this._startDateVal.value = this._formatter.format(sd); 385 this._endDateVal.value = this._formatter.format(ed); 386 } 387 }; 388 389 ZmMailPrefsPage.prototype._calcDuration = 390 function() { 391 var sd = this._fixAndGetValidDateFromField(this._startDateField); 392 var ed = this._fixAndGetValidDateFromField(this._endDateField); 393 394 var sdDay = new Date(sd.getTime()); 395 var edDay = new Date(ed.getTime()); 396 sdDay.setHours(0, 0, 0, 0); 397 edDay.setHours(0, 0, 0, 0); 398 this._duration = edDay.getTime() - sdDay.getTime(); 399 DBG.println(AjxDebug.DBG3, "ZmMailPrefsPage._calcDuration: Start=" + AjxDateUtil.simpleComputeDateStr(sdDay) + 400 ", End=" + AjxDateUtil.simpleComputeDateStr(edDay) + ", duration=" + this._duration); 401 } 402 403 ZmMailPrefsPage.prototype._dateFieldListener = 404 function(ev) { 405 var sd = this._fixAndGetValidDateFromField(this._startDateField); 406 var ed = this._fixAndGetValidDateFromField(this._endDateField); 407 if(this._startTimeSelect && this._endTimeSelect){ 408 sd = this._startTimeSelect.getValue(sd); 409 ed = this._endTimeSelect.getValue(ed); 410 } 411 this._fixDates(sd, ed, DwtUiEvent.getTarget(ev) == this._endDateField); 412 this._calcDuration(); 413 this._startDateVal.value = this._formatter.format(AjxDateUtil.simpleParseDateStr(this._startDateField.value)); 414 this._endDateVal.value = this._formatter.format(AjxDateUtil.simpleParseDateStr(this._endDateField.value)); 415 }; 416 417 ZmMailPrefsPage.prototype._timeChangeListener = 418 function(ev) { 419 var stDate = AjxDateUtil.simpleParseDateStr(this._startDateField.value); 420 var endDate = AjxDateUtil.simpleParseDateStr(this._endDateField.value); 421 stDate = this._startTimeSelect.getValue(stDate); 422 endDate = this._endTimeSelect.getValue(endDate); 423 this._startDateVal.value = this._formatter.format(stDate); 424 this._endDateVal.value = this._formatter.format(endDate); 425 }; 426 427 /* Fixes the field values so that end date always is later than or equal to start date 428 * @param startDate {Date} The value of the start date field or calendar selection 429 * @param endDate {Date} The value of the end date field or calendar selection 430 * @param endModified {boolean} endDate was changed - don't preserve the duration 431 */ 432 ZmMailPrefsPage.prototype._fixDates = 433 function(startDate, endDate, endModified) { 434 var startDateNoTimeOffset = new Date(startDate.getTime()); 435 startDateNoTimeOffset.setHours(0,0,0,0); 436 var endDateNoTimeOffset = new Date(endDate.getTime()); 437 endDateNoTimeOffset.setHours(0,0,0,0); 438 439 if (startDateNoTimeOffset >= endDateNoTimeOffset) { 440 // Start date after end date 441 if (endModified) { 442 // EndDate was set to be prior to the startDate - set them to be equal 443 this._startDateField.value = AjxDateUtil.simpleComputeDateStr(endDate); 444 DBG.println(AjxDebug.DBG3, "ZmMailPrefsPage._fixDates: endModified, set start == end"); 445 } else { 446 // StartDate modified - preserve the duration 447 var newEndDate = new Date(startDateNoTimeOffset.getTime() + this._duration); 448 this._endDateField.value = AjxDateUtil.simpleComputeDateStr(newEndDate); 449 DBG.println(AjxDebug.DBG3, "ZmMailPrefsPage._fixDates: Start=" + AjxDateUtil.simpleComputeDateStr(startDate) + 450 ", End=" + AjxDateUtil.simpleComputeDateStr(newEndDate) + ", duration=" + this._duration); 451 } 452 } 453 }; 454 455 ZmMailPrefsPage.prototype._setupCheckbox = 456 function(id, setup, value) { 457 var cbox = ZmPreferencesPage.prototype._setupCheckbox.apply(this, arguments); 458 if (id == ZmSetting.VACATION_CALENDAR_ENABLED || 459 id == ZmSetting.VACATION_DURATION_ENABLED || 460 id == ZmSetting.VACATION_DURATION_ALL_DAY) 461 { 462 cbox.addSelectionListener(new AjxListener(this, this._handleEnableVacationMsg, [cbox, false, id])); 463 } 464 return cbox; 465 }; 466 467 ZmMailPrefsPage.prototype._setupRadioGroup = 468 function(id, setup, value) { 469 var control = ZmPreferencesPage.prototype._setupRadioGroup.apply(this, arguments); 470 if (id == ZmSetting.POP_DOWNLOAD_SINCE) { 471 var radioGroup = this.getFormObject(id); 472 var radioButton = radioGroup.getRadioButtonByValue(ZmMailApp.POP_DOWNLOAD_SINCE_NO_CHANGE); 473 radioButton.setVisible(false); 474 } 475 else if (id == ZmSetting.VACATION_MSG_ENABLED) { 476 var radioGroup = this.getFormObject(id); 477 radioGroup.addSelectionListener(new AjxListener(this, this._handleEnableVacationMsg, [radioGroup, false, id])); 478 } 479 return control; 480 }; 481 482 ZmMailPrefsPage.prototype._setupCustom = 483 function(id, setup, value) { 484 if (id == ZmSetting.MAIL_BLACKLIST) { 485 this._blackListControl = new ZmWhiteBlackList(this, id, "BlackList"); 486 return this._blackListControl; 487 } 488 489 if (id == ZmSetting.MAIL_WHITELIST) { 490 this._whiteListControl = new ZmWhiteBlackList(this, id, "WhiteList"); 491 return this._whiteListControl; 492 } 493 }; 494 495 ZmMailPrefsPage.prototype._handleResponseLoadWhiteBlackList = 496 function(result) { 497 var resp = result.getResponse().GetWhiteBlackListResponse; 498 this._blackListControl.loadFromJson(resp.blackList[0].addr); 499 this._whiteListControl.loadFromJson(resp.whiteList[0].addr); 500 }; 501 502 503 // 504 // Protected methods 505 // 506 507 ZmMailPrefsPage.prototype._handleEnableVacationMsg = 508 function(cbox, noDuration, id, evt) { 509 var textarea = this.getFormObject(ZmSetting.VACATION_MSG); 510 var extTextarea = this.getFormObject(ZmSetting.VACATION_EXTERNAL_MSG); 511 var externalTypeSelect = this.getFormObject(ZmSetting.VACATION_EXTERNAL_SUPPRESS); 512 if (textarea) { 513 if (id == ZmSetting.VACATION_DURATION_ALL_DAY) { 514 this._enableDateTimeControls(true); 515 } else if (id == ZmSetting.VACATION_DURATION_ENABLED) { 516 this._allDayCheckbox.setEnabled(cbox.isSelected()); 517 this._enableDateTimeControls(cbox.isSelected()); 518 var calCheckBox = this.getFormObject(ZmSetting.VACATION_CALENDAR_ENABLED); 519 calCheckBox.setEnabled(cbox.isSelected()); 520 var calendarType = this.getFormObject(ZmSetting.VACATION_CALENDAR_TYPE); 521 calendarType.setEnabled(calCheckBox.isSelected() && cbox.isSelected()); 522 }else if(id == ZmSetting.VACATION_CALENDAR_ENABLED){ 523 var calendarType = this.getFormObject(ZmSetting.VACATION_CALENDAR_TYPE); 524 calendarType.setEnabled(cbox.isSelected()); 525 }else { 526 527 // MESSAGE_ENABLED, main On/Off switch 528 var enabled = cbox.getSelectedValue()=="true"; 529 textarea.setEnabled(enabled); 530 531 this._durationCheckbox.setEnabled(enabled); 532 var val = this._startDateVal.value && enabled ? true : false; 533 this._durationCheckbox.setSelected((val && !noDuration)); 534 535 var calCheckBox = this.getFormObject(ZmSetting.VACATION_CALENDAR_ENABLED); 536 calCheckBox.setEnabled((this._durationCheckbox.isSelected() || appCtxt.get(ZmSetting.VACATION_DURATION_ENABLED)) && enabled); 537 calCheckBox.setSelected(enabled && (appCtxt.get(ZmSetting.VACATION_CALENDAR_APPT_ID) != "-1")); 538 539 var calendarType = this.getFormObject(ZmSetting.VACATION_CALENDAR_TYPE); 540 calendarType.setEnabled(calCheckBox.isSelected() && this._durationCheckbox.isSelected() && enabled); 541 externalTypeSelect.setEnabled(enabled); 542 extTextarea.setEnabled(enabled); 543 this._allDayCheckbox.setEnabled(enabled && this._durationCheckbox.isSelected()); 544 this._enableDateTimeControls(enabled && this._durationCheckbox.isSelected()); 545 } 546 } 547 }; 548 549 ZmMailPrefsPage.prototype._enableDateTimeControls = 550 function(enableDate) { 551 this._setEnabledStartDate(enableDate); 552 this._setEnabledEndDate(enableDate); 553 var enableTime = enableDate && !this._allDayCheckbox.isSelected(); 554 this._startTimeSelect.setEnabled(enableTime); 555 this._endTimeSelect.setEnabled(enableTime); 556 } 557 558 ZmMailPrefsPage.prototype._setEnabledStartDate = 559 function(val) { 560 var condition = val && this._durationCheckbox.isSelected(); 561 this._startDateField.disabled = !condition; 562 this._startDateButton.setEnabled(condition); 563 var stDateVal = AjxDateUtil.simpleParseDateStr(this._startDateField.value); 564 if(this._startTimeSelect){stDateVal = this._startTimeSelect.getValue(stDateVal);} 565 this._startDateVal.value = (!condition) 566 ? "" : (this._formatter.format(stDateVal)); 567 }; 568 569 ZmMailPrefsPage.prototype._setEnabledEndDate = 570 function(val) { 571 //this._endDateCheckbox.setEnabled(val); 572 var condition = val && this._durationCheckbox.isSelected(); 573 this._endDateField.disabled = !condition; 574 this._endDateButton.setEnabled(condition); 575 var endDateVal = AjxDateUtil.simpleParseDateStr(this._endDateField.value); 576 if(this._endTimeSelect){endDateVal = this._endTimeSelect.getValue(endDateVal);} 577 this._endDateVal.value = (!condition) 578 ? "" : (this._formatter.format(endDateVal)); 579 }; 580 581 582 ZmMailPrefsPage.prototype.getPreSaveCallback = 583 function() { 584 return new AjxCallback(this, this._preSave); 585 }; 586 587 ZmMailPrefsPage.prototype._preSave = 588 function(callback) { 589 if (this._startDateField && this._endDateField) { 590 var stDate = AjxDateUtil.simpleParseDateStr(this._startDateField.value); 591 var endDate = AjxDateUtil.simpleParseDateStr(this._endDateField.value); 592 593 var allDay = this._allDayCheckbox.isSelected(); 594 if (!allDay) { 595 // Add in time fields if not all-day 596 stDate = this._startTimeSelect.getValue(stDate); 597 endDate = this._endTimeSelect.getValue(endDate); 598 } else { 599 // For the prefs, need to set the all day end time 600 endDate.setHours(23, 59, 59, 0); 601 } 602 if (this._startDateField.disabled) { 603 this._startDateVal.value = ""; 604 } else { 605 this._startDateVal.value = this._formatter.format(stDate); 606 } 607 if (this._endDateField.disabled) { 608 this._endDateVal.value = ""; 609 } else { 610 this._endDateVal.value = this._formatter.format(endDate); 611 } 612 613 this._oldStartDate = appCtxt.get(ZmSetting.VACATION_FROM); 614 this._oldEndDate = appCtxt.get(ZmSetting.VACATION_UNTIL); 615 } 616 617 if (callback) { 618 callback.run(); 619 } 620 }; 621 622 ZmMailPrefsPage.prototype.getPostSaveCallback = 623 function() { 624 return new AjxCallback(this, this._postSave); 625 }; 626 627 ZmMailPrefsPage.prototype._postSave = 628 function(changed) { 629 var form = this.getFormObject(ZmSetting.POLLING_INTERVAL); 630 var polling = form && form.getSelectedOption() && form.getSelectedOption().getDisplayValue(); 631 if (polling) { 632 // A polling value is specified - apply it 633 if (polling == ZmMsg.pollInstant) { 634 // Instant notify is selected 635 if (appCtxt.get(ZmSetting.INSTANT_NOTIFY) && !appCtxt.getAppController().getInstantNotify()) { 636 // Instant notify is not operating - Turn it on 637 appCtxt.getAppController().setInstantNotify(true); 638 } 639 } else if (appCtxt.getAppController().getInstantNotify()) { 640 // Instant notify is not selected, but is currently operating - Turn it off 641 appCtxt.getAppController().setInstantNotify(false); 642 } 643 } 644 645 var vacationChangePrefs = [ 646 ZmSetting.VACATION_MSG_ENABLED, 647 ZmSetting.VACATION_FROM, 648 ZmSetting.VACATION_UNTIL 649 ]; 650 651 var modified = false; 652 for (var i = 0; i < vacationChangePrefs.length; i++) { 653 if (changed[vacationChangePrefs[i]]) { 654 modified = true; 655 break; 656 } 657 } 658 if (modified) { 659 var soapDoc = AjxSoapDoc.create("ModifyPrefsRequest", "urn:zimbraAccount"); 660 var node = soapDoc.set("pref", "TRUE"); 661 node.setAttribute("name", "zimbraPrefOutOfOfficeStatusAlertOnLogin"); 662 appCtxt.getAppController().sendRequest({soapDoc:soapDoc, asyncMode:true}); 663 } 664 665 //if old end date was greater than today then fetch appt id from metadata and delete the old appointment 666 var now = new Date(); 667 if (appCtxt.get(ZmSetting.VACATION_CALENDAR_APPT_ID) != "-1" && this._formatter && this._oldEndDate && 668 this._formatter.parse(AjxDateUtil.dateGMT2Local(this._oldEndDate)) > now) 669 { 670 ZmAppt.loadById(appCtxt.get(ZmSetting.VACATION_CALENDAR_APPT_ID),new AjxCallback(this, this._oooDeleteApptCallback)); 671 } 672 if (this._durationCheckbox && this._durationCheckbox.isSelected()) { 673 //Create calendar appointments for this out of office request. 674 var calCheckBox = this.getFormObject(ZmSetting.VACATION_CALENDAR_ENABLED); 675 if (calCheckBox && calCheckBox.isSelected()) { 676 var stDate = this._getPrefDate(ZmSetting.VACATION_FROM); 677 var endDate = this._getPrefDate(ZmSetting.VACATION_UNTIL); 678 var allDay = this._allDayCheckbox.isSelected(); 679 if (stDate != null && endDate != null) { 680 if (allDay) { 681 // Strip the time of day information - calendar view 682 // creates all-day appt with just day info 683 endDate.setHours(0,0,0,0); 684 } 685 var calController = appCtxt.getApp(ZmApp.CALENDAR).getCalController(); 686 calController.createAppointmentFromOOOPref(stDate,endDate, allDay, new AjxCallback(this, this._oooApptCallback)); 687 } 688 } 689 } 690 }; 691 692 ZmMailPrefsPage.prototype._oooDeleteApptCallback = function(appt){ 693 if (appt) { 694 var calController = appCtxt.getApp(ZmApp.CALENDAR).getCalController(); 695 calController._continueDelete(appt, ZmCalItem.MODE_DELETE); 696 appCtxt.set(ZmSetting.VACATION_CALENDAR_APPT_ID, "-1"); 697 } 698 }; 699 700 ZmMailPrefsPage.prototype._oooApptCallback = function(response){ 701 //store the appt id as meta data 702 if (response && response.apptId) { 703 appCtxt.set(ZmSetting.VACATION_CALENDAR_APPT_ID, response.apptId); 704 } 705 appCtxt.setStatusMsg(ZmMsg.oooStatus); 706 } 707 708 ZmMailPrefsPage.prototype._convModeChangeYesCallback = 709 function(dialog) { 710 dialog.popdown(); 711 window.onbeforeunload = null; 712 var url = AjxUtil.formatUrl(); 713 DBG.println(AjxDebug.DBG1, "Conv mode change, redirect to: " + url); 714 ZmZimbraMail.sendRedirect(url); // redirect to self to force reload 715 }; 716 717 // ??? SHOULD THIS BE IN A NEW FILE? ??? 718 // ??? IT IS ONLY USED BY ZmMailPrefsPage. ??? 719 /** 720 * Custom control used to handle adding/removing addresses for white/black list 721 * 722 * @param parent 723 * @param id 724 * 725 * @private 726 */ 727 ZmWhiteBlackList = function(parent, id, templateId) { 728 DwtComposite.call(this, {parent:parent}); 729 730 this._settingId = id; 731 switch(id) { 732 case ZmSetting.MAIL_BLACKLIST: 733 this._max = appCtxt.get(ZmSetting.MAIL_BLACKLIST_MAX_NUM_ENTRIES); 734 break; 735 case ZmSetting.MAIL_WHITELIST: 736 this._max = appCtxt.get(ZmSetting.MAIL_WHITELIST_MAX_NUM_ENTRIES); 737 break; 738 case ZmSetting.TRUSTED_ADDR_LIST: 739 this._max = appCtxt.get(ZmSetting.TRUSTED_ADDR_LIST_MAX_NUM_ENTRIES); 740 break; 741 } 742 this._setContent(templateId); 743 744 this._list = []; 745 this._add = {}; 746 this._remove = {}; 747 }; 748 749 ZmWhiteBlackList.prototype = new DwtComposite; 750 ZmWhiteBlackList.prototype.constructor = ZmWhiteBlackList; 751 ZmWhiteBlackList.prototype.isZmWhiteBlackList = true; 752 753 ZmWhiteBlackList.prototype.toString = 754 function() { 755 return "ZmWhiteBlackList"; 756 }; 757 758 ZmWhiteBlackList.prototype.reset = 759 function() { 760 this._inputEl.setValue(""); 761 this._listView.set(AjxVector.fromArray(this._list).clone(), null, true); 762 this._add = {}; 763 this._remove = {}; 764 765 this.updateNumUsed(); 766 }; 767 768 ZmWhiteBlackList.prototype.getValue = 769 function() { 770 return this._listView.getList().clone().getArray().join(',').replace(';', ',').split(','); 771 }; 772 773 774 ZmWhiteBlackList.prototype.loadFromJson = 775 function(data) { 776 if (data) { 777 for (var i = 0; i < data.length; i++) { 778 var content = AjxUtil.isSpecified(data[i]._content) ? data[i]._content : data[i]; 779 if(content){ 780 var item = this._addEmail(content); 781 this._list.push(item); 782 } 783 } 784 } 785 this.updateNumUsed(); 786 }; 787 788 ZmWhiteBlackList.prototype.setSoapContent = 789 function(soapDoc, method) { 790 if (!this.isDirty()) { return; } 791 792 var methodEl = soapDoc.set(method); 793 794 for (var i in this._add) { 795 var addrEl = soapDoc.set("addr", i, methodEl); 796 addrEl.setAttribute("op", "+"); 797 } 798 799 for (var i in this._remove) { 800 var addrEl = soapDoc.set("addr", i, methodEl); 801 addrEl.setAttribute("op", "-"); 802 } 803 }; 804 805 ZmWhiteBlackList.prototype.isDirty = 806 function() { 807 var isDirty = false; 808 809 for (var i in this._add) { 810 isDirty = true; 811 break; 812 } 813 814 if (!isDirty) { 815 for (var i in this._remove) { 816 isDirty = true; 817 break; 818 } 819 } 820 821 return isDirty; 822 }; 823 824 ZmWhiteBlackList.prototype.saveLocal = 825 function() { 826 if (this.isDirty()) { 827 this._list = this._listView.getList().clone().getArray(); 828 this._add = {}; 829 this._remove = {}; 830 } 831 }; 832 833 ZmWhiteBlackList.prototype.updateNumUsed = 834 function() { 835 this._numUsedText.innerHTML = AjxMessageFormat.format(ZmMsg.whiteBlackNumUsed, [this._listView.size(), this._max]); 836 }; 837 838 ZmWhiteBlackList.prototype._setContent = 839 function(templateId) { 840 this.getHtmlElement().innerHTML = AjxTemplate.expand("prefs.Pages#"+templateId, {id:this._htmlElId}); 841 842 var id = this._htmlElId + "_EMAIL_ADDRESS"; 843 var el = document.getElementById(id); 844 this._inputEl = new DwtInputField({parent:this, parentElement:id, size:35, hint:ZmMsg.enterEmailAddressOrDomain}); 845 this._inputEl.getInputElement().style.width = "210px"; 846 this._inputEl._showHint(); 847 this._inputEl.addListener(DwtEvent.ONKEYUP, new AjxListener(this, this._handleKeyUp)); 848 this.parent._addControlTabIndex(el, this._inputEl); 849 850 id = this._htmlElId + "_LISTVIEW"; 851 el = document.getElementById(id); 852 this._listView = new DwtListView({parent:this, parentElement:id}); 853 this._listView.addClassName("ZmWhiteBlackList"); 854 this.parent._addControlTabIndex(el, this._listView); 855 856 id = this._htmlElId + "_ADD_BUTTON"; 857 el = document.getElementById(id); 858 var addButton = new DwtButton({parent:this, parentElement:id}); 859 addButton.setText(ZmMsg.add); 860 addButton.addSelectionListener(new AjxListener(this, this._addListener)); 861 this.parent._addControlTabIndex(el, addButton); 862 863 id = this._htmlElId + "_REMOVE_BUTTON"; 864 el = document.getElementById(id); 865 var removeButton = new DwtButton({parent:this, parentElement:id}); 866 removeButton.setText(ZmMsg.remove); 867 removeButton.addSelectionListener(new AjxListener(this, this._removeListener)); 868 this.parent._addControlTabIndex(el, removeButton); 869 870 id = this._htmlElId + "_NUM_USED"; 871 this._numUsedText = document.getElementById(id); 872 }; 873 874 ZmWhiteBlackList.prototype._addEmail = 875 function(addr) { 876 var item = new ZmWhiteBlackListItem(addr); 877 this._listView.addItem(item, null, true); 878 return item; 879 }; 880 881 ZmWhiteBlackList.prototype._addListener = 882 function() { 883 if (this._listView.size() >= this._max) { 884 var dialog = appCtxt.getMsgDialog(); 885 dialog.setMessage(ZmMsg.errorWhiteBlackListExceeded); 886 dialog.popup(); 887 return; 888 } 889 890 var val, 891 items = AjxStringUtil.trim(this._inputEl.getValue(), true); 892 if (items.length) { 893 items = AjxStringUtil.split(items, [',', ';', ' ']); 894 for(var i=0; i<items.length; i++) { 895 val = items[i]; 896 if(val) { 897 this._addEmail(AjxStringUtil.htmlEncode(val)); 898 if (!this._add[val]) { 899 this._add[val] = true; 900 } 901 } 902 } 903 this._inputEl.setValue("", true); 904 this._inputEl.blur(); 905 this._inputEl.focus(); 906 907 this.updateNumUsed(); 908 } 909 }; 910 911 ZmWhiteBlackList.prototype._removeListener = 912 function() { 913 var items = this._listView.getSelection(); 914 for (var i = 0; i < items.length; i++) { 915 var item = items[i]; 916 this._listView.removeItem(item, true); 917 var addr = item.toString(); 918 if (this._add[addr]) { 919 delete this._add[addr]; 920 } else { 921 this._remove[addr] = true; 922 } 923 } 924 925 this.updateNumUsed(); 926 }; 927 928 ZmWhiteBlackList.prototype._handleKeyUp = 929 function(ev) { 930 var charCode = DwtKeyEvent.getCharCode(ev); 931 if (charCode == 13 || charCode == 3) { 932 this._addListener(); 933 } 934 }; 935 936 // Helper 937 ZmWhiteBlackListItem = function(addr) { 938 this.addr = addr; 939 this.id = Dwt.getNextId(); 940 }; 941 942 ZmWhiteBlackListItem.prototype.toString = 943 function() { 944 return this.addr; 945 }; 946