Skip to content

Commit

Permalink
feat(ItemNavigation): handle Page UP/DOWN (#3727)
Browse files Browse the repository at this point in the history
As we improve the keyboard handling more and more, it turns out the Item Navigation does not handle Page Up and Page Down combinations. The change has been triggered from this recently merged SegmentedButton PR and this in progress
Timeline PR where we manually handle the focus on PageUp/Down. Now, the code from the SegmentedButton is removed, as the ItemNavigation takes care of it.

For most of the components, Page Up/Down should behave as Home and End. But some of the components has specific predefined number of items that should be skipped before applying the focus to the next item. Therefore, we also introduce a new property "skipItemsSize". In this change only the List is using it.

Note: for grid/matrix components (like ColorPalette,ProductSwitch), the PageDown/Up should move the focus in column direction. This will be done with future enhancement.
  • Loading branch information
ilhan007 authored Aug 25, 2021
1 parent 1c8e656 commit 91a974f
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 13 deletions.
2 changes: 1 addition & 1 deletion packages/base/hash.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9tF7yEWQXVH9MvgcDDfgmFxdVoU=
U9zClJPhSOUR0TQbGCxYYRJJTOQ=
66 changes: 66 additions & 0 deletions packages/base/src/delegate/ItemNavigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
isRight,
isHome,
isEnd,
isPageDown,
isPageUp,
} from "../Keys.js";
import getActiveElement from "../util/getActiveElement.js";

