Skip to content

Commit df72a21

Browse files
authored
Add getNextActiveElement helper function to utils, replacing custom implementation through components (#33608)
1 parent 372890b commit df72a21

File tree

4 files changed

+76
-31
lines changed

4 files changed

+76
-31
lines changed

js/src/carousel.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
getElementFromSelector,
1111
isRTL,
1212
isVisible,
13+
getNextActiveElement,
1314
reflow,
1415
triggerTransitionEnd,
1516
typeCheckConfig
@@ -337,21 +338,7 @@ class Carousel extends BaseComponent {
337338

338339
_getItemByOrder(order, activeElement) {
339340
const isNext = order === ORDER_NEXT
340-
const isPrev = order === ORDER_PREV
341-
const activeIndex = this._getItemIndex(activeElement)
342-
const lastItemIndex = this._items.length - 1
343-
const isGoingToWrap = (isPrev && activeIndex === 0) || (isNext && activeIndex === lastItemIndex)
344-
345-
if (isGoingToWrap && !this._config.wrap) {
346-
return activeElement
347-
}
348-
349-
const delta = isPrev ? -1 : 1
350-
const itemIndex = (activeIndex + delta) % this._items.length
351-
352-
return itemIndex === -1 ?
353-
this._items[this._items.length - 1] :
354-
this._items[itemIndex]
341+
return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap)
355342
}
356343

357344
_triggerSlideEvent(relatedTarget, eventDirectionName) {

js/src/dropdown.js

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
isVisible,
1717
isRTL,
1818
noop,
19+
getNextActiveElement,
1920
typeCheckConfig
2021
} from './util/index'
2122
import Data from './dom/data'
@@ -354,28 +355,17 @@ class Dropdown extends BaseComponent {
354355
}
355356

356357
_selectMenuItem(event) {
357-
const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)
358-
359-
if (!items.length) {
358+
if (![ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) {
360359
return
361360
}
362361

363-
let index = items.indexOf(event.target)
364-
365-
// Up
366-
if (event.key === ARROW_UP_KEY && index > 0) {
367-
index--
368-
}
362+
const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)
369363

370-
// Down
371-
if (event.key === ARROW_DOWN_KEY && index < items.length - 1) {
372-
index++
364+
if (!items.length) {
365+
return
373366
}
374367

375-
// index is -1 if the first keydown is an ArrowUp
376-
index = index === -1 ? 0 : index
377-
378-
items[index].focus()
368+
getNextActiveElement(items, event.target, event.key === ARROW_DOWN_KEY, false).focus()
379369
}
380370

381371
// Static

js/src/util/index.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,34 @@ const execute = callback => {
261261
}
262262
}
263263

264+
/**
265+
* Return the previous/next element of a list.
266+
*
267+
* @param {array} list The list of elements
268+
* @param activeElement The active element
269+
* @param shouldGetNext Choose to get next or previous element
270+
* @param isCycleAllowed
271+
* @return {Element|elem} The proper element
272+
*/
273+
const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
274+
let index = list.indexOf(activeElement)
275+
276+
// if the element does not exist in the list initialize it as the first element
277+
if (index === -1) {
278+
return list[0]
279+
}
280+
281+
const listLength = list.length
282+
283+
index += shouldGetNext ? 1 : -1
284+
285+
if (isCycleAllowed) {
286+
index = (index + listLength) % listLength
287+
}
288+
289+
return list[Math.max(0, Math.min(index, listLength - 1))]
290+
}
291+
264292
export {
265293
getElement,
266294
getUID,
@@ -275,6 +303,7 @@ export {
275303
isDisabled,
276304
findShadowRoot,
277305
noop,
306+
getNextActiveElement,
278307
reflow,
279308
getjQuery,
280309
onDOMContentLoaded,

js/tests/unit/util/index.spec.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,4 +611,43 @@ describe('Util', () => {
611611
expect(spy).toHaveBeenCalled()
612612
})
613613
})
614+
615+
describe('getNextActiveElement', () => {
616+
it('should return first element if active not exists or not given', () => {
617+
const array = ['a', 'b', 'c', 'd']
618+
619+
expect(Util.getNextActiveElement(array, '', true, true)).toEqual('a')
620+
expect(Util.getNextActiveElement(array, 'g', true, true)).toEqual('a')
621+
})
622+
623+
it('should return next element or same if is last', () => {
624+
const array = ['a', 'b', 'c', 'd']
625+
626+
expect(Util.getNextActiveElement(array, 'a', true, true)).toEqual('b')
627+
expect(Util.getNextActiveElement(array, 'b', true, true)).toEqual('c')
628+
expect(Util.getNextActiveElement(array, 'd', true, false)).toEqual('d')
629+
})
630+
631+
it('should return next element or first, if is last and "isCycleAllowed = true"', () => {
632+
const array = ['a', 'b', 'c', 'd']
633+
634+
expect(Util.getNextActiveElement(array, 'c', true, true)).toEqual('d')
635+
expect(Util.getNextActiveElement(array, 'd', true, true)).toEqual('a')
636+
})
637+
638+
it('should return previous element or same if is first', () => {
639+
const array = ['a', 'b', 'c', 'd']
640+
641+
expect(Util.getNextActiveElement(array, 'b', false, true)).toEqual('a')
642+
expect(Util.getNextActiveElement(array, 'd', false, true)).toEqual('c')
643+
expect(Util.getNextActiveElement(array, 'a', false, false)).toEqual('a')
644+
})
645+
646+
it('should return next element or first, if is last and "isCycleAllowed = true"', () => {
647+
const array = ['a', 'b', 'c', 'd']
648+
649+
expect(Util.getNextActiveElement(array, 'd', false, true)).toEqual('c')
650+
expect(Util.getNextActiveElement(array, 'a', false, true)).toEqual('d')
651+
})
652+
})
614653
})

0 commit comments

Comments
 (0)