1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2010, 2011, 2012, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 /** 24 * Creates a generic time picker dialog 25 * @constructor 26 * @class 27 * 28 * @extends ZmDialog 29 * 30 */ 31 ZmTimeDialog = function(params) { 32 params.id = Dwt.getNextId("ZmTimeDialog_"); 33 ZmDialog.call(this, params); 34 var html = AjxTemplate.expand("share.Dialogs#ZmTimeDialog", {id: this._htmlElId, description: ZmMsg.sendLaterDescription, label: ZmMsg.time}); 35 this.setContent(html); 36 this.setTitle(ZmMsg.sendLaterTitle); 37 this._createDwtObjects(); 38 }; 39 40 ZmTimeDialog.prototype = new ZmDialog; 41 ZmTimeDialog.prototype.constructor = ZmTimeDialog; 42 43 // Public 44 45 ZmTimeDialog.prototype.toString = 46 function() { 47 return "ZmTimeDialog"; 48 }; 49 50 ZmTimeDialog.prototype.initialize = 51 function() { 52 // Init Date / time picker 53 var now = new Date(); 54 this._dateField.value = AjxDateUtil.simpleComputeDateStr(now); 55 this.showTimeFields(true); 56 this._timeSelect.set(now); 57 58 // Init Timezone picker 59 var options = AjxTimezone.getAbbreviatedZoneChoices(); 60 var serverIdMap = {}; 61 var serverId; 62 if (options.length != this._tzCount) { 63 this._tzCount = options.length; 64 this._tzoneSelect.clearOptions(); 65 for (var i = 0; i < options.length; i++) { 66 if (!options[i].autoDetected) { 67 serverId = options[i].value; 68 serverIdMap[serverId] = true; 69 this._tzoneSelect.addOption(options[i]); 70 } 71 } 72 } 73 this.autoSelectTimezone(); 74 }; 75 76 77 78 ZmTimeDialog.prototype.isValid = 79 function() { 80 return true; 81 }; 82 83 ZmTimeDialog.prototype.isDirty = 84 function() { 85 return true; 86 }; 87 88 ZmTimeDialog.prototype.getValue = 89 function() { 90 var date = this._timeSelect.getValue(AjxDateUtil.simpleParseDateStr(this._dateField.value)); 91 var timezone = this._tzoneSelect.getValue(); 92 return {date: date, timezone: timezone}; 93 } 94 95 ZmTimeDialog.prototype.isValidDateStr = 96 function() { 97 return AjxDateUtil.isValidSimpleDateStr(this._dateField.value); 98 }; 99 100 ZmTimeDialog.prototype.popup = 101 function() { 102 this.initialize(); 103 ZmDialog.prototype.popup.call(this); 104 if (!this._tabGroupComplete) { 105 var members = [this._dateField, this._dateButton, this._timeSelect.getInputField(), this._tzoneSelect]; 106 for (var i = 0; i < members.length; i++) { 107 this._tabGroup.addMember(members[i], i); 108 } 109 this._tabGroupComplete = true; 110 } 111 this._tabGroup.setFocusMember(this._dateField); 112 }; 113 114 // Private / protected methods 115 116 ZmTimeDialog.prototype._createDwtObjects = 117 function() { 118 119 var dateButtonListener = new AjxListener(this, this._dateButtonListener); 120 var dateCalSelectionListener = new AjxListener(this, this._dateCalSelectionListener); 121 122 this._dateButton = this.createMiniCalButton(this._htmlElId + "_miniCal", dateButtonListener, dateCalSelectionListener); 123 124 // create selects for Time section 125 var timeSelectListener = new AjxListener(this, this._timeChangeListener); 126 127 this._timeSelect = new DwtTimeInput(this, DwtTimeInput.START); 128 this._timeSelect.addChangeListener(timeSelectListener); 129 this._timeSelect.reparentHtmlElement(this._htmlElId + "_time"); 130 131 this._dateField = Dwt.byId(this._htmlElId + "_date"); 132 133 this._tzoneSelect = new DwtSelect({parent:this, parentElement: (this._htmlElId + "_tzSelect"), layout:DwtMenu.LAYOUT_SCROLL, maxRows: 7, id: Dwt.getNextId("TimeZoneSelect_")}); 134 }; 135 136 ZmTimeDialog.prototype.showTimeFields = 137 function(show) { 138 Dwt.setVisibility(this._timeSelect.getHtmlElement(), show); 139 }; 140 141 // Listeners 142 143 ZmTimeDialog.prototype._dateButtonListener = 144 function(ev) { 145 var calDate = AjxDateUtil.simpleParseDateStr(this._dateField.value); 146 147 // if date was input by user and its foobar, reset to today's date 148 if (calDate === null || isNaN(calDate)) { 149 calDate = new Date(); 150 var field = this._dateField; 151 field.value = AjxDateUtil.simpleComputeDateStr(calDate); 152 } 153 154 // always reset the date to current field's date 155 var menu = ev.item.getMenu(); 156 var cal = menu.getItem(0); 157 cal.setDate(calDate, true); 158 ev.item.popup(); 159 }; 160 161 ZmTimeDialog.prototype._dateCalSelectionListener = 162 function(ev) { 163 var parentButton = ev.item.parent.parent; 164 165 // do some error correction... maybe we can optimize this? 166 var sd = AjxDateUtil.simpleParseDateStr(this._dateField.value); 167 var newDate = AjxDateUtil.simpleComputeDateStr(ev.detail); 168 169 // change the start/end date if they mismatch 170 if (parentButton == this._dateButton) { 171 this._dateField.value = newDate; 172 } 173 }; 174 175 ZmTimeDialog.prototype.createMiniCalButton = 176 function(buttonId, dateButtonListener, dateCalSelectionListener) { 177 // create button 178 var dateButton = new DwtButton({parent:this}); 179 dateButton.addDropDownSelectionListener(dateButtonListener); 180 dateButton.setData(Dwt.KEY_ID, buttonId); 181 if (AjxEnv.isIE) { 182 dateButton.setSize("20"); 183 } 184 185 // create menu for button 186 var calMenu = new DwtMenu({parent:dateButton, style:DwtMenu.CALENDAR_PICKER_STYLE}); 187 calMenu.setSize("150"); 188 calMenu._table.width = "100%"; 189 dateButton.setMenu(calMenu, true); 190 191 // create mini cal for menu for button 192 var cal = new DwtCalendar({parent:calMenu}); 193 cal.setData(Dwt.KEY_ID, buttonId); 194 cal.setSkipNotifyOnPage(true); 195 var fdow = appCtxt.get(ZmSetting.CAL_FIRST_DAY_OF_WEEK) || 0; 196 cal.setFirstDayOfWeek(fdow); 197 cal.addSelectionListener(dateCalSelectionListener); 198 // add settings change listener on mini cal in case first day of week setting changes 199 // safety check since this is static code (may not have loaded calendar) 200 var fdowSetting = appCtxt.getSettings().getSetting(ZmSetting.CAL_FIRST_DAY_OF_WEEK); 201 if (fdowSetting) { 202 var listener = new AjxListener(null, ZmCalendarApp._settingChangeListener, cal); 203 fdowSetting.addChangeListener(listener); 204 } 205 206 // reparent and cleanup 207 dateButton.reparentHtmlElement(buttonId); 208 delete buttonId; 209 210 return dateButton; 211 }; 212 213 ZmTimeDialog.prototype.autoSelectTimezone = 214 function() { 215 if (AjxTimezone.DEFAULT_RULE.autoDetected) { 216 217 var cRule = AjxTimezone.DEFAULT_RULE; 218 var standardOffsetMatch, daylightOffsetMatch, transMatch; 219 220 for (var i in AjxTimezone.MATCHING_RULES) { 221 var rule = AjxTimezone.MATCHING_RULES[i]; 222 if (rule.autoDetected) continue; 223 if (rule.standard.offset == cRule.standard.offset) { 224 225 if (!standardOffsetMatch) 226 standardOffsetMatch = rule.serverId; 227 228 var isDayLightOffsetMatching = (cRule.daylight && rule.daylight && (rule.daylight.offset == cRule.daylight.offset)); 229 230 if(isDayLightOffsetMatching) { 231 if (!daylightOffsetMatch) 232 daylightOffsetMatch = rule.serverId; 233 var isTransYearMatching = (rule.daylight.trans[0] == cRule.daylight.trans[0]); 234 var isTransMonthMatching = (rule.daylight.trans[1] == cRule.daylight.trans[1]); 235 if (isTransYearMatching && isTransMonthMatching && !transMatch) 236 transMatch = rule.serverId; 237 } 238 } 239 } 240 //select closest matching timezone 241 var serverId = transMatch ? transMatch : (daylightOffsetMatch || standardOffsetMatch); 242 if (serverId) this._tzoneSelect.setSelectedValue(serverId); 243 } else { 244 var tz = AjxTimezone.getServerId(AjxTimezone.DEFAULT); 245 this._tzoneSelect.setSelectedValue(tz); 246 } 247 }; 248