Skip to content

Commit

Permalink
feat(ui5-time-picker): improve keyboard handling support (#2092)
Browse files Browse the repository at this point in the history
PageUp: Hours + 1, PageDown: Hours - 1, PageUp + Shift : Minutes + 1
PageDown + Shift: Minutes - 1, PageUp + Shift + Ctrl: Seconds + 1, PageDown + Shift + Ctrl: Seconds - 1

Related to: #1534
  • Loading branch information
tsanislavgatev committed Aug 18, 2020
1 parent ed3c393 commit 20c55ed
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 1 deletion.
18 changes: 18 additions & 0 deletions packages/base/src/Keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ const isBackSpace = event => (event.key ? event.key === "Backspace" : event.keyC

const isDelete = event => (event.key ? event.key === "Delete" : event.keyCode === KeyCodes.DELETE) && !hasModifierKeys(event);

const isPageUp = event => (event.key ? event.key === "PageUp" : event.keyCode === KeyCodes.PAGE_UP) && !hasModifierKeys(event);

const isPageDown = event => (event.key ? event.key === "PageDown" : event.keyCode === KeyCodes.PAGE_DOWN) && !hasModifierKeys(event);

const isPageUpShift = event => (event.key ? event.key === "PageUp" : event.keyCode === KeyCodes.PAGE_UP) && checkModifierKeys(event, false, false, true);

const isPageDownShift = event => (event.key ? event.key === "PageDown" : event.keyCode === KeyCodes.PAGE_DOWN) && checkModifierKeys(event, false, false, true);

const isPageUpShiftCtrl = event => (event.key ? event.key === "PageUp" : event.keyCode === KeyCodes.PAGE_UP) && checkModifierKeys(event, true, false, true);

const isPageDownShiftCtrl = event => (event.key ? event.key === "PageDown" : event.keyCode === KeyCodes.PAGE_DOWN) && checkModifierKeys(event, true, false, true);

const isShow = event => {
if (event.key) {
return isF4(event) || isShowByArrows(event);
Expand Down Expand Up @@ -167,4 +179,10 @@ export {
isDelete,
isShow,
isF4,
isPageUp,
isPageDown,
isPageUpShift,
isPageDownShift,
isPageUpShiftCtrl,
isPageDownShiftCtrl,
};
86 changes: 86 additions & 0 deletions packages/main/src/TimePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ import {
isTabNext,
isTabPrevious,
isShow,
isPageUp,
isPageDown,
isPageUpShift,
isPageDownShift,
isPageUpShiftCtrl,
isPageDownShiftCtrl,
} from "@ui5/webcomponents-base/src/Keys.js";
import "@ui5/webcomponents-icons/dist/icons/time-entry-request.js";
import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js";
Expand Down Expand Up @@ -231,6 +237,22 @@ const metadata = {
* For example, if the <code>format-pattern</code> is "HH:mm:ss",
* a valid value string is "11:42:35" and the same is displayed in the input.
*
* <h3>Keyboard handling</h3>
* [F4], [ALT]+[UP], [ALT]+[DOWN] Open/Close picker dialog and move focus to it.
* When closed:
* [PAGEUP] - Increments hours by 1. If 12 am is reached, increment hours to 1 pm and vice versa.
* [PAGEDOWN] - Decrements the corresponding field by 1. If 1 pm is reached, decrement hours to 12 am and vice versa.
* [SHIFT]+[PAGEUP] Increments minutes by 1.
* [SHIFT]+ [PAGEDOWN] Decrements minutes by 1.
* [SHIFT]+[CTRL]+[PAGEUP] Increments seconds by 1.
* [SHIFT]+[CTRL]+ [PAGEDOWN] Decrements seconds by 1.
* When opened:
* [UP] If focus is on one of the selection lists: Select the value which is above the current value. If the first value is selected, select the last value in the list. Exception: AM/ PM List: stay on the first item.
* [DOWN] If focus is on one of the selection lists: Select the value which is below the current value. If the last value is selected, select the first value in the list. Exception: AM/ PM List: stay on the last item.
* [LEFT] If focus is on one of the selection lists: Move focus to the selection list which is left of the current selection list. If focus is at the first selection list, move focus to the last selection list.
* [RIGHT] If focus is on one of the selection lists: Move focus to the selection list which is right of the current selection list. When focus is at the last selection list, move focus to the first selection list.
* [PAGEUP] If focus is on one of the selection lists: Move focus to the first entry of this list.
* [PAGEDOWN] If focus is on one of the selection lists: Move focus to the last entry of this list.
* <h3>ES6 Module Import</h3>
*
* <code>import @ui5/webcomponents/dist/TimePicker.js";</code>
Expand Down Expand Up @@ -647,6 +669,26 @@ class TimePicker extends UI5Element {
e.preventDefault();
responsivePopover.querySelector(`.ui5-time-picker-footer`).lastElementChild.focus();
}

if (isPageDown(e)) {
this._selectLimitCell(e, false);
} else if (isPageUp(e)) {
this._selectLimitCell(e, true);
}
}

_selectLimitCell(e, isMax) {
e.preventDefault();
if (e.target === this.hoursSlider) {
const hoursArray = this.hoursArray;
e.target.value = isMax ? hoursArray[hoursArray.length - 1] : hoursArray[0];
} else if (e.target === this.minutesSlider) {
const minutesArray = this.minutesArray;
e.target.value = isMax ? minutesArray[minutesArray.length - 1] : minutesArray[0];
} else if (e.target === this.secondsSlider) {
const secondsArray = this.secondsArray;
e.target.value = isMax ? secondsArray[secondsArray.length - 1] : secondsArray[0];
}
}

_onfooterkeydown(e) {
Expand Down Expand Up @@ -674,6 +716,50 @@ class TimePicker extends UI5Element {
e.preventDefault();
this.togglePicker();
}

if (this.isOpen()) {
return;
}

if (isPageUpShiftCtrl(e)) {
e.preventDefault();
this._incrementValue(true, false, false, true);
} else if (isPageUpShift(e)) {
e.preventDefault();
this._incrementValue(true, false, true, false);
} else if (isPageUp(e)) {
e.preventDefault();
this._incrementValue(true, true, false, false);
}

if (isPageDownShiftCtrl(e)) {
e.preventDefault();
this._incrementValue(false, false, false, true);
} else if (isPageDownShift(e)) {
e.preventDefault();
this._incrementValue(false, false, true, false);
} else if (isPageDown(e)) {
e.preventDefault();
this._incrementValue(false, true, false, false);
}
}

_incrementValue(increment, hours, minutes, seconds) {
const date = this.dateValue;
const incrementStep = increment ? 1 : -1;

if (hours && this.shouldBuildHoursSlider) {
date.setHours(date.getHours() + incrementStep);
} else if (minutes && this.shouldBuildMinutesSlider) {
date.setMinutes(date.getMinutes() + incrementStep);
} else if (seconds && this.shouldBuildSecondsSlider) {
date.setSeconds(date.getSeconds() + incrementStep);
} else {
return;
}

this.setValue(this.formatValue(date));
this.fireEvent("change", { value: this.value, valid: true });
}

_handleWheel(e) {
Expand Down
2 changes: 1 addition & 1 deletion packages/main/src/TimePickerPopover.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@keydown="{{_ontimepickerpopoverkeydown}}"
@wheel="{{_handleWheel}}"
>
<div class="{{classes.container}}" @keydown={{_oncontainerkeydown}} tabindex="0" @focusin="{{_onfocuscontainerin}}">
<div class="{{classes.container}}" @keydown={{_oncontainerkeydown}} tabindex="-1" @focusin="{{_onfocuscontainerin}}">
{{#if shouldBuildHoursSlider}}
<ui5-wheelslider
label = "{{hoursSliderTitle}}"
Expand Down
49 changes: 49 additions & 0 deletions packages/main/test/specs/TimePicker.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,53 @@ describe("TimePicker general interaction", () => {
// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("valueState"), "None", "The value state is None");
});

it("tests input keyboard handling", () => {
const timepicker = browser.$("#timepicker5");

// act
timepicker.click();
timepicker.keys(['Shift', 'PageUp']);
timepicker.keys('Shift');

// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("value"), "12:01:01", "The value of minutes is +1");
// act
timepicker.click();
timepicker.keys(['Shift', 'PageDown']);
timepicker.keys('Shift');

// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("value"), "12:00:01", "The value of minutes is -1");

// act
timepicker.click();
timepicker.keys('PageUp');

// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("value"), "01:00:01", "The value of hours is +1");
// act
timepicker.click();
timepicker.keys('PageDown');

// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("value"), "12:00:01", "The value of hours is -1");

// act
timepicker.click();
timepicker.keys(['Shift', 'Control', 'PageUp']);
timepicker.keys('Shift');
timepicker.keys('Control');

// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("value"), "12:00:02", "The value of seconds is +1");
// act
timepicker.click();
timepicker.keys(['Shift', 'Control', 'PageDown']);
timepicker.keys('Shift');
timepicker.keys('Control');

// assert
assert.strictEqual(timepicker.shadow$("ui5-input").getProperty("value"), "12:00:01", "The value of seconds is -1");
});
});

0 comments on commit 20c55ed

Please sign in to comment.