@@ -33,7 +33,7 @@ import {
33
33
} from '../../constants/slots'
34
34
import { arrayIncludes } from '../../utils/array'
35
35
import { BvEvent } from '../../utils/bv-event.class'
36
-
import { attemptFocus, selectAll } from '../../utils/dom'
36
+
import { attemptFocus, selectAll, requestAF } from '../../utils/dom'
37
37
import { stopEvent } from '../../utils/events'
38
38
import { identity } from '../../utils/identity'
39
39
import { isEvent } from '../../utils/inspect'
@@ -280,14 +280,14 @@ export const BTabs = /*#__PURE__*/ Vue.extend({
280
280
// Update the v-model
281
281
this.$emit(MODEL_EVENT_NAME, index)
282
282
},
283
+
// If tabs added, removed, or re-ordered, we emit a `changed` event
283
284
tabs(newValue, oldValue) {
284
-
// If tabs added, removed, or re-ordered, we emit a `changed` event
285
-
// We use `tab._uid` instead of `tab.safeId()`, as the later is changed
286
-
// in a `$nextTick()` if no explicit ID is provided, causing duplicate emits
285
+
// We use `_uid` instead of `safeId()`, as the later is changed in a `$nextTick()`
286
+
// if no explicit ID is provided, causing duplicate emits
287
287
if (
288
288
!looseEqual(
289
-
newValue.map(t => t[COMPONENT_UID_KEY]),
290
-
oldValue.map(t => t[COMPONENT_UID_KEY])
289
+
newValue.map($tab => $tab[COMPONENT_UID_KEY]),
290
+
oldValue.map($tab => $tab[COMPONENT_UID_KEY])
291
291
)
292
292
) {
293
293
// In a `$nextTick()` to ensure `currentTab` has been set first
@@ -298,6 +298,9 @@ export const BTabs = /*#__PURE__*/ Vue.extend({
298
298
})
299
299
}
300
300
},
301
+
// Each `<b-tab>` will register/unregister itself
302
+
// We use this to detect when tabs are added/removed
303
+
// to trigger the update of the tabs
301
304
registeredTabs() {
302
305
this.updateTabs()
303
306
}
@@ -332,7 +335,9 @@ export const BTabs = /*#__PURE__*/ Vue.extend({
332
335
/* istanbul ignore next: difficult to test mutation observer in JSDOM */
333
336
const handler = () => {
334
337
this.$nextTick(() => {
335
-
this.updateTabs()
338
+
requestAF(() => {
339
+
this.updateTabs()
340
+
})
336
341
})
337
342
}
338
343
@@ -352,8 +357,9 @@ export const BTabs = /*#__PURE__*/ Vue.extend({
352
357
353
358
// DOM Order of Tabs
354
359
let order = []
360
+
/* istanbul ignore next: too difficult to test */
355
361
if (IS_BROWSER && $tabs.length > 0) {
356
-
// We rely on the DOM when mounted to get the 'true' order of the `<b-tab>` children
362
+
// We rely on the DOM when mounted to get the "true" order of the `<b-tab>` children
357
363
// `querySelectorAll()` always returns elements in document order, regardless of
358
364
// order specified in the selector
359
365
const selector = $tabs.map($tab => `#${$tab.safeId()}`).join(', ')
@@ -369,29 +375,44 @@ export const BTabs = /*#__PURE__*/ Vue.extend({
369
375
updateTabs() {
370
376
const $tabs = this.getTabs()
371
377
372
-
// Normalize `currentTab`
373
-
let { currentTab } = this
374
-
const $tab = $tabs[currentTab]
375
-
if (!$tab || $tab.disabled) {
376
-
currentTab = $tabs.indexOf(
377
-
$tabs
378
-
.slice()
379
-
.reverse()
380
-
.find($tab => $tab.localActive && !$tab.disabled)
381
-
)
378
+
// Find last active non-disabled tab in current tabs
379
+
// We trust tab state over `currentTab`, in case tabs were added/removed/re-ordered
380
+
let tabIndex = $tabs.indexOf(
381
+
$tabs
382
+
.slice()
383
+
.reverse()
384
+
.find($tab => $tab.localActive && !$tab.disabled)
385
+
)
382
386
383
-
if (currentTab === -1) {
384
-
currentTab = $tabs.indexOf($tabs.find(notDisabled))
387
+
// Else try setting to `currentTab`
388
+
if (tabIndex < 0) {
389
+
const { currentTab } = this
390
+
if (currentTab >= $tabs.length) {
391
+
// Handle last tab being removed, so find the last non-disabled tab
392
+
tabIndex = $tabs.indexOf(
393
+
$tabs
394
+
.slice()
395
+
.reverse()
396
+
.find(notDisabled)
397
+
)
398
+
} else if ($tabs[currentTab] && !$tabs[currentTab].disabled) {
399
+
// Current tab is not disabled
400
+
tabIndex = currentTab
385
401
}
386
402
}
387
403
404
+
// Else find first non-disabled tab in current tabs
405
+
if (tabIndex < 0) {
406
+
tabIndex = $tabs.indexOf($tabs.find(notDisabled))
407
+
}
408
+
388
409
// Ensure only one tab is active at a time
389
410
$tabs.forEach(($tab, index) => {
390
-
$tab.localActive = index === currentTab
411
+
$tab.localActive = index === tabIndex
391
412
})
392
413
393
414
this.tabs = $tabs
394
-
this.currentTab = currentTab
415
+
this.currentTab = tabIndex
395
416
},
396
417
// Find a button that controls a tab, given the tab reference
397
418
// Returns the button vm instance
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4