Bug 1361676 - Show selection highlight on date picker. r=mconley
authorScott Wu <scottcwwu@gmail.com>
Wed, 03 May 2017 18:05:36 +0800
changeset 357426 1500391c15309e87a843aeb7fd46a98e5273b8ad
parent 357425 0398b6fa1a0e574aef4370d1151574c550476551
child 357427 07819b6e08bfa493cb54ec1a2b7072694ec224cc
push id42366
push usercbook@mozilla.com
push dateWed, 10 May 2017 13:20:39 +0000
treeherderautoland@1500391c1530 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1361676
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;
 }