15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be 35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liucr.define('settime', function() { 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * TimeSetter handles a dialog to check and set system time. It can also 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * include a timezone dropdown if timezoneId is provided. 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * TimeSetter uses the system time to populate the controls initially and 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * update them as the system time or timezone changes, and notifies Chrome 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * when the user changes the time or timezone. 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @constructor 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function TimeSetter() {} 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu cr.addSingletonGetter(TimeSetter); 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @const */ var BODY_PADDING_PX = 20; 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @const */ var LABEL_PADDING_PX = 5; 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu TimeSetter.prototype = { 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Performs initial setup. 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu initialize: function() { 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Store values for reverting inputs when the user's date/time is invalid. 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.prevValues_ = {}; 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // The build time doesn't include a timezone, so subtract 1 day to get a 315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // safe minimum date. 325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.minDate_ = new Date(loadTimeData.getValue('buildTime')); 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.minDate_.setDate(this.minDate_.getDate() - 1); 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Set the max date to the min date plus 20 years. 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.maxDate_ = new Date(this.minDate_); 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.maxDate_.setYear(this.minDate_.getFullYear() + 20); 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Make sure the ostensible date is within this range. 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var now = new Date(); 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (now > this.maxDate_) 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.maxDate_ = now; 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu else if (now < this.minDate_) 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.minDate_ = now; 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('date').setAttribute('min', this.toHtmlValues_(this.minDate_).date); 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('date').setAttribute('max', this.toHtmlValues_(this.maxDate_).date); 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.updateTime_(); 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Show the timezone select if we have a timezone ID. 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var currentTimezoneId = loadTimeData.getValue('currentTimezoneId'); 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (currentTimezoneId) { 545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.setTimezone_(currentTimezoneId); 555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('timezone-select').addEventListener( 565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'change', this.onTimezoneChange_.bind(this), false); 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('timezone').hidden = false; 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.sizeToFit_(); 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('time').addEventListener('blur', this.onTimeBlur_.bind(this), false); 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('date').addEventListener('blur', this.onTimeBlur_.bind(this), false); 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('set-time').addEventListener( 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'submit', this.onSubmit_.bind(this), false); 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Sets the current timezone. 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} timezoneId The timezone ID to select. 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu setTimezone_: function(timezoneId) { 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu $('timezone-select').value = timezoneId; 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.updateTime_(); 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Updates the date/time controls to the current local time. 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called initially, then called again once a minute. 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu updateTime_: function() { 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var now = new Date(); 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Only update time controls if neither is focused. 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (document.activeElement.id != 'date' && 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu document.activeElement.id != 'time') { 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var htmlValues = this.toHtmlValues_(now); 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.prevValues_.date = $('date').value = htmlValues.date; 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.prevValues_.time = $('time').value = htmlValues.time; 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.clearTimeout(this.timeTimeout_); 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Start timer to update these inputs every minute. 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var secondsRemaining = 60 - now.getSeconds(); 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timeTimeout_ = window.setTimeout(this.updateTime_.bind(this), 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu secondsRemaining * 1000); 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Sets the system time from the UI. 1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu applyTime_: function() { 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var date = $('date').valueAsDate; 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu date.setMilliseconds(date.getMilliseconds() + $('time').valueAsNumber); 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Add timezone offset to get real time. 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var seconds = Math.floor(date / 1000); 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu chrome.send('setTimeInSeconds', [seconds]); 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when focus is lost on date/time controls. 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Event} e The blur event. 1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu onTimeBlur_: function(e) { 1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (e.target.validity.valid && e.target.value) { 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Make this the new fallback time in case of future invalid input. 1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.prevValues_[e.target.id] = e.target.value; 1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.applyTime_(); 1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Restore previous value. 1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu e.target.value = this.prevValues_[e.target.id]; 1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Event} e The change event. 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu onTimezoneChange_: function(e) { 1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu chrome.send('setTimezone', [e.currentTarget.value]); 1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Closes the dialog window. 1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Event} e The submit event. 1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu onSubmit_: function(e) { 1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu e.preventDefault(); 1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu chrome.send('dialogClose'); 1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Resizes the window if necessary to show the entire contents. 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sizeToFit_: function() { 1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Because of l10n, we should check that the vertical content can fit 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // within the window. 1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (window.innerHeight < document.body.scrollHeight) { 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Resize window to fit scrollHeight and the title bar. 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var newHeight = document.body.scrollHeight + 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.outerHeight - window.innerHeight; 1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu window.resizeTo(window.outerWidth, newHeight); 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Builds date and time strings suitable for the values of HTML date and 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * time elements. 1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Date} date The date object to represent. 1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {{date: string, time: string}} Date is an RFC 3339 formatted date 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * and time is an HH:MM formatted time. 1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu toHtmlValues_: function(date) { 1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Get the current time and subtract the timezone offset, so the 1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // JSON string is in local time. 1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var localDate = new Date(date); 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu localDate.setMinutes(date.getMinutes() - date.getTimezoneOffset()); 1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return {date: localDate.toISOString().slice(0, 10), 1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu time: localDate.toISOString().slice(11, 16)}; 1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }, 1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }; 1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu TimeSetter.setTimezone = function(timezoneId) { 1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu TimeSetter.getInstance().setTimezone_(timezoneId); 1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }; 1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu TimeSetter.updateTime = function() { 1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu TimeSetter.getInstance().updateTime_(); 1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }; 1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return { 1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu TimeSetter: TimeSetter 1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }; 1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}); 1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liudocument.addEventListener('DOMContentLoaded', function() { 1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu settime.TimeSetter.getInstance().initialize(); 2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}); 201