1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 cr.define('settime', function() { 6 /** 7 * TimeSetter handles a dialog to check and set system time. It can also 8 * include a timezone dropdown if timezoneId is provided. 9 * 10 * TimeSetter uses the system time to populate the controls initially and 11 * update them as the system time or timezone changes, and notifies Chrome 12 * when the user changes the time or timezone. 13 * @constructor 14 */ 15 function TimeSetter() {} 16 17 cr.addSingletonGetter(TimeSetter); 18 19 /** @const */ var BODY_PADDING_PX = 20; 20 /** @const */ var LABEL_PADDING_PX = 5; 21 22 TimeSetter.prototype = { 23 /** 24 * Performs initial setup. 25 */ 26 initialize: function() { 27 // Store values for reverting inputs when the user's date/time is invalid. 28 this.prevValues_ = {}; 29 30 // The build time doesn't include a timezone, so subtract 1 day to get a 31 // safe minimum date. 32 this.minDate_ = new Date(loadTimeData.getValue('buildTime')); 33 this.minDate_.setDate(this.minDate_.getDate() - 1); 34 35 // Set the max date to the min date plus 20 years. 36 this.maxDate_ = new Date(this.minDate_); 37 this.maxDate_.setYear(this.minDate_.getFullYear() + 20); 38 39 // Make sure the ostensible date is within this range. 40 var now = new Date(); 41 if (now > this.maxDate_) 42 this.maxDate_ = now; 43 else if (now < this.minDate_) 44 this.minDate_ = now; 45 46 $('date').setAttribute('min', this.toHtmlValues_(this.minDate_).date); 47 $('date').setAttribute('max', this.toHtmlValues_(this.maxDate_).date); 48 49 this.updateTime_(); 50 51 // Show the timezone select if we have a timezone ID. 52 var currentTimezoneId = loadTimeData.getValue('currentTimezoneId'); 53 if (currentTimezoneId) { 54 this.setTimezone_(currentTimezoneId); 55 $('timezone-select').addEventListener( 56 'change', this.onTimezoneChange_.bind(this), false); 57 $('timezone').hidden = false; 58 } 59 60 this.sizeToFit_(); 61 62 $('time').addEventListener('blur', this.onTimeBlur_.bind(this), false); 63 $('date').addEventListener('blur', this.onTimeBlur_.bind(this), false); 64 65 $('set-time').addEventListener( 66 'submit', this.onSubmit_.bind(this), false); 67 }, 68 69 /** 70 * Sets the current timezone. 71 * @param {string} timezoneId The timezone ID to select. 72 * @private 73 */ 74 setTimezone_: function(timezoneId) { 75 $('timezone-select').value = timezoneId; 76 this.updateTime_(); 77 }, 78 79 /** 80 * Updates the date/time controls to the current local time. 81 * Called initially, then called again once a minute. 82 * @private 83 */ 84 updateTime_: function() { 85 var now = new Date(); 86 87 // Only update time controls if neither is focused. 88 if (document.activeElement.id != 'date' && 89 document.activeElement.id != 'time') { 90 var htmlValues = this.toHtmlValues_(now); 91 this.prevValues_.date = $('date').value = htmlValues.date; 92 this.prevValues_.time = $('time').value = htmlValues.time; 93 } 94 95 window.clearTimeout(this.timeTimeout_); 96 97 // Start timer to update these inputs every minute. 98 var secondsRemaining = 60 - now.getSeconds(); 99 this.timeTimeout_ = window.setTimeout(this.updateTime_.bind(this), 100 secondsRemaining * 1000); 101 }, 102 103 /** 104 * Sets the system time from the UI. 105 * @private 106 */ 107 applyTime_: function() { 108 var date = $('date').valueAsDate; 109 date.setMilliseconds(date.getMilliseconds() + $('time').valueAsNumber); 110 111 // Add timezone offset to get real time. 112 date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); 113 114 var seconds = Math.floor(date / 1000); 115 chrome.send('setTimeInSeconds', [seconds]); 116 }, 117 118 /** 119 * Called when focus is lost on date/time controls. 120 * @param {Event} e The blur event. 121 * @private 122 */ 123 onTimeBlur_: function(e) { 124 if (e.target.validity.valid && e.target.value) { 125 // Make this the new fallback time in case of future invalid input. 126 this.prevValues_[e.target.id] = e.target.value; 127 this.applyTime_(); 128 } else { 129 // Restore previous value. 130 e.target.value = this.prevValues_[e.target.id]; 131 } 132 }, 133 134 /** 135 * @param {Event} e The change event. 136 * @private 137 */ 138 onTimezoneChange_: function(e) { 139 chrome.send('setTimezone', [e.currentTarget.value]); 140 }, 141 142 /** 143 * Closes the dialog window. 144 * @param {Event} e The submit event. 145 * @private 146 */ 147 onSubmit_: function(e) { 148 e.preventDefault(); 149 chrome.send('dialogClose'); 150 }, 151 152 /** 153 * Resizes the window if necessary to show the entire contents. 154 * @private 155 */ 156 sizeToFit_: function() { 157 // Because of l10n, we should check that the vertical content can fit 158 // within the window. 159 if (window.innerHeight < document.body.scrollHeight) { 160 // Resize window to fit scrollHeight and the title bar. 161 var newHeight = document.body.scrollHeight + 162 window.outerHeight - window.innerHeight; 163 window.resizeTo(window.outerWidth, newHeight); 164 } 165 }, 166 167 /** 168 * Builds date and time strings suitable for the values of HTML date and 169 * time elements. 170 * @param {Date} date The date object to represent. 171 * @return {{date: string, time: string}} Date is an RFC 3339 formatted date 172 * and time is an HH:MM formatted time. 173 * @private 174 */ 175 toHtmlValues_: function(date) { 176 // Get the current time and subtract the timezone offset, so the 177 // JSON string is in local time. 178 var localDate = new Date(date); 179 localDate.setMinutes(date.getMinutes() - date.getTimezoneOffset()); 180 return {date: localDate.toISOString().slice(0, 10), 181 time: localDate.toISOString().slice(11, 16)}; 182 }, 183 }; 184 185 TimeSetter.setTimezone = function(timezoneId) { 186 TimeSetter.getInstance().setTimezone_(timezoneId); 187 }; 188 189 TimeSetter.updateTime = function() { 190 TimeSetter.getInstance().updateTime_(); 191 }; 192 193 return { 194 TimeSetter: TimeSetter 195 }; 196 }); 197 198 document.addEventListener('DOMContentLoaded', function() { 199 settime.TimeSetter.getInstance().initialize(); 200 }); 201