Expand Down Expand Up @@ -52,6 +54,7 @@ class ItemNavigation {
* - currentIndex: the index of the item that will be initially selected (from which navigation will begin)
* - navigationMode (Auto|Horizontal|Vertical): whether the items are displayed horizontally (Horizontal), vertically (Vertical) or as a matrix (Auto) meaning the user can navigate in both directions (up/down and left/right)
* - rowSize: tells how many items per row there are when the items are not rendered as a flat list but rather as a matrix. Relevant for navigationMode=Auto
* - skipItemsSize: tells how many items upon PAGE_UP and PAGE_DOWN should be skipped to applying the focus on the next item
* - behavior (Static|Cycling): tells what to do when trying to navigate beyond the first and last items
* Static means that nothing happens if the user tries to navigate beyond the first/last item.
* Cycling means that when the user navigates beyond the last item they go to the first and vice versa.
Expand Down Expand Up @@ -85,6 +88,7 @@ class ItemNavigation {
this._behavior = options.behavior || ItemNavigationBehavior.Static;
this._navigationMode = options.navigationMode || NavigationMode.Auto;
this._affectedPropertiesNames = options.affectedPropertiesNames || [];
this._skipItemsSize = options.skipItemsSize || null;
}

/**
Expand Down Expand Up @@ -142,6 +146,10 @@ class ItemNavigation {
this._handleHome();
} else if (isEnd(event)) {
this._handleEnd();
} else if (isPageUp(event)) {
this._handlePageUp();
} else if (isPageDown(event)) {
this._handlePageDown();
} else {
return; // if none of the supported keys is pressed, we don't want to prevent the event or update the item navigation
}
Expand Down Expand Up @@ -222,6 +230,64 @@ class ItemNavigation {
this._currentIndex += (homeEndRange - 1 - this._currentIndex % homeEndRange); // eslint-disable-line
}

_handlePageUp() {
if (this._rowSize > 1) {
// eslint-disable-next-line
// TODO: handle page up on matrix (grid) layout - ColorPalette, ProductSwitch.
return;
}
this._handlePageUpFlat();
}

_handlePageDown() {
if (this._rowSize > 1) {
// eslint-disable-next-line
// TODO: handle page up on matrix (grid) layout - ColorPalette, ProductSwitch.
return;
}
this._handlePageDownFlat();
}

/**
* Handles PAGE_UP in a flat list-like structure, both vertically and horizontally.
*/
_handlePageUpFlat() {
if (this._skipItemsSize === null) {
// Move the focus to the very top (as Home).
this._currentIndex -= this._currentIndex;
}

if (this._currentIndex + 1 > this._skipItemsSize) {
// When there are more than "skipItemsSize" number of items to the top,
// move the focus up/left with the predefined number.
this._currentIndex -= this._skipItemsSize;
} else {
// Otherwise, move the focus to the very top (as Home).
this._currentIndex -= this._currentIndex;
}
}

/**
* Handles PAGE_DOWN in a flat list-like structure, both vertically and horizontally.
*/
_handlePageDownFlat() {
if (this._skipItemsSize === null) {
// Move the focus to the very bottom (as End).
this._currentIndex = this._getItems().length - 1;
}

const currentToEndRange = this._getItems().length - this._currentIndex - 1;

if (currentToEndRange > this._skipItemsSize) {
// When there are more than "skipItemsSize" number of items until the bottom,
// move the focus down/right with the predefined number.
this._currentIndex += this._skipItemsSize;
} else {
// Otherwise, move the focus to the very bottom (as End).
this._currentIndex = this._getItems().length - 1;
}
}

_applyTabIndex() {
const items = this._getItems();
for (let i = 0; i < items.length; i++) {
Expand Down
3 changes: 3 additions & 0 deletions packages/main/src/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import { LOAD_MORE_TEXT } from "./generated/i18n/i18n-defaults.js";

const INFINITE_SCROLL_DEBOUNCE_RATE = 250; // ms

const PAGE_UP_DOWN_SIZE = 10;

/**
* @public
*/
Expand Down Expand Up @@ -575,6 +577,7 @@ class List extends UI5Element {

initItemNavigation() {
this._itemNavigation = new ItemNavigation(this, {
skipItemsSize: PAGE_UP_DOWN_SIZE, // PAGE_UP and PAGE_DOWN will skip trough 10 items
navigationMode: NavigationMode.Vertical,
getItemsCallback: () => this.getEnabledItems(),
});
Expand Down
12 changes: 0 additions & 12 deletions packages/main/src/SegmentedButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { isIE } from "@ui5/webcomponents-base/dist/Device.js";
import {
isSpace,
isEnter,
isPageUp,
isPageDown,
} from "@ui5/webcomponents-base/dist/Keys.js";
import { SEGMENTEDBUTTON_ARIA_DESCRIPTION, SEGMENTEDBUTTON_ARIA_DESCRIBEDBY } from "./generated/i18n/i18n-defaults.js";
import SegmentedButtonItem from "./SegmentedButtonItem.js";
Expand Down Expand Up @@ -218,16 +216,6 @@ class SegmentedButton extends UI5Element {
this._selectItem(event);
} else if (isSpace(event)) {
event.preventDefault();
} else if (isPageUp(event)) {
event.preventDefault();
const target = this.items[0];
target.focus();
this._itemNavigation.setCurrentItem(target);
} else if (isPageDown(event)) {
event.preventDefault();
const target = this.items[this.items.length - 1];
target.focus();
this._itemNavigation.setCurrentItem(target);
}
}

Expand Down
38 changes: 38 additions & 0 deletions packages/main/test/pages/ItemNavigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,43 @@ <h2>Vertical navigation only</h2>
<ui5-li id="item4">Option 2.2</ui5-li>
<ui5-li id="item5">Option 2.3</ui5-li>
</ui5-list>

<h1>Test PAGE UP/DOWN</h1>
<br><br>
<ui5-list>
<ui5-li id="pageUpDownList_item1">0</ui5-li>
<ui5-li>1</ui5-li>
<ui5-li>2</ui5-li>
<ui5-li id="pageUpDownList_item4">3</ui5-li>
<ui5-li>4</ui5-li>
<ui5-li id="pageUpDownList_item6">5</ui5-li>
<ui5-li>6</ui5-li>
<ui5-li>7</ui5-li>
<ui5-li>8</ui5-li>
<ui5-li>9</ui5-li>
<ui5-li id="pageUpDownList_item11">10</ui5-li>

<ui5-li>11</ui5-li>
<ui5-li>12</ui5-li>
<ui5-li>13</ui5-li>
<ui5-li>14</ui5-li>
<ui5-li id="pageUpDownList_item16">15</ui5-li>
<ui5-li>16</ui5-li>
<ui5-li>17</ui5-li>
<ui5-li>18</ui5-li>
<ui5-li>19</ui5-li>
<ui5-li>20</ui5-li>

<ui5-li>21</ui5-li>
<ui5-li>22</ui5-li>
<ui5-li>23</ui5-li>
<ui5-li>24</ui5-li>
<ui5-li id="pageUpDownList_item26">25</ui5-li>
<ui5-li>26</ui5-li>
<ui5-li>27</ui5-li>
<ui5-li>28</ui5-li>
<ui5-li>29</ui5-li>
<ui5-li>30</ui5-li>
</ui5-list>
</body>
</html>
40 changes: 40 additions & 0 deletions packages/main/test/pages/List_keyboard_support.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,45 @@ <h1>UI5 Table Web Component</h1>
</ui5-list>

<div class="focusable" tabindex="0"></div>

<h1>Test PAGE UP/DOWN</h1>
<br><br>
<ui5-list>
<ui5-li>0</ui5-li>
<ui5-li>1</ui5-li>
<ui5-li>2</ui5-li>
<ui5-li>3</ui5-li>
<ui5-li>4</ui5-li>
<ui5-li>5</ui5-li>
<ui5-li>6</ui5-li>
<ui5-li>7</ui5-li>
<ui5-li>8</ui5-li>
<ui5-li>9</ui5-li>
<ui5-li>10</ui5-li>

<ui5-li>11</ui5-li>
<ui5-li>12</ui5-li>
<ui5-li>13</ui5-li>
<ui5-li>14</ui5-li>
<ui5-li>15</ui5-li>
<ui5-li>16</ui5-li>
<ui5-li>17</ui5-li>
<ui5-li>18</ui5-li>
<ui5-li>19</ui5-li>
<ui5-li>20</ui5-li>

<ui5-li>21</ui5-li>
<ui5-li>22</ui5-li>
<ui5-li>23</ui5-li>
<ui5-li>24</ui5-li>
<ui5-li>25</ui5-li>
<ui5-li>26</ui5-li>
<ui5-li>27</ui5-li>
<ui5-li>28</ui5-li>
<ui5-li>29</ui5-li>
<ui5-li>30</ui5-li>
</ui5-list>


</body>
</html>
34 changes: 34 additions & 0 deletions packages/main/test/specs/ItemNavigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,38 @@ describe("Item Navigation Tests", () => {
firstItem.keys("ArrowDown");
assert.strictEqual(secondItem.isFocused(), true, "second item is now focused - vertical navigation allowed.");
});


it("test PageDown", () => {
const itemOnFocus = $("#pageUpDownList_item1");
const nextFocusedItem = $("#pageUpDownList_item11");

itemOnFocus.click();
itemOnFocus.keys("PageDown");
assert.strictEqual(nextFocusedItem.isFocused(), true, "The 11th item is focused.");

const itemOnFocus2 = $("#pageUpDownList_item16");
const nextFocusedItem2 = $("#pageUpDownList_item26");

itemOnFocus2.click();
itemOnFocus2.keys("PageDown");
assert.strictEqual(nextFocusedItem2.isFocused(), true, "The 26th is focused.");
});


it("test PageUp", () => {
const itemOnFocus = $("#pageUpDownList_item4");
const nextFocusedItem = $("#pageUpDownList_item1");

itemOnFocus.click();
itemOnFocus.keys("PageUp");
assert.strictEqual(nextFocusedItem.isFocused(), true, "The first item is focused.");

const itemOnFocus2 = $("#pageUpDownList_item16");
const nextFocusedItem2 = $("#pageUpDownList_item6");

itemOnFocus2.click();
itemOnFocus2.keys("PageUp");
assert.strictEqual(nextFocusedItem2.isFocused(), true, "The 6th is focused.");
});
});

0 comments on commit 91a974f

Please sign in to comment.