Source: panels/date_time/panel.js

/**
 * Used to show Personalization/Date & Time panel
 */
define(function(require) {
  'use strict';

  var SettingsPanel = require('modules/settings_panel');
  var DateTime = require('modules/date_time');
  var tzSelect = require('shared/tz_select');

  return function ctor_date_time_panel() {
    var HOUR_12 = 'ampm';
    var HOUR_24 = '24';
    return SettingsPanel({
      onInit: function(panel) {
        this._elements = {
          timeAutoSwitch: panel.querySelector('.time-auto'),
          timezoneRegion: panel.querySelector('.timezone-region'),
          timezoneCity: panel.querySelector('.timezone-city'),
          datePicker: panel.querySelector('.date-picker'),
          timePicker: panel.querySelector('.time-picker'),
          clockDate: panel.querySelector('.clock-date'),
          clockTime: panel.querySelector('.clock-time'),
          timeManual: panel.querySelector('.time-manual'),
          timezone: panel.querySelector('.timezone'),
          timezonePickers: [].slice.apply(
            panel.querySelectorAll('.timezone-picker')),
          timezoneInfo: panel.querySelector('.timezone-info'),
          timezoneInfoText: panel.querySelector('.timezone-info-text'),
          timeFormat: panel.querySelector('.time-format-time')
        };

        // update date/clock periodically
        this._boundSetDate = () => {
          this._elements.clockDate.textContent = DateTime.date;
        };

        this._boundSetTime = () => {
          this._elements.clockTime.textContent = DateTime.time;
        };

        this._boundSetTimezoneInfo = () => {
          // Only display the timezone info when auto time is enabled.
          var info = DateTime.clockAutoEnabled ? DateTime.timezone : '';
          this._elements.timezoneInfoText.textContent = info;
        };

        // Reset the timezone to the previous user selected value
        this._boundSetSelectedTimeZone = (selected) => {
          DateTime.setUserSelectedTimezone(selected);
        };

        this._boundUpdateUI = this._updateUI.bind(this);
        this._boundDatePickerChange = this._datePickerChange.bind(this);
        this._boundTimePickerChange = this._timePickerChange.bind(this);

        this._boundTimeFormatChange = () => {
          var value = (this._elements.timeFormat.value === HOUR_12);
          DateTime.setCurrentHour12(value);
        };
      },
      onBeforeShow: function() {
        DateTime.observe('date', this._boundSetDate);
        DateTime.observe('time', this._boundSetTime);
        DateTime.observe('timezone', this._boundSetTimezoneInfo);
        DateTime.observe('clockAutoEnabled', this._boundUpdateUI);
        DateTime.observe('clockAutoAvailable', this._boundUpdateUI);
        DateTime.observe('timezoneAutoAvailable', this._boundUpdateUI);
        DateTime.observe('userSelectedTimezone',
          this._boundSetSelectedTimeZone);

        this._elements.datePicker.addEventListener('input',
          this._boundDatePickerChange);
        this._elements.timePicker.addEventListener('input',
          this._boundTimePickerChange);
        this._elements.timeFormat.addEventListener('change',
          this._boundTimeFormatChange);

        this._renderTimeZone();
        this._boundSetDate();
        this._boundSetTime();
        this._boundSetTimezoneInfo();
        if (DateTime.userSelectedTimezone && !DateTime.clockAutoEnabled) {
          this._boundSetSelectedTimeZone(DateTime.userSelectedTimezone);
        }
        this._renderTimeFormat();
        this._boundUpdateUI();

        window.addEventListener('localized', this);
      },

      onHide: function() {
        DateTime.unobserve('date', this._boundSetDate);
        DateTime.unobserve('time', this._boundSetTime);
        DateTime.unobserve('timezone', this._boundSetTimezoneInfo);
        DateTime.unobserve('clockAutoEnabled', this._boundUpdateUI);
        DateTime.unobserve('clockAutoAvailable', this._boundUpdateUI);
        DateTime.unobserve('timezoneAutoAvailable', this._boundUpdateUI);
        DateTime.unobserve('userSelectedTimezone',
          this._boundSetSelectedTimeZone);

        this._elements.datePicker.removeEventListener('input',
          this._boundDatePickerChange);
        this._elements.timePicker.removeEventListener('input',
          this._boundTimePickerChange);
        this._elements.timeFormat.removeEventListener('change',
          this._boundTimeFormatChange);

        window.removeEventListener('localized', this);
      },

      /**
       * monitor time.timezone changes, see /shared/js/tz_select.js
       */
      _renderTimeZone: function dt_renderTimeZone() {
        var noOp = function() {};
        tzSelect(this._elements.timezoneRegion, this._elements.timezoneCity,
          noOp, noOp);
      },

      /**
       * Update DatePicker value
       */
      _datePickerChange: function dt_datePickerChange() {
        DateTime.setTime('date', this._elements.datePicker.value);
        // Clean up the value of picker once we get date set by the user.
        // It will get new date according system time when pop out again.
        this._elements.datePicker.value = '';
      },

      /**
       * Update TimePicker value
       */
      _timePickerChange: function dt_timePickerChange() {
        DateTime.setTime('time', this._elements.timePicker.value);
        // Clean up the value of picker once we get time set by the user.
        // It will get new time according system time when pop out again.
        this._elements.timePicker.value = '';
      },

      handleEvent: function dt_handleEvent(evt) {
        switch (evt.type) {
          case 'localized':
            this._renderTimeZone();
            break;
        }
      },

      /**
       * Update Panel UI elements
       */
      _updateUI: function dt_updateUI() {
        this._elements.timeAutoSwitch.dataset.state =
            DateTime.clockAutoEnabled ? 'auto' : 'manual';
        // There are three possible combinations:
        // - clockAutoAvailable is true, timezoneAutoAvailable is true
        // - clockAutoAvailable is false, timezoneAutoAvailable is false
        // - clockAutoAvailable is true, timezoneAutoAvailable is false
        // We show the auto time switch only when clockAutoAvailable is true.
        this._elements.timeAutoSwitch.hidden = !DateTime.clockAutoAvailable;

        // DataTime.clockAutoEnabled is a user preference and in some cases it
        // can be true while DateTime.clockAutoAvailable is false. The reason is
        // the device may not connect to the network to retrieve the correct
        // time automatically after startup. That being said, we should always
        // check both `DateTime.clockAutoEnabled` and
        // `DateTime.clockAutoAvailable` to determine whether the device is in
        // the auto time mode.
        var autoTimeMode =
          DateTime.clockAutoEnabled && DateTime.clockAutoAvailable;

        this._elements.datePicker.disabled = autoTimeMode;
        this._elements.timePicker.disabled = autoTimeMode;
        this._elements.timezoneRegion.disabled =
          DateTime.timezoneAutoAvailable && autoTimeMode;
        this._elements.timezoneCity.disabled =
          DateTime.timezoneAutoAvailable && autoTimeMode;

        // XXX: Force to trigger the selector change so that tz_select is able
        //      to write the previous user-selected value back to time.timezone.
        if (!DateTime.clockAutoEnabled) {
          this._elements.timezoneRegion.dispatchEvent(new Event('change'));
          this._elements.timezoneCity.dispatchEvent(new Event('change'));
        }

        if (autoTimeMode) {
          this._elements.timeManual.classList.add('disabled');
          this._elements.timezonePickers.forEach((picker) => {
            picker.hidden = DateTime.timezoneAutoAvailable;
          });
          this._elements.timezoneInfo.hidden = !DateTime.timezoneAutoAvailable;
        } else {
          this._elements.timeManual.classList.remove('disabled');
          this._elements.timezonePickers.forEach((picker) => {
            picker.hidden = false;
          });
          this._elements.timezoneInfo.hidden = true;
        }
      },

      /**
       * Update TimeFormat selector
       */
      _renderTimeFormat: function dt_renderTimeFormat() {
        // restore default selection
        var selectedItem = 0;
        if (!DateTime.currentHour12) {
          selectedItem = 1;
        }

        var options = [{
          attr: 'hour-12', // 2:00PM
          value: HOUR_12,
        }, {
          attr: 'hour-24', // 14:00
          value: HOUR_24
        }];

        var obj = this._elements.timeFormat;
        while(obj.options.length) { // clean options
          obj.remove(0);
        }
        for (var i = 0; i < options.length; i++) {
          var option = document.createElement('option');
          option.setAttribute('data-l10n-id', options[i].attr);
          option.selected = (selectedItem === i);
          option.value = options[i].value;
          obj.appendChild(option);
        }
      }
    });
  };
});