Bug 1361676 - Show selection highlight on date picker. r=mconley draft
authorScott Wu <scottcwwu@gmail.com>
Wed, 03 May 2017 18:05:36 +0800
changeset 575256 bd1931613725a17144cbd1fa7acb965ddd82f29e
parent 575133 120d8562d4a53e4f78bd86c6f5076f6db265e5a3
child 575316 7075f44201ba4077f3ec4c02cd93ce866abe1a02
push id58014
push userbmo:scwwu@mozilla.com
push dateWed, 10 May 2017 07:06:07 +0000
reviewersmconley
bugs1361676
milestone55.0a1
Bug 1361676 - Show selection highlight on date picker. r=mconley MozReview-Commit-ID: GBE5zwWxQiu
toolkit/content/widgets/calendar.js
toolkit/content/widgets/datekeeper.js
toolkit/content/widgets/datepicker.js
toolkit/themes/shared/datetimeinputpickers.css
--- a/toolkit/content/widgets/calendar.js
+++ b/toolkit/content/widgets/calendar.js
@@ -146,19 +146,17 @@ Calendar.prototype = {
    */
   handleEvent(event) {
     switch (event.type) {
       case "click": {
         if (event.target.parentNode == this.context.daysView) {
           let targetId = event.target.dataset.id;
           let targetObj = this.props.days[targetId];
           if (targetObj.enabled) {
-            this.props.setSelection({
-              selection: targetObj.dateObj
-            });
+            this.props.setSelection(targetObj.dateObj);
           }
         }
         break;
       }
     }
   },
 
   /**
--- a/toolkit/content/widgets/datekeeper.js
+++ b/toolkit/content/widgets/datekeeper.js
@@ -29,16 +29,20 @@ function DateKeeper(props) {
     get month() {
       return this.state.dateObj.getUTCMonth();
     },
 
     get day() {
       return this.state.dateObj.getUTCDate();
     },
 
+    get selection() {
+      return this.state.selection;
+    },
+
     /**
      * Initialize DateKeeper
      * @param  {Number} year
      * @param  {Number} month
      * @param  {Number} day
      * @param  {String} min
      * @param  {String} max
      * @param  {Number} firstDayOfWeek
@@ -53,16 +57,17 @@ function DateKeeper(props) {
         firstDayOfWeek, weekends, calViewSize,
         min: new Date(min != undefined ? min : MIN_DATE),
         max: new Date(max != undefined ? max : MAX_DATE),
         today: this._newUTCDate(today.getFullYear(), today.getMonth(), today.getDate()),
         weekHeaders: this._getWeekHeaders(firstDayOfWeek, weekends),
         years: [],
         months: [],
         days: [],
+        selection: { year, month, day },
       };
 
       this.state.dateObj = isDateSet ?
                            this._newUTCDate(year, month, day) :
                            new Date(this.state.today);
     },
     /**
      * Set new date. The year is always treated as full year, so the short-form
@@ -76,22 +81,24 @@ function DateKeeper(props) {
      */
     set({ year = this.year, month = this.month, day = this.day }) {
       // Use setUTCFullYear so that year 99 doesn't get parsed as 1999
       this.state.dateObj.setUTCFullYear(year, month, day);
     },
 
     /**
      * Set selection date
-     * @param {Date} selection
+     * @param {Number} year
+     * @param {Number} month
+     * @param {Number} day
      */
-    setSelection(selection) {
-      this.set({ year: selection.getUTCFullYear(),
-                 month: selection.getUTCMonth(),
-                 day: selection.getUTCDate() });
+    setSelection({ year, month, day }) {
+      this.state.selection.year = year;
+      this.state.selection.month = month;
+      this.state.selection.day = day;
     },
 
     /**
      * Set month. Makes sure the day is <= the last day of the month
      * @param {Number} month
      */
     setMonth(month) {
       const lastDayOfMonth = this._newUTCDate(this.year, month + 1, 0).getUTCDate();
@@ -195,16 +202,21 @@ function DateKeeper(props) {
         let classNames = [];
         let enabled = true;
         if (this.state.weekends.includes(dateObj.getUTCDay())) {
           classNames.push("weekend");
         }
         if (month != dateObj.getUTCMonth()) {
           classNames.push("outside");
         }
+        if (this.state.selection.year == dateObj.getUTCFullYear() &&
+            this.state.selection.month == dateObj.getUTCMonth() &&
+            this.state.selection.day == dateObj.getUTCDate()) {
+          classNames.push("selection");
+        }
         if (dateObj.getTime() < this.state.min.getTime() || dateObj.getTime() > this.state.max.getTime()) {
           classNames.push("out-of-range");
           enabled = false;
         }
         if (this.state.today.getTime() == dateObj.getTime()) {
           classNames.push("today");
         }
         days.push({
--- a/toolkit/content/widgets/datepicker.js
+++ b/toolkit/content/widgets/datepicker.js
@@ -52,42 +52,48 @@ function DatePicker(context) {
       });
 
       document.dir = dir;
 
       this.state = {
         dateKeeper,
         locale,
         isMonthPickerVisible: false,
-        isYearSet: false,
-        isMonthSet: false,
-        isDateSet: false,
         datetimeOrders: new Intl.DateTimeFormat(locale)
                           .formatToParts(new Date(0)).map(part => part.type),
         getDayString: new Intl.NumberFormat(locale).format,
         getWeekHeaderString: weekday => weekdayStrings[weekday],
         getMonthString: month => monthStrings[month],
-        setSelection: ({ selection }) => {
-          dateKeeper.setSelection(selection);
-          this.state.isYearSet = true;
-          this.state.isMonthSet = true;
-          this.state.isDateSet = true;
+        setSelection: date => {
+          dateKeeper.setSelection({
+            year: date.getUTCFullYear(),
+            month: date.getUTCMonth(),
+            day: date.getUTCDate(),
+          });
           this._update();
           this._dispatchState();
           this._closePopup();
         },
         setYear: year => {
           dateKeeper.setYear(year);
-          this.state.isYearSet = true;
+          dateKeeper.setSelection({
+            year,
+            month: dateKeeper.selection.month,
+            day: dateKeeper.selection.day,
+          });
           this._update();
           this._dispatchState();
         },
         setMonth: month => {
           dateKeeper.setMonth(month);
-          this.state.isMonthSet = true;
+          dateKeeper.setSelection({
+            year: dateKeeper.selection.year,
+            month,
+            day: dateKeeper.selection.day,
+          });
           this._update();
           this._dispatchState();
         },
         toggleMonthPicker: () => {
           this.state.isMonthPickerVisible = !this.state.isMonthPickerVisible;
           this._update();
         }
       };
@@ -160,29 +166,25 @@ function DatePicker(context) {
         name: "ClosePopup"
       }, "*");
     },
 
     /**
      * Use postMessage to pass the state of picker to the panel.
      */
     _dispatchState() {
-      const { year, month, day } = this.state.dateKeeper;
-      const { isYearSet, isMonthSet, isDaySet } = this.state;
+      const { year, month, day } = this.state.dateKeeper.selection;
       // The panel is listening to window for postMessage event, so we
       // do postMessage to itself to send data to input boxes.
       window.postMessage({
         name: "PickerPopupChanged",
         detail: {
           year,
           month,
           day,
-          isYearSet,
-          isMonthSet,
-          isDaySet
         }
       }, "*");
     },
 
     /**
      * Attach event listeners
      */
     _attachEventListeners() {
@@ -253,29 +255,22 @@ function DatePicker(context) {
      *          {Number} year [optional]
      *          {Number} month [optional]
      *          {Number} date [optional]
      *        }
      */
     set({ year, month, day }) {
       const { dateKeeper } = this.state;
 
-      if (year != undefined) {
-        this.state.isYearSet = true;
-      }
-      if (month != undefined) {
-        this.state.isMonthSet = true;
-      }
-      if (day != undefined) {
-        this.state.isDaySet = true;
-      }
-
       dateKeeper.set({
         year, month, day
       });
+      dateKeeper.setSelection({
+        year, month, day
+      });
       this._update();
     }
   };
 
   /**
    * MonthYear is a component that handles the month & year spinners
    *
    * @param {Object} options
--- a/toolkit/themes/shared/datetimeinputpickers.css
+++ b/toolkit/themes/shared/datetimeinputpickers.css
@@ -327,43 +327,44 @@ button.month-year.active::after {
   text-align: center;
   padding: calc((var(--spinner-item-height) - var(--font-size-default)) / 2) 0;
   margin-bottom: var(--spinner-item-margin-bottom);
   height: var(--spinner-item-height);
   -moz-user-select: none;
   scroll-snap-coordinate: 0 0;
 }
 
+.spinner-container > .spinner > div::before,
+.calendar-container .days-view > div::before {
+  position: absolute;
+  top: 5%;
+  bottom: 5%;
+  left: 5%;
+  right: 5%;
+  z-index: -10;
+  border-radius: var(--border-radius);
+}
+
 .spinner-container > .spinner > div:hover::before,
 .calendar-container .days-view > div:hover::before {
   background: var(--fill-color);
   border: var(--border);
-  border-radius: var(--border-radius);
   content: "";
-  position: absolute;
-  z-index: -10;
 }
 
 .spinner-container > .spinner:not(.scrolling) > div.selection,
-.calendar-container .days-view > div.selection {
+.calendar-container .days-view > div.selection:not(.out-of-range) {
   color: var(--selected-font-color);
 }
 
 .spinner-container > .spinner > div.selection::before,
 .calendar-container .days-view > div.selection::before {
   background: var(--selected-fill-color);
   border: none;
-  border-radius: var(--border-radius);
   content: "";
-  position: absolute;
-  top: 0%;
-  bottom: 0%;
-  left: 0%;
-  right: 0%;
-  z-index: -10;
 }
 
 .spinner-container > .spinner > div.disabled::before,
 .spinner-container > .spinner.scrolling > div.selection::before,
 .spinner-container > .spinner.scrolling > div:hover::before {
   display: none;
 }