1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2009, 2010, 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) 2009, 2010, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @overview
 26  */
 27 
 28 /**
 29  * Creates a timezone dialog.
 30  * @class
 31  * This class represents a timezone dialog.
 32  * 
 33  * @param	{DwtComposite}	parent		the parent
 34  * @param	{String}	className		the class name
 35  *  
 36  * @extends		DwtDialog
 37  */
 38 ZmTimezonePicker = function(parent, className) {
 39 
 40     var buttons = [ ZmTimezonePicker.SAVE_BUTTON ];
 41     var saveButton = new DwtDialog_ButtonDescriptor(ZmTimezonePicker.SAVE_BUTTON, ZmMsg.save, DwtDialog.ALIGN_RIGHT);
 42 	DwtDialog.call(this, {parent:parent, className:className,
 43         title:ZmMsg.selectTimezoneTitle, standardButtons:DwtDialog.NO_BUTTONS,
 44         extraButtons: [saveButton]});
 45 
 46     this.setButtonListener(ZmTimezonePicker.SAVE_BUTTON, new AjxListener(this, this._handleSaveButton));
 47     this.setContent(this._contentHtml());
 48 	this._setTimezoneMenu();
 49 };
 50 
 51 ZmTimezonePicker.prototype = new DwtDialog;
 52 ZmTimezonePicker.prototype.constructor = ZmTimezonePicker;
 53 
 54 ZmTimezonePicker.SAVE_BUTTON = ++DwtDialog.LAST_BUTTON;
 55 
 56 ZmTimezonePicker.prototype.toString = 
 57 function() {
 58 	return "ZmTimezonePicker";
 59 };
 60 
 61 ZmTimezonePicker.prototype.popup =
 62 function() {
 63 	this._initTzSelect();
 64     this.autoSelectTimezone();
 65 	DwtDialog.prototype.popup.call(this);
 66 };
 67 
 68 ZmTimezonePicker.prototype.cleanup =
 69 function(bPoppedUp) {
 70 	DwtDialog.prototype.cleanup.call(this, bPoppedUp);
 71 };
 72 
 73 ZmTimezonePicker.prototype._setTimezoneMenu =
 74 function() {
 75 	var timezoneListener = new AjxListener(this, this._timezoneListener);
 76 	this._tzoneSelect = new DwtSelect({parent:this, parentElement: (this._htmlElId + "_tzSelect"), layout: DwtMenu.LAYOUT_SCROLL, maxRows:7});
 77 	this._tzoneSelect.addChangeListener(timezoneListener);
 78 
 79 	this._tzoneShowAll = new DwtCheckbox({parent:this, parentElement:(this._htmlElId+"_tzShowAll")});
 80 	this._tzoneShowAll.setText(ZmMsg.selectTimezoneIShowAll);
 81 	this._tzoneShowAll.addSelectionListener(new AjxListener(this, this._handleShowAllChange));
 82 };
 83 
 84 ZmTimezonePicker.prototype._initTzSelect =
 85 function(force) {
 86     var showAll = this._tzoneShowAll.isSelected();
 87 	var options = showAll ? AjxTimezone.getAbbreviatedZoneChoices() : AjxTimezone.getMatchingTimezoneChoices();
 88     var serverIdMap = {};
 89     var serverId;
 90 	if (force || options.length != this._tzCount) {
 91 		this._tzCount = options.length;
 92 		this._tzoneSelect.clearOptions();
 93 		for (var i = 0; i < options.length; i++) {
 94             if(options[i].autoDetected) continue;
 95 
 96             serverId = options[i].value;
 97             //avoid duplicate entries
 98             if(!showAll && serverIdMap[serverId]) continue;
 99             serverIdMap[serverId] = true;
100 
101             this._tzoneSelect.addOption(options[i]);
102 		}
103 	}
104 };
105 
106 ZmTimezonePicker.prototype.autoSelectTimezone =
107 function() {
108     if(AjxTimezone.DEFAULT_RULE.autoDetected) {
109 
110         var cRule = AjxTimezone.DEFAULT_RULE;
111         var standardOffsetMatch, daylightOffsetMatch, transMatch;
112 
113         for(var i in AjxTimezone.MATCHING_RULES) {
114             var rule = AjxTimezone.MATCHING_RULES[i];
115             if(rule.autoDetected) continue;
116             if(rule.standard.offset == cRule.standard.offset) {
117 
118                 if(!standardOffsetMatch) standardOffsetMatch = rule.serverId;
119 
120                 var isDayLightOffsetMatching = (cRule.daylight && rule.daylight && (rule.daylight.offset == cRule.daylight.offset));
121 
122                 if(isDayLightOffsetMatching) {
123 
124                     if(!daylightOffsetMatch) daylightOffsetMatch = rule.serverId;
125 
126                     var isTransYearMatching = (rule.daylight.trans[0] == cRule.daylight.trans[0]);
127                     var isTransMonthMatching = (rule.daylight.trans[1] == cRule.daylight.trans[1]);
128 
129                     if(isTransYearMatching && isTransMonthMatching && !transMatch) {
130                         transMatch = rule.serverId;
131                     }
132                 }
133             }
134         }
135         //select closest matching timezone
136         var serverId = transMatch ? transMatch : (daylightOffsetMatch || standardOffsetMatch);
137         if(serverId) this._tzoneSelect.setSelectedValue(serverId);
138     }else {
139         var tz = AjxTimezone.getServerId(AjxTimezone.DEFAULT);
140         this._tzoneSelect.setSelectedValue(tz);
141     }
142 };
143 
144 /**
145  * Updates the selected timezone.
146  * 
147  * @param	{Hash}	dateInfo		a hash of date information
148  * @param	{ZmTimezone}	timezone		the timezone
149  */
150 ZmTimezonePicker.prototype.updateTimezone =
151 function(dateInfo) {
152 	this._tzoneSelect.setSelectedValue(dateInfo.timezone);
153 };
154 
155 ZmTimezonePicker.prototype.setCallback =
156 function(callback) {
157 	this._callback = callback;
158 };
159 
160 ZmTimezonePicker.prototype._timezoneListener =
161 function(ev) {
162 	//todo: timezone change listener
163 };
164 
165 ZmTimezonePicker.prototype._handleShowAllChange = function(evt) {
166     var value = this._tzoneSelect.getValue();
167     this._initTzSelect(true);
168     this._tzoneSelect.setSelectedValue(value);
169 };
170 
171 ZmTimezonePicker.prototype._contentHtml = 
172 function() {
173 	return AjxTemplate.expand("share.Dialogs#ZmTimezonePicker", {id:this._htmlElId});
174 };
175 
176 ZmTimezonePicker.prototype._okButtonListener =
177 function(ev) {
178 	DwtDialog.prototype._buttonListener.call(this, ev, results);
179 };
180 
181 ZmTimezonePicker.prototype._enterListener =
182 function(ev) {
183 };
184 
185 ZmTimezonePicker.prototype._getTabGroupMembers =
186 function() {
187 	return [this._tzoneSelect];
188 };
189 
190 ZmTimezonePicker.prototype._handleSaveButton =
191 function(event) {
192     var timezone = this._tzoneSelect.getValue();
193     this.popdown();
194     if(this._callback) {
195         this._callback.run(timezone);
196     }
197 };
198 
199 ZmTimezonePicker.prototype.handleKeyAction =
200 function(actionCode, ev) {
201 	switch (actionCode) {
202 		case DwtKeyMap.CANCEL:
203 			this._runCallbackForButtonId(DwtDialog.CANCEL_BUTTON);
204 			break;
205 		default:
206 			DwtDialog.prototype.handleKeyAction.call(this, actionCode, ev);
207 			break;
208 	}
209 	return true;
210 };
211