Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoSot <geo.sotis@gmail.com>2021-05-19 01:23:52 +0300
committerGitHub <noreply@github.com>2021-05-19 01:23:52 +0300
commitdf72a21fa89a4885bb666f4a3bc0a9e757b870c2 (patch)
treed80c2614184e53f73de9364ac46dbeef9f61aa08
parent372890b67b28238c98ec4d5ffcdb777c9939e87c (diff)
Add `getNextActiveElement` helper function to utils, replacing custom implementation through components (#33608)
-rw-r--r--js/src/carousel.js17
-rw-r--r--js/src/dropdown.js22
-rw-r--r--js/src/util/index.js29
-rw-r--r--js/tests/unit/util/index.spec.js39
4 files changed, 76 insertions, 31 deletions
diff --git a/js/src/carousel.js b/js/src/carousel.js
index bb894e9c37..7d197ab1ee 100644
--- a/js/src/carousel.js
+++ b/js/src/carousel.js
@@ -10,6 +10,7 @@ import {
getElementFromSelector,
isRTL,
isVisible,
+ getNextActiveElement,
reflow,
triggerTransitionEnd,
typeCheckConfig
@@ -337,21 +338,7 @@ class Carousel extends BaseComponent {
_getItemByOrder(order, activeElement) {
const isNext = order === ORDER_NEXT
- const isPrev = order === ORDER_PREV
- const activeIndex = this._getItemIndex(activeElement)
- const lastItemIndex = this._items.length - 1
- const isGoingToWrap = (isPrev && activeIndex === 0) || (isNext && activeIndex === lastItemIndex)
-
- if (isGoingToWrap && !this._config.wrap) {
- return activeElement
- }
-
- const delta = isPrev ? -1 : 1
- const itemIndex = (activeIndex + delta) % this._items.length
-
- return itemIndex === -1 ?
- this._items[this._items.length - 1] :
- this._items[itemIndex]
+ return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap)
}
_triggerSlideEvent(relatedTarget, eventDirectionName) {
diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index 565edb8929..cab2d018bb 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -16,6 +16,7 @@ import {
isVisible,
isRTL,
noop,
+ getNextActiveElement,
typeCheckConfig
} from './util/index'
import Data from './dom/data'
@@ -354,28 +355,17 @@ class Dropdown extends BaseComponent {
}
_selectMenuItem(event) {
- const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)
-
- if (!items.length) {
+ if (![ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) {
return
}
- let index = items.indexOf(event.target)
-
- // Up
- if (event.key === ARROW_UP_KEY && index > 0) {
- index--
- }
+ const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)
- // Down
- if (event.key === ARROW_DOWN_KEY && index < items.length - 1) {
- index++
+ if (!items.length) {
+ return
}
- // index is -1 if the first keydown is an ArrowUp
- index = index === -1 ? 0 : index
-
- items[index].focus()
+ getNextActiveElement(items, event.target, event.key === ARROW_DOWN_KEY, false).focus()
}
// Static
diff --git a/js/src/util/index.js b/js/src/util/index.js
index 9441d0a44a..6b38a05e94 100644
--- a/js/src/util/index.js
+++ b/js/src/util/index.js
@@ -261,6 +261,34 @@ const execute = callback => {
}
}
+/**
+ * Return the previous/next element of a list.
+ *
+ * @param {array} list The list of elements
+ * @param activeElement The active element
+ * @param shouldGetNext Choose to get next or previous element
+ * @param isCycleAllowed
+ * @return {Element|elem} The proper element
+ */
+const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
+ let index = list.indexOf(activeElement)
+
+ // if the element does not exist in the list initialize it as the first element
+ if (index === -1) {
+ return list[0]
+ }
+
+ const listLength = list.length
+
+ index += shouldGetNext ? 1 : -1
+
+ if (isCycleAllowed) {
+ index = (index + listLength) % listLength
+ }
+
+ return list[Math.max(0, Math.min(index, listLength - 1))]
+}
+
export {
getElement,
getUID,
@@ -275,6 +303,7 @@ export {
isDisabled,
findShadowRoot,
noop,
+ getNextActiveElement,
reflow,
getjQuery,
onDOMContentLoaded,
diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js
index b4010e0e0e..ca6430bee5 100644
--- a/js/tests/unit/util/index.spec.js
+++ b/js/tests/unit/util/index.spec.js
@@ -611,4 +611,43 @@ describe('Util', () => {
expect(spy).toHaveBeenCalled()
})
})
+
+ describe('getNextActiveElement', () => {
+ it('should return first element if active not exists or not given', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, '', true, true)).toEqual('a')
+ expect(Util.getNextActiveElement(array, 'g', true, true)).toEqual('a')
+ })
+
+ it('should return next element or same if is last', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'a', true, true)).toEqual('b')
+ expect(Util.getNextActiveElement(array, 'b', true, true)).toEqual('c')
+ expect(Util.getNextActiveElement(array, 'd', true, false)).toEqual('d')
+ })
+
+ it('should return next element or first, if is last and "isCycleAllowed = true"', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'c', true, true)).toEqual('d')
+ expect(Util.getNextActiveElement(array, 'd', true, true)).toEqual('a')
+ })
+
+ it('should return previous element or same if is first', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'b', false, true)).toEqual('a')
+ expect(Util.getNextActiveElement(array, 'd', false, true)).toEqual('c')
+ expect(Util.getNextActiveElement(array, 'a', false, false)).toEqual('a')
+ })
+
+ it('should return next element or first, if is last and "isCycleAllowed = true"', () => {
+ const array = ['a', 'b', 'c', 'd']
+
+ expect(Util.getNextActiveElement(array, 'd', false, true)).toEqual('c')
+ expect(Util.getNextActiveElement(array, 'a', false, true)).toEqual('d')
+ })
+ })
})