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 * Creates a generic quick add dialog (which basically mean it has different 25 * than regular dialogs). See "DwtSemiModalDialog" in Ajax widget templates 26 * for cosmetics. 27 * @constructor 28 * @class 29 * This class represents a modal dialog which has at least a title and the 30 * standard buttons (OK/Cancel). 31 * widgets (i.e. buttons, etc) as necessary. 32 * <p> 33 * Dialogs always hang off the main shell since their stacking order is managed 34 * through z-index. 35 * 36 * @author Parag Shah 37 * 38 * @param {ZmShell} parent parent widget (the shell) 39 * 40 * @extends ZmQuickAddDialog 41 * 42 */ 43 ZmApptQuickAddDialog = function(parent) { 44 // create extra "more details" button to be added at the footer of DwtDialog 45 var moreDetailsButton = new DwtDialog_ButtonDescriptor(ZmApptQuickAddDialog.MORE_DETAILS_BUTTON, 46 ZmMsg.moreDetails, DwtDialog.ALIGN_LEFT); 47 ZmQuickAddDialog.call(this, parent, null, null, [moreDetailsButton]); 48 DBG.timePt("ZmQuickAddDialog constructor", true); 49 50 AjxDispatcher.run("GetResources"); 51 AjxDispatcher.require(["MailCore", "CalendarCore"]); 52 53 var app = appCtxt.getApp(ZmApp.CALENDAR); 54 this._fbCache = new ZmFreeBusyCache(app); 55 56 var html = AjxTemplate.expand("calendar.Appointment#ZmApptQuickAddDialog", {id: this._htmlElId}); 57 this.setContent(html); 58 59 this.setTitle(ZmMsg.quickAddAppt); 60 DBG.timePt("create content"); 61 this._locations = []; 62 this._calendarOrgs = {}; 63 64 this._createDwtObjects(); 65 this._cacheFields(); 66 this._addEventHandlers(); 67 this._button[ZmApptQuickAddDialog.MORE_DETAILS_BUTTON].setSize("100"); 68 this._dateInfo = {}; 69 70 DBG.timePt("create dwt controls, fields; register handlers"); 71 }; 72 73 ZmApptQuickAddDialog.prototype = new ZmQuickAddDialog; 74 ZmApptQuickAddDialog.prototype.constructor = ZmApptQuickAddDialog; 75 76 77 // Consts 78 79 ZmApptQuickAddDialog.MORE_DETAILS_BUTTON = ++DwtDialog.LAST_BUTTON; 80 81 // Public 82 83 ZmApptQuickAddDialog.prototype.toString = 84 function() { 85 return "ZmApptQuickAddDialog"; 86 }; 87 88 89 ZmApptQuickAddDialog.prototype.getFreeBusyCache = 90 function() { 91 return this._fbCache; 92 } 93 94 ZmApptQuickAddDialog.prototype.initialize = 95 function(appt) { 96 this._appt = appt; 97 98 // reset fields... 99 this._subjectField.setValue(appt.getName() ? appt.getName() : ""); 100 this._locationField.setValue(appt.getLocation() ? appt.getLocation() : ""); 101 this._startDateField.value = AjxDateUtil.simpleComputeDateStr(appt.startDate); 102 this._endDateField.value = AjxDateUtil.simpleComputeDateStr(appt.endDate); 103 var isAllDay = appt.isAllDayEvent(); 104 this._showTimeFields(!isAllDay); 105 this._showAsSelect.setSelectedValue("B"); 106 if (!isAllDay) { 107 this._startTimeSelect.set(appt.startDate); 108 this._endTimeSelect.set(appt.endDate); 109 //need to capture initial time set while composing/editing appt 110 ZmApptViewHelper.getDateInfo(this, this._dateInfo); 111 } else { 112 this._dateInfo = {}; 113 this._showAsSelect.setSelectedValue("F"); 114 } 115 116 this._privacySelect.enable(); 117 this._privacySelect.setSelectedValue("PUB"); 118 this._calendarOrgs = {}; 119 ZmApptViewHelper.populateFolderSelect(this._folderSelect, this._folderRow, this._calendarOrgs, appt); 120 this._repeatSelect.setSelectedValue("NON"); 121 this._repeatDescField.innerHTML = ""; 122 this._origFormValue = this._formValue(); 123 this._locations = []; 124 }; 125 126 /** 127 * Gets the appointment. 128 * 129 * @return {ZmAppt} the appointment 130 */ 131 ZmApptQuickAddDialog.prototype.getAppt = 132 function() { 133 // create a copy of the appointment so we dont muck w/ the original 134 var appt = ZmAppt.quickClone(this._appt); 135 appt.setViewMode(ZmCalItem.MODE_NEW); 136 137 // save field values of this view w/in given appt 138 appt.setName(this._subjectField.getValue()); 139 appt.freeBusy = this._showAsSelect.getValue(); 140 appt.privacy = this._privacySelect.getValue(); 141 var calId = this._folderSelect.getValue(); 142 appt.setFolderId(calId); 143 appt.setOrganizer(this._calendarOrgs[calId]); 144 145 // set the start date by aggregating start date/time fields 146 var startDate = AjxDateUtil.simpleParseDateStr(this._startDateField.value); 147 var endDate = AjxDateUtil.simpleParseDateStr(this._endDateField.value); 148 if (this._appt.isAllDayEvent()) { 149 appt.setAllDayEvent(true); 150 if(AjxDateUtil.isDayShifted(startDate)) { 151 AjxDateUtil.rollToNextDay(startDate); 152 AjxDateUtil.rollToNextDay(endDate); 153 } 154 } else { 155 appt.setAllDayEvent(false); 156 startDate = this._startTimeSelect.getValue(startDate); 157 endDate = this._endTimeSelect.getValue(endDate); 158 } 159 appt.setStartDate(startDate); 160 appt.setEndDate(endDate); 161 appt.setRecurType(this._repeatSelect.getValue()); 162 appt.location = this._locationField.getValue(); 163 appt.setAttendees(this._locations, ZmCalBaseItem.LOCATION); 164 165 //set alarm for reminders 166 if (this._hasReminderSupport) { 167 appt.setReminderMinutes(this._reminderSelect.getValue()); 168 if (this._reminderEmailCheckbox && this._reminderEmailCheckbox.isSelected()) { 169 appt.addReminderAction(ZmCalItem.ALARM_EMAIL); 170 } 171 if (this._reminderDeviceEmailCheckbox && this._reminderDeviceEmailCheckbox.isSelected()) { 172 appt.addReminderAction(ZmCalItem.ALARM_DEVICE_EMAIL); 173 } 174 } 175 176 return appt; 177 }; 178 179 ZmApptQuickAddDialog.prototype.isValid = 180 function() { 181 var subj = AjxStringUtil.trim(this._subjectField.getValue()); 182 var errorMsg = null; 183 184 if (subj && subj.length) { 185 if (!DwtTimeInput.validStartEnd( this._startDateField, this._endDateField, this._startTimeSelect, this._endTimeSelect)) { 186 errorMsg = ZmMsg.errorInvalidDates; 187 } 188 } else { 189 errorMsg = ZmMsg.errorMissingSubject; 190 } 191 if (errorMsg) { 192 var dlg = appCtxt.getMsgDialog(); 193 dlg.setMessage(errorMsg, DwtMessageDialog.WARNING_STYLE); 194 dlg.popup(); 195 } 196 197 return errorMsg == null; 198 }; 199 200 ZmApptQuickAddDialog.prototype.isDirty = 201 function() { 202 return this._formValue() != this._origFormValue; 203 }; 204 205 ZmApptQuickAddDialog.prototype._setFocusToSubjectFeild = 206 function(){ 207 this._tabGroup.setFocusMember(this._subjectField); 208 }; 209 210 ZmApptQuickAddDialog.prototype.popup = 211 function(loc) { 212 ZmQuickAddDialog.prototype.popup.call(this, loc); 213 this._fbCache.clearCache(); 214 if (!this._tabGroupComplete) { 215 // tab group filled in here rather than in the constructor b/c we need 216 // all the content fields to have been created 217 this._tabGroup.addMember([ 218 this._subjectField, this._locationField, this._showAsSelect, 219 this._privacySelect, this._folderSelect, 220 this._startDateField, this._startDateButton, this._startTimeSelect.getTabGroupMember(), 221 this._endDateField, this._endDateButton, this._endTimeSelect.getTabGroupMember(), 222 this._repeatSelect, this._reminderSelect 223 ]); 224 this._tabGroupComplete = true; 225 } 226 //bug:68208 Focus must be in the Subject of QuickAdd Appointment dialog after double-click in calendar 227 this._focusAction = new AjxTimedAction(this, this._setFocusToSubjectFeild); 228 AjxTimedAction.scheduleAction(this._focusAction, 300); 229 230 if (this._hasReminderSupport) { 231 var defaultWarningTime = appCtxt.get(ZmSetting.CAL_REMINDER_WARNING_TIME); 232 this._reminderSelect.setSelectedValue(defaultWarningTime); 233 this._setEmailReminderControls(); 234 } 235 236 var defaultPrivacyOption = appCtxt.get(ZmSetting.CAL_APPT_VISIBILITY); 237 this._privacySelect.setSelectedValue((defaultPrivacyOption == ZmSetting.CAL_VISIBILITY_PRIV) ? "PRI" : "PUB"); 238 239 Dwt.setVisible(this._suggestions, false); 240 Dwt.setVisible(this._suggestLocation, false); 241 242 DBG.timePt("ZmQuickAddDialog#popup", true); 243 }; 244 245 ZmApptQuickAddDialog.prototype._autoCompCallback = 246 function(text, el, match) { 247 if (match.item) { 248 this._locationField.setValue(match.item.getFullName()); 249 } 250 }; 251 252 // Private / protected methods 253 254 ZmApptQuickAddDialog.prototype._createDwtObjects = 255 function() { 256 257 // create DwtInputField's 258 this._subjectField = new DwtInputField({parent:this, type:DwtInputField.STRING, 259 initialValue:null, size:null, maxLen:null, 260 errorIconStyle:DwtInputField.ERROR_ICON_NONE, 261 validationStyle:DwtInputField.CONTINUAL_VALIDATION, 262 hint: ZmMsg.subject, 263 parentElement:(this._htmlElId + "_subject")}); 264 this._subjectField.getInputElement().setAttribute('aria-labelledby', this._htmlElId + "_subject_label"); 265 this._subjectField.setRequired(true); 266 Dwt.setSize(this._subjectField.getInputElement(), "100%", "2rem"); 267 268 269 this._locationField = new DwtInputField({parent:this, type:DwtInputField.STRING, 270 initialValue:null, size:null, maxLen:null, 271 errorIconStyle:DwtInputField.ERROR_ICON_NONE, 272 validationStyle:DwtInputField.ONEXIT_VALIDATION, 273 label: ZmMsg.location, hint: ZmMsg.location, 274 parentElement:(this._htmlElId + "_location")}); 275 this._locationField.getInputElement().setAttribute('aria-labelledby', this._htmlElId + "_location_label"); 276 Dwt.setSize(this._locationField.getInputElement(), "100%", "2rem"); 277 278 // create DwtSelects 279 this._showAsSelect = new DwtSelect({parent:this, parentElement:(this._htmlElId + "_showAs")}); 280 this._showAsSelect.setAttribute('aria-labelledby', this._htmlElId + '_showAs_label'); 281 for (var i = 0; i < ZmApptViewHelper.SHOWAS_OPTIONS.length; i++) { 282 var option = ZmApptViewHelper.SHOWAS_OPTIONS[i]; 283 this._showAsSelect.addOption(option.label, option.selected, option.value, "ShowAs" + option.value); 284 } 285 286 this._privacySelect = new DwtSelect({parent:this, parentElement:(this._htmlElId + "_privacy")}); 287 this._privacySelect.setAttribute('aria-labelledby', this._htmlElId + "_privacy_label"); 288 for (var j = 0; j < ZmApptEditView.PRIVACY_OPTIONS.length; j++) { 289 var option = ZmApptEditView.PRIVACY_OPTIONS[j]; 290 this._privacySelect.addOption(option.label, option.selected, option.value); 291 } 292 this._privacySelect.addChangeListener(new AjxListener(this, this._privacyListener)); 293 294 this._folderSelect = new DwtSelect({parent:this, parentElement:(this._htmlElId + "_calendar"), label: ZmMsg.calendar}); 295 this._folderSelect.setAttribute('aria-labelledby', this._htmlElId + "_calendar_label"); 296 this._folderSelect.addChangeListener(new AjxListener(this, this._privacyListener)); 297 298 var dateButtonListener = new AjxListener(this, this._dateButtonListener); 299 var dateCalSelectionListener = new AjxListener(this, this._dateCalSelectionListener); 300 301 var startMiniCalId = this._htmlElId + "_startMiniCal"; 302 this._startDateButton = ZmCalendarApp.createMiniCalButton(this, startMiniCalId, dateButtonListener, dateCalSelectionListener); 303 var endMiniCalId = this._htmlElId + "_endMiniCal"; 304 this._endDateButton = ZmCalendarApp.createMiniCalButton(this, endMiniCalId, dateButtonListener, dateCalSelectionListener); 305 306 // create selects for Time section 307 var timeSelectListener = new AjxListener(this, this._timeChangeListener); 308 309 this._startTimeSelect = new DwtTimeInput(this, DwtTimeInput.START); 310 this._startTimeSelect.addChangeListener(timeSelectListener); 311 this._startTimeSelect.reparentHtmlElement(this._htmlElId + "_startTime"); 312 313 this._endTimeSelect = new DwtTimeInput(this, DwtTimeInput.END); 314 this._endTimeSelect.addChangeListener(timeSelectListener); 315 this._endTimeSelect.reparentHtmlElement(this._htmlElId + "_endTime"); 316 317 this._repeatSelect = new DwtSelect({parent:this, parentElement:(this._htmlElId + "_repeat"), label: ZmMsg.repeat}); 318 this._repeatSelect.addChangeListener(new AjxListener(this, this._repeatChangeListener)); 319 for (var i = 0; i < ZmApptViewHelper.REPEAT_OPTIONS.length-1; i++) { 320 var option = ZmApptViewHelper.REPEAT_OPTIONS[i]; 321 this._repeatSelect.addOption(option.label, option.selected, option.value); 322 } 323 324 //reminder DwtSelect 325 var displayOptions = [ 326 ZmMsg.apptRemindNever, 327 ZmMsg.apptRemindAtEventTime, 328 ZmMsg.apptRemindNMinutesBefore, 329 ZmMsg.apptRemindNMinutesBefore, 330 ZmMsg.apptRemindNMinutesBefore, 331 ZmMsg.apptRemindNMinutesBefore, 332 ZmMsg.apptRemindNMinutesBefore, 333 ZmMsg.apptRemindNMinutesBefore, 334 ZmMsg.apptRemindNMinutesBefore, 335 ZmMsg.apptRemindNHoursBefore, 336 ZmMsg.apptRemindNHoursBefore, 337 ZmMsg.apptRemindNHoursBefore, 338 ZmMsg.apptRemindNHoursBefore, 339 ZmMsg.apptRemindNHoursBefore, 340 ZmMsg.apptRemindNDaysBefore, 341 ZmMsg.apptRemindNDaysBefore, 342 ZmMsg.apptRemindNDaysBefore, 343 ZmMsg.apptRemindNDaysBefore, 344 ZmMsg.apptRemindNWeeksBefore, 345 ZmMsg.apptRemindNWeeksBefore 346 ]; 347 348 var options = [-1, 0, 1, 5, 10, 15, 30, 45, 60, 120, 180, 240, 300, 1080, 1440, 2880, 4320, 5760, 10080, 20160]; 349 var labels = [-1, 0, 1, 5, 10, 15, 30, 45, 60, 2, 3, 4, 5, 18, 1, 2, 3, 4, 1, 2]; 350 var defaultWarningTime = appCtxt.get(ZmSetting.CAL_REMINDER_WARNING_TIME); 351 352 this._hasReminderSupport = Dwt.byId(this._htmlElId + "_reminderSelect") != null; 353 354 if (this._hasReminderSupport) { 355 this._reminderSelect = new DwtSelect({parent:this, label: ZmMsg.reminder}); 356 this._reminderSelect.addChangeListener(new AjxListener(this, this._setEmailReminderControls)); 357 for (var j = 0; j < options.length; j++) { 358 var optLabel = ZmCalendarApp.__formatLabel(displayOptions[j], labels[j]); 359 this._reminderSelect.addOption(optLabel, (defaultWarningTime == options[j]), options[j]); 360 } 361 this._reminderSelect.reparentHtmlElement(this._htmlElId + "_reminderSelect"); 362 363 this._reminderEmailCheckbox = new DwtCheckbox({parent: this}); 364 this._reminderEmailCheckbox.replaceElement(document.getElementById(this._htmlElId + "_reminderEmailCheckbox")); 365 this._reminderEmailCheckbox.setText(ZmMsg.email); 366 this._reminderDeviceEmailCheckbox = new DwtCheckbox({parent: this}); 367 this._reminderDeviceEmailCheckbox.replaceElement(document.getElementById(this._htmlElId + "_reminderDeviceEmailCheckbox")); 368 this._reminderDeviceEmailCheckbox.setText(ZmMsg.deviceEmail); 369 this._setEmailReminderControls(); 370 371 var settings = appCtxt.getSettings(); 372 var listener = new AjxListener(this, this._settingChangeListener); 373 settings.getSetting(ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS).addChangeListener(listener); 374 settings.getSetting(ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ADDRESS).addChangeListener(listener); 375 } 376 377 // init auto-complete widget if contacts app enabled 378 if (appCtxt.get(ZmSetting.CONTACTS_ENABLED)) { 379 this._initAutocomplete(); 380 } 381 382 this._suggestLocationId = this._htmlElId + "_suggest_location"; 383 this._suggestLocation = document.getElementById(this._suggestLocationId); 384 385 this._suggestions = document.getElementById(this._htmlElId + "_suggestions"); 386 Dwt.setVisible(this._suggestions, false); 387 388 var closeCallback = this._onSuggestionClose.bind(this); 389 var dialogContentEl = document.getElementById(this._htmlElId + "_content"); 390 this._containerSize = Dwt.getSize(dialogContentEl); 391 if (appCtxt.get(ZmSetting.GAL_ENABLED)) { 392 this._locationAssistant = new ZmLocationAssistantView(this, appCtxt.getCurrentController(), this, closeCallback); 393 this._locationAssistant.reparentHtmlElement(this._suggestions); 394 } 395 AjxTimedAction.scheduleAction(new AjxTimedAction(this, this.loadPreference), 300); 396 }; 397 398 ZmApptQuickAddDialog.prototype.loadPreference = 399 function() { 400 var prefDlg = appCtxt.getSuggestionPreferenceDialog(); 401 prefDlg.setCallback(new AjxCallback(this, this._prefChangeListener)); 402 prefDlg.getSearchPreference(appCtxt.getActiveAccount()); 403 }; 404 405 ZmApptQuickAddDialog.prototype._prefChangeListener = 406 function() { 407 // Preference Dialog is only displayed when the suggestions panel is visible - so update suggestions 408 if (this._locationAssistant) { 409 this._locationAssistant.clearResources(); 410 this._locationAssistant.suggestAction(); 411 } 412 }; 413 414 ZmApptQuickAddDialog.prototype._handleConfigureClick = function() { 415 // transfer settings to new appt compose tab 416 var button = this._button[ZmApptQuickAddDialog.MORE_DETAILS_BUTTON]; 417 if (button) { 418 button._emulateSingleClick(); // HACK: should be public method on DwtButton 419 } 420 421 // or just get rid of this modal dialog 422 else { 423 this.popdown(); 424 } 425 426 // go to reminders prefs page 427 // NOTE: We can't query the section name based on the pref id 428 // NOTE: because that info won't be available until the first time 429 // NOTE: prefs app is launched. 430 skin.gotoPrefs("NOTIFICATIONS"); 431 }; 432 433 ZmApptQuickAddDialog.prototype._initAutocomplete = 434 function() { 435 var acCallback = new AjxCallback(this, this._autocompleteCallback); 436 this._acList = null; 437 438 if (appCtxt.get(ZmSetting.GAL_ENABLED) || appCtxt.get(ZmSetting.GAL_ENABLED)) { 439 // autocomplete for locations 440 var app = appCtxt.getApp(ZmApp.CALENDAR); 441 var params = { 442 dataClass: appCtxt.getAutocompleter(), 443 matchValue: ZmAutocomplete.AC_VALUE_NAME, 444 compCallback: acCallback, 445 keyUpCallback: this._handleLocationChange.bind(this), 446 options: {type:ZmAutocomplete.AC_TYPE_LOCATION}, 447 contextId: [this.toString(), ZmCalBaseItem.LOCATION].join("-") 448 }; 449 this._acLocationsList = new ZmAutocompleteListView(params); 450 this._acLocationsList.handle(this._locationField.getInputElement()); 451 this._acList = this._acLocationsList; 452 } 453 }; 454 455 ZmApptQuickAddDialog.prototype._autocompleteCallback = 456 function(text, el, match) { 457 if (!match) { 458 DBG.println(AjxDebug.DBG1, "ZmApptQuickAddDialog: match empty in autocomplete callback; text: " + text); 459 return; 460 } 461 var attendee = match.item; 462 if (attendee) { 463 var type = el._attType; 464 this._isKnownLocation = true; 465 attendee = (attendee instanceof AjxVector) ? attendee.getArray() : 466 (attendee instanceof Array) ? attendee : [attendee]; 467 for (var i = 0; i < attendee.length; i++) { 468 this._locations.push(attendee[i]); 469 } 470 } 471 }; 472 473 //monitor location field change and reset location resources array 474 ZmApptQuickAddDialog.prototype._handleLocationChange = 475 function(event, aclv, result) { 476 var val = this._locationField.getValue(); 477 if (val.length <= 1) { 478 // This is only called onKeyUp, so a length 1 string means typing just started 479 this._locations = []; 480 this._isKnownLocation = false; 481 } 482 }; 483 484 ZmApptQuickAddDialog.prototype._privacyListener = 485 function() { 486 if (!this._privacySelect) { return; } 487 488 var value = this._privacySelect.getValue(); 489 var calId = this._folderSelect.getValue(); 490 var cal = calId && appCtxt.getById(calId); 491 492 if (appCtxt.isOffline) { 493 var currAcct = cal.getAccount(); 494 appCtxt.accountList.setActiveAccount(currAcct); 495 } 496 497 if (cal) { 498 var isRemote = cal.isRemote(); 499 if (value == "PRI" && isRemote && !cal.hasPrivateAccess()) { 500 this._privacySelect.setSelectedValue("PUB"); 501 this._privacySelect.disable(); 502 } else { 503 this._privacySelect.enable(); 504 } 505 } 506 }; 507 508 ZmApptQuickAddDialog.prototype._cacheFields = 509 function() { 510 this._folderRow = document.getElementById(this._htmlElId + "_folderRow"); 511 this._startDateField = document.getElementById(this._htmlElId + "_startDate"); 512 this._endDateField = document.getElementById(this._htmlElId + "_endDate"); 513 this._repeatDescField = document.getElementById(this._htmlElId + "_repeatDesc"); 514 }; 515 516 ZmApptQuickAddDialog.prototype._addEventHandlers = 517 function() { 518 var qadId = AjxCore.assignId(this); 519 520 Dwt.setHandler(this._startDateField, DwtEvent.ONCHANGE, ZmApptQuickAddDialog._onChange); 521 Dwt.setHandler(this._endDateField, DwtEvent.ONCHANGE, ZmApptQuickAddDialog._onChange); 522 Dwt.setHandler(this._suggestLocation, DwtEvent.ONCLICK, this._showLocationSuggestions.bind(this)); 523 524 var dateSelectListener = this._dateChangeListener.bind(this); 525 Dwt.setHandler(this._startDateField, DwtEvent.ONCHANGE, dateSelectListener); 526 Dwt.setHandler(this._endDateField, DwtEvent.ONCHANGE, dateSelectListener); 527 528 this._startDateField._qadId = this._endDateField._qadId = qadId; 529 }; 530 531 ZmApptQuickAddDialog.prototype._showTimeFields = 532 function(show) { 533 Dwt.setVisibility(this._startTimeSelect.getHtmlElement(), show); 534 Dwt.setVisibility(this._endTimeSelect.getHtmlElement(), show); 535 if (this._supportTimeZones) 536 Dwt.setVisibility(this._endTZoneSelect.getHtmlElement(), show); 537 // also show/hide the "@" text 538 Dwt.setVisibility(document.getElementById(this._htmlElId + "_startTimeAt"), show); 539 Dwt.setVisibility(document.getElementById(this._htmlElId + "_endTimeAt"), show); 540 }; 541 542 543 544 ZmApptQuickAddDialog.prototype._onSuggestionClose = 545 function() { 546 // Make the trigger link visible 547 Dwt.setVisible(this._suggestLocation, true); 548 } 549 550 ZmApptQuickAddDialog.prototype._showLocationSuggestions = 551 function() { 552 // Hide the trigger link and display the location suggestion panel 553 Dwt.setVisible(this._suggestLocation, false); 554 Dwt.setVisible(this._suggestions, true); 555 this._locationAssistant.show(this._containerSize); 556 this._locationAssistant.suggestAction(); 557 }; 558 559 ZmApptQuickAddDialog.prototype._formValue = 560 function() { 561 var vals = []; 562 563 vals.push(this._subjectField.getValue()); 564 vals.push(this._locationField.getValue()); 565 vals.push(this._startDateField.value); 566 vals.push(this._endDateField.value); 567 if (this._hasReminderSupport) { 568 vals.push(this._reminderSelect.getValue()); 569 vals.push(this._reminderEmailCheckbox.isSelected()); 570 vals.push(this._reminderDeviceEmailCheckbox.isSelected()); 571 } 572 if (!this._appt.isAllDayEvent()) { 573 vals.push( 574 AjxDateUtil.getServerDateTime(this._startTimeSelect.getValue()), 575 AjxDateUtil.getServerDateTime(this._endTimeSelect.getValue()) 576 ); 577 } 578 vals.push(this._repeatSelect.getValue()); 579 580 var str = vals.join("|"); 581 str = str.replace(/\|+/, "|"); 582 return str; 583 }; 584 585 // Listeners 586 587 ZmApptQuickAddDialog.prototype._dateButtonListener = 588 function(ev) { 589 var calDate = ev.item == this._startDateButton 590 ? AjxDateUtil.simpleParseDateStr(this._startDateField.value) 591 : AjxDateUtil.simpleParseDateStr(this._endDateField.value); 592 593 // if date was input by user and its foobar, reset to today's date 594 if (isNaN(calDate)) { 595 calDate = new Date(); 596 var field = ev.item == this._startDateButton 597 ? this._startDateField : this._endDateField; 598 field.value = AjxDateUtil.simpleComputeDateStr(calDate); 599 } 600 601 // always reset the date to current field's date 602 var menu = ev.item.getMenu(); 603 var cal = menu.getItem(0); 604 cal.setDate(calDate, true); 605 ev.item.popup(); 606 }; 607 608 ZmApptQuickAddDialog.prototype._dateCalSelectionListener = 609 function(ev) { 610 var parentButton = ev.item.parent.parent; 611 612 // do some error correction... maybe we can optimize this? 613 var sd = AjxDateUtil.simpleParseDateStr(this._startDateField.value); 614 var ed = AjxDateUtil.simpleParseDateStr(this._endDateField.value); 615 var newDate = AjxDateUtil.simpleComputeDateStr(ev.detail); 616 617 // change the start/end date if they mismatch 618 if (parentButton == this._startDateButton) { 619 if (ed.valueOf() < ev.detail.valueOf()) 620 this._endDateField.value = newDate; 621 this._startDateField.value = newDate; 622 } else { 623 if (sd.valueOf() > ev.detail.valueOf()) 624 this._startDateField.value = newDate; 625 this._endDateField.value = newDate; 626 } 627 this._dateChangeListener(); 628 }; 629 630 ZmApptQuickAddDialog.prototype._repeatChangeListener = 631 function(ev) { 632 this._repeatDescField.innerHTML = ev._args.newValue != "NON" ? AjxStringUtil.htmlEncode(ZmMsg.recurEndNone) : ""; 633 if (this._repeatSelect._selectedValue === "WEE") { 634 this._appt._recurrence.repeatCustom = 1; 635 } 636 }; 637 638 ZmApptQuickAddDialog.prototype._timeChangeListener = 639 function(ev, id) { 640 DwtTimeInput.adjustStartEnd(ev, this._startTimeSelect, this._endTimeSelect, this._startDateField, this._endDateField, this._dateInfo, id); 641 if (!this._appt.isAllDayEvent()) { 642 ZmApptViewHelper.getDateInfo(this, this._dateInfo); 643 } 644 this._locationAssistant && this._locationAssistant.updateTime(); 645 }; 646 647 ZmApptQuickAddDialog.prototype._dateChangeListener = 648 function(ev, id) { 649 if (!this._appt.isAllDayEvent()) { 650 ZmApptViewHelper.getDateInfo(this, this._dateInfo); 651 } 652 this._locationAssistant && this._locationAssistant.updateTime(); 653 }; 654 655 ZmApptQuickAddDialog.prototype.getDurationInfo = 656 function() { 657 var startDate = AjxDateUtil.simpleParseDateStr(this._dateInfo.startDate); 658 var endDate = AjxDateUtil.simpleParseDateStr(this._dateInfo.endDate); 659 startDate = this._startTimeSelect.getValue(startDate); 660 endDate = this._endTimeSelect.getValue(endDate); 661 662 var durationInfo = {}; 663 durationInfo.startTime = startDate.getTime(); 664 durationInfo.endTime = endDate.getTime(); 665 durationInfo.duration = durationInfo.endTime - durationInfo.startTime; 666 return durationInfo; 667 }; 668 669 ZmApptQuickAddDialog.prototype._setEmailReminderControls = 670 function() { 671 var enabled = this._reminderSelect.getValue() != 0; 672 673 var email = appCtxt.get(ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS); 674 var emailEnabled = Boolean(email); 675 this._reminderEmailCheckbox.setEnabled(enabled && emailEnabled); 676 this._reminderEmailCheckbox.setToolTipContent(emailEnabled ? email : null); 677 678 var deviceEmail = appCtxt.get(ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ADDRESS); 679 var deviceEmailEnabled = Boolean(deviceEmail); 680 this._reminderDeviceEmailCheckbox.setEnabled(enabled && deviceEmailEnabled); 681 this._reminderDeviceEmailCheckbox.setToolTipContent(deviceEmailEnabled ? deviceEmail : null); 682 683 var configureEnabled = !emailEnabled && !deviceEmailEnabled; 684 this._reminderEmailCheckbox.setVisible(!configureEnabled); 685 this._reminderDeviceEmailCheckbox.setVisible((!configureEnabled && appCtxt.get(ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ENABLED))); 686 }; 687 688 ZmApptQuickAddDialog.prototype._settingChangeListener = 689 function(ev) { 690 if (ev.type != ZmEvent.S_SETTING) { return; } 691 var id = ev.source.id; 692 if (id == ZmSetting.CAL_EMAIL_REMINDERS_ADDRESS || id == ZmSetting.CAL_DEVICE_EMAIL_REMINDERS_ADDRESS) { 693 this._setEmailReminderControls(); 694 } 695 }; 696 697 // Static methods 698 ZmApptQuickAddDialog._onChange = 699 function(ev) { 700 var el = DwtUiEvent.getTarget(ev); 701 var qad = AjxCore.objectWithId(el._qadId); 702 ZmApptViewHelper.handleDateChange(qad._startDateField, qad._endDateField, el == qad._startDateField); 703 }; 704 705 ZmApptQuickAddDialog.prototype.updateLocation = 706 function(location, locationStr) { 707 this._locationField.setValue(locationStr); 708 if (this._useAcAddrBubbles) { 709 this._locationField.clear(); 710 this._locationField.addBubble({address:locationStr, match:match, skipNotify:true}); 711 } 712 this._locations.push(location); 713 }; 714 715 // Stub for the location picker and ZmScheduleAssistant 716 ZmApptQuickAddDialog.prototype.getCalendarAccount = 717 function() { 718 var cal = appCtxt.getById(this._folderSelect.getValue()); 719 return cal && cal.getAccount(); 720 }; 721 722 ZmApptQuickAddDialog.prototype.getFreeBusyExcludeInfo = 723 function(emailAddr){ 724 return null; 725 }; 726