Commit 9fbb516b authored by Stephen Sigwart's avatar Stephen Sigwart Committed by Commit Bot

Allow home/end for date/time pickers

Home key changes to first of month, January in month view, and week 1 in
week view. End key changes to last of month, December, or last week. For
time, home goes to 1, 00, and am while end goes to 12, 59, and pm.

Bug: 1062025
Change-Id: I40daebeca55eeb578a3b75d1ab06b6013d9bc540
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2358476Reviewed-by: default avatarMason Freed <masonfreed@chromium.org>
Commit-Queue: Stephen Sigwart <ssigwart@gmail.com>
Cr-Commit-Position: refs/heads/master@{#800548}
parent fe990596
...@@ -304,6 +304,25 @@ Day.prototype.next = function(offset) { ...@@ -304,6 +304,25 @@ Day.prototype.next = function(offset) {
return new Day(this.year, this.month, this.date + offset); return new Day(this.year, this.month, this.date + offset);
}; };
/**
* @return {!Day}
*/
Day.prototype.nextHome = function() {
if (this.date !== 1)
return new Day(this.year, this.month, 1);
return new Day(this.year, this.month - 1, 1);
};
/**
* @return {!Day}
*/
Day.prototype.nextEnd = function() {
let tomorrow = this.next();
if (tomorrow.month === this.month)
return new Day(this.year, this.month + 1, 1).previous();
return new Day(tomorrow.year, tomorrow.month + 1, 1).previous();
};
/** /**
* Given that 'this' is the Nth day of the month, returns the Nth * Given that 'this' is the Nth day of the month, returns the Nth
* day of the month that is specified by the parameter. * day of the month that is specified by the parameter.
...@@ -603,6 +622,30 @@ Week.prototype.next = function(offset) { ...@@ -603,6 +622,30 @@ Week.prototype.next = function(offset) {
return new Week(this.year, this.week + offset); return new Week(this.year, this.week + offset);
}; };
/**
* @return {!Week}
*/
Week.prototype.nextHome = function() {
// Go back weeks until we find the one that is the first week of a month. Do
// that by finding the first day in the current week, then go back a day. We
// want the first week of the month for that day.
var desiredDay = this.firstDay().previous();
desiredDay.date = 1;
return Week.createFromDay(desiredDay);
};
/**
* @return {!Week}
*/
Week.prototype.nextEnd = function() {
// Go forward weeks until we find the one that is the last week of a month. Do
// that by finding the week containing the last day of the month for the day
// following the last day included in the current week.
var desiredDay = this.lastDay().next();
desiredDay = new Day(desiredDay.year, desiredDay.month + 1, 1).previous();
return Week.createFromDay(desiredDay);
};
/** /**
* Given that 'this' is the Nth week of the month, returns * Given that 'this' is the Nth week of the month, returns
* the Week that is the Nth week in the month specified * the Week that is the Nth week in the month specified
...@@ -828,6 +871,24 @@ Month.prototype.next = function(offset) { ...@@ -828,6 +871,24 @@ Month.prototype.next = function(offset) {
return new Month(this.year, this.month + offset); return new Month(this.year, this.month + offset);
}; };
/**
* @return {!Month}
*/
Month.prototype.nextHome = function() {
if (this.month !== 0)
return new Month(this.year, 0);
return new Month(this.year - 1, 0);
};
/**
* @return {!Month}
*/
Month.prototype.nextEnd = function() {
if (this.month !== MonthsPerYear - 1)
return new Month(this.year, MonthsPerYear - 1);
return new Month(this.year + 1, MonthsPerYear - 1);
};
/** /**
* @return {!Date} * @return {!Date}
*/ */
...@@ -3168,6 +3229,23 @@ YearListView.prototype.onKeyDown = function(event) { ...@@ -3168,6 +3229,23 @@ YearListView.prototype.onKeyDown = function(event) {
if (newSelection) { if (newSelection) {
this.setSelectedMonthAndUpdateView(newSelection); this.setSelectedMonthAndUpdateView(newSelection);
} }
} else if (key == 'Home') {
var newMonth = this._selectedMonth.month === 0 ?
new Month(this._selectedMonth.year - 1, 0) :
new Month(this._selectedMonth.year, 0);
var newSelection = this.getNearestValidRangeLookingBackward(newMonth);
if (newSelection) {
this.setSelectedMonthAndUpdateView(newSelection);
}
} else if (key == 'End') {
var lastMonthNum = MonthsPerYear - 1;
var newMonth = this._selectedMonth.month === lastMonthNum ?
new Month(this._selectedMonth.year + 1, lastMonthNum) :
new Month(this._selectedMonth.year, lastMonthNum);
var newSelection = this.getNearestValidRangeLookingForward(newMonth);
if (newSelection) {
this.setSelectedMonthAndUpdateView(newSelection);
}
} else if (this.type !== 'month') { } else if (this.type !== 'month') {
if (key == 'Enter') { if (key == 'Enter') {
this.dispatchEvent( this.dispatchEvent(
...@@ -5020,6 +5098,20 @@ CalendarPicker.prototype.onCalendarTableKeyDownRefresh = function(event) { ...@@ -5020,6 +5098,20 @@ CalendarPicker.prototype.onCalendarTableKeyDownRefresh = function(event) {
} }
} }
break; break;
case 'Home':
var newSelection = this.getNearestValidRangeLookingBackward(
this._selection.nextHome());
if (newSelection) {
this.setSelection(newSelection);
}
break;
case 'End':
var newSelection =
this.getNearestValidRangeLookingForward(this._selection.nextEnd());
if (newSelection) {
this.setSelection(newSelection);
}
break;
}; };
} }
// else if there is no selection it must be the case that there are no // else if there is no selection it must be the case that there are no
...@@ -5163,6 +5255,8 @@ CalendarPicker.prototype.onBodyKeyDown = function(event) { ...@@ -5163,6 +5255,8 @@ CalendarPicker.prototype.onBodyKeyDown = function(event) {
case 'ArrowRight': case 'ArrowRight':
case 'PageUp': case 'PageUp':
case 'PageDown': case 'PageDown':
case 'Home':
case 'End':
if (global.params.isFormControlsRefreshEnabled && if (global.params.isFormControlsRefreshEnabled &&
this.type !== 'datetime-local' && this.type !== 'datetime-local' &&
event.target.matches('.calendar-table-view') && this._selection) { event.target.matches('.calendar-table-view') && this._selection) {
......
...@@ -88,6 +88,8 @@ class DateTimeLocalPicker extends HTMLElement { ...@@ -88,6 +88,8 @@ class DateTimeLocalPicker extends HTMLElement {
break; break;
case 'Home': case 'Home':
case 'End': case 'End':
window.pagePopupController.setValue(this.selectedValue);
event.stopPropagation();
// Prevent an attempt to scroll to the end of // Prevent an attempt to scroll to the end of
// of an infinitely looping time picker column. // of an infinitely looping time picker column.
event.preventDefault(); event.preventDefault();
......
...@@ -135,6 +135,8 @@ class MonthPicker extends HTMLElement { ...@@ -135,6 +135,8 @@ class MonthPicker extends HTMLElement {
case 'ArrowRight': case 'ArrowRight':
case 'PageUp': case 'PageUp':
case 'PageDown': case 'PageDown':
case 'Home':
case 'End':
if (this.selectedMonth) { if (this.selectedMonth) {
window.pagePopupController.setValue(this.selectedMonth.toString()); window.pagePopupController.setValue(this.selectedMonth.toString());
} }
......
...@@ -282,6 +282,8 @@ class TimePicker extends HTMLElement { ...@@ -282,6 +282,8 @@ class TimePicker extends HTMLElement {
break; break;
case 'Home': case 'Home':
case 'End': case 'End':
window.pagePopupController.setValue(this.selectedValue);
event.stopPropagation();
// Prevent an attempt to scroll to the end of // Prevent an attempt to scroll to the end of
// of an infinitely looping column. // of an infinitely looping column.
event.preventDefault(); event.preventDefault();
...@@ -697,6 +699,14 @@ class TimeColumn extends HTMLUListElement { ...@@ -697,6 +699,14 @@ class TimeColumn extends HTMLUListElement {
nextTimeColumn.focus(); nextTimeColumn.focus();
} }
break; break;
case 'Home':
this.setToMinValue();
this.scrollToSelectedCell();
break;
case 'End':
this.setToMaxValue();
this.scrollToSelectedCell();
break;
} }
}; };
...@@ -730,6 +740,38 @@ class TimeColumn extends HTMLUListElement { ...@@ -730,6 +740,38 @@ class TimeColumn extends HTMLUListElement {
} }
}; };
setToMinValue = () => {
if (this.columnType_ == TimeColumnType.AMPM) {
this.selectedTimeCell = this.firstChild;
const isAM = this.selectedTimeCell.textContent ==
global.params.ampmLabels[Label.AM];
if (!isAM)
this.selectedTimeCell = this.lastChild;
} else {
this.selectedTimeCell = this.firstChild;
for (let timeCell of this.children) {
if (timeCell.value < this.selectedTimeCell.value)
this.selectedTimeCell = timeCell;
}
}
};
setToMaxValue = () => {
if (this.columnType_ == TimeColumnType.AMPM) {
this.selectedTimeCell = this.firstChild;
const isAM = this.selectedTimeCell.textContent ==
global.params.ampmLabels[Label.AM];
if (isAM)
this.selectedTimeCell = this.lastChild;
} else {
this.selectedTimeCell = this.lastChild;
for (let timeCell of this.children) {
if (timeCell.value > this.selectedTimeCell.value)
this.selectedTimeCell = timeCell;
}
}
};
get columnType() { get columnType() {
return this.columnType_; return this.columnType_;
} }
......
...@@ -21,6 +21,24 @@ promise_test(() => { ...@@ -21,6 +21,24 @@ promise_test(() => {
eventSender.keyDown('PageUp'); eventSender.keyDown('PageUp');
assert_equals(dateElement.value, "2019-02-14", "Previous month hotkey should have decremented month"); assert_equals(dateElement.value, "2019-02-14", "Previous month hotkey should have decremented month");
eventSender.keyDown('Home');
assert_equals(dateElement.value, "2019-02-01", "Home hotkey should go to the first of the month");
eventSender.keyDown('Home');
assert_equals(dateElement.value, "2019-01-01", "Home hotkey should go to the first of the previous month");
eventSender.keyDown('Home');
assert_equals(dateElement.value, "2018-12-01", "Home hotkey should wrap to previous year");
eventSender.keyDown('End');
assert_equals(dateElement.value, "2018-12-31", "End hotkey should go to the end of the month");
eventSender.keyDown('End');
assert_equals(dateElement.value, "2019-01-31", "End hotkey hotkey should wrap to next year");
eventSender.keyDown('End');
assert_equals(dateElement.value, "2019-02-28", "End hotkey should go to the end of the next month");
eventSender.keyDown('Enter'); eventSender.keyDown('Enter');
assert_equals(internals.pagePopupWindow, null, "Enter key should have closed popup."); assert_equals(internals.pagePopupWindow, null, "Enter key should have closed popup.");
}); });
......
<!DOCTYPE html>
<html>
<head>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../fast/forms/resources/common.js"></script>
<script src="../../../fast/forms/resources/picker-common.js"></script>
<script src="../../../fast/forms/calendar-picker/resources/calendar-picker-common.js"></script>
</head>
<body>
<input type="month" id="month-0" value="2018-06">
<script>
promise_test(() => {
let monthElement = document.getElementById('month-0');
return openPickerWithPromise(monthElement)
.then(() => {
eventSender.keyDown('Home');
assert_equals(monthElement.value, "2018-01", "Home hotkey should go to the first of the year");
eventSender.keyDown('Home');
assert_equals(monthElement.value, "2017-01", "Home hotkey should go to the previous year");
eventSender.keyDown('End');
assert_equals(monthElement.value, "2017-12", "End hotkey should go to the end of the year");
eventSender.keyDown('End');
assert_equals(monthElement.value, "2018-12", "End hotkey should go to the next year");
eventSender.keyDown('Enter');
assert_equals(internals.pagePopupWindow, null, "Enter key should have closed popup.");
});
}, "Month picker: Home/end month hotkeys");
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../fast/forms/resources/common.js"></script>
<script src="../../../fast/forms/resources/picker-common.js"></script>
<script src="../../../fast/forms/calendar-picker/resources/calendar-picker-common.js"></script>
</head>
<body>
<input type="week" id="week-0" value="2018-W23">
<script>
promise_test(() => {
let weekElement = document.getElementById('week-0');
return openPickerWithPromise(weekElement)
.then(() => {
eventSender.keyDown('Home');
assert_equals(weekElement.value, "2018-W22", "Home hotkey should go to the first week of the month");
for (let week of [18, 13,9,5,1]) {
eventSender.keyDown('Home');
assert_equals(weekElement.value, "2018-W" + ("0" + week).substr(-2), "Home hotkey should go to the first week of the previous month");
}
eventSender.keyDown('Home');
assert_equals(weekElement.value, "2017-W48", "Home hotkey should wrap to the previous year");
eventSender.keyDown('End');
assert_equals(weekElement.value, "2017-W52", "End hotkey should go to the end week of the month");
eventSender.keyDown('End');
assert_equals(weekElement.value, "2018-W05", "End hotkey should go to the end week of the next month (wrapping to next year)");
eventSender.keyDown('Enter');
assert_equals(internals.pagePopupWindow, null, "Enter key should have closed popup.");
});
}, "Week picker: Home/end month hotkeys");
</script>
</body>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment