%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/ugotscom/.trash/laravel/node_modules/bootstrap-vue/src/components/tabs/
Upload File :
Create Path :
Current File : /home/ugotscom/.trash/laravel/node_modules/bootstrap-vue/src/components/tabs/tabs.js

import Vue from '../../vue'
import { NAME_TABS, NAME_TAB_BUTTON_HELPER } from '../../constants/components'
import {
  CODE_DOWN,
  CODE_END,
  CODE_HOME,
  CODE_LEFT,
  CODE_RIGHT,
  CODE_SPACE,
  CODE_UP
} from '../../constants/key-codes'
import { SLOT_NAME_TITLE } from '../../constants/slot-names'
import { makePropsConfigurable } from '../../utils/config'
import identity from '../../utils/identity'
import looseEqual from '../../utils/loose-equal'
import observeDom from '../../utils/observe-dom'
import stableSort from '../../utils/stable-sort'
import { arrayIncludes, concat } from '../../utils/array'
import { BvEvent } from '../../utils/bv-event.class'
import { attemptFocus, requestAF, selectAll } from '../../utils/dom'
import { stopEvent } from '../../utils/events'
import { isEvent } from '../../utils/inspect'
import { mathMax } from '../../utils/math'
import { toInteger } from '../../utils/number'
import { omit } from '../../utils/object'
import idMixin from '../../mixins/id'
import normalizeSlotMixin from '../../mixins/normalize-slot'
import { BLink } from '../link/link'
import { BNav, props as BNavProps } from '../nav/nav'

// --- Constants ---

const navProps = omit(BNavProps, ['tabs', 'isNavBar', 'cardHeader'])

// --- Helper methods ---

// Filter function to filter out disabled tabs
const notDisabled = tab => !tab.disabled

// --- Helper components ---

// @vue/component
const BVTabButton = /*#__PURE__*/ Vue.extend({
  name: NAME_TAB_BUTTON_HELPER,
  inject: {
    bvTabs: {
      /* istanbul ignore next */
      default() {
        return {}
      }
    }
  },
  props: makePropsConfigurable(
    {
      // Reference to the child <b-tab> instance
      tab: { default: null },
      tabs: {
        type: Array,
        /* istanbul ignore next */
        default() {
          return []
        }
      },
      id: { type: String, default: null },
      controls: { type: String, default: null },
      tabIndex: { type: Number, default: null },
      posInSet: { type: Number, default: null },
      setSize: { type: Number, default: null },
      noKeyNav: { type: Boolean, default: false }
    },
    NAME_TABS
  ),
  methods: {
    focus() {
      attemptFocus(this.$refs.link)
    },
    handleEvt(evt) {
      if (this.tab.disabled) {
        /* istanbul ignore next */
        return
      }
      const { type, keyCode, shiftKey } = evt
      if (type === 'click') {
        stopEvent(evt)
        this.$emit('click', evt)
      } else if (type === 'keydown' && keyCode === CODE_SPACE) {
        // For ARIA tabs the SPACE key will also trigger a click/select
        // Even with keyboard navigation disabled, SPACE should "click" the button
        // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/4323
        stopEvent(evt)
        this.$emit('click', evt)
      } else if (type === 'keydown' && !this.noKeyNav) {
        // For keyboard navigation
        if ([CODE_UP, CODE_LEFT, CODE_HOME].indexOf(keyCode) !== -1) {
          stopEvent(evt)
          if (shiftKey || keyCode === CODE_HOME) {
            this.$emit('first', evt)
          } else {
            this.$emit('prev', evt)
          }
        } else if ([CODE_DOWN, CODE_RIGHT, CODE_END].indexOf(keyCode) !== -1) {
          stopEvent(evt)
          if (shiftKey || keyCode === CODE_END) {
            this.$emit('last', evt)
          } else {
            this.$emit('next', evt)
          }
        }
      }
    }
  },
  render(h) {
    const { id, tabIndex, setSize, posInSet, controls, handleEvt } = this
    const {
      title,
      localActive,
      disabled,
      titleItemClass,
      titleLinkClass,
      titleLinkAttributes
    } = this.tab

    const $link = h(
      BLink,
      {
        ref: 'link',
        staticClass: 'nav-link',
        class: [
          {
            active: localActive && !disabled,
            disabled
          },
          titleLinkClass,
          // Apply <b-tabs> `activeNavItemClass` styles when the tab is active
          localActive ? this.bvTabs.activeNavItemClass : null
        ],
        props: { disabled },
        attrs: {
          ...titleLinkAttributes,
          role: 'tab',
          id,
          // Roving tab index when keynav enabled
          tabindex: tabIndex,
          'aria-selected': localActive && !disabled ? 'true' : 'false',
          'aria-setsize': setSize,
          'aria-posinset': posInSet,
          'aria-controls': controls
        },
        on: {
          click: handleEvt,
          keydown: handleEvt
        }
      },
      [this.tab.normalizeSlot(SLOT_NAME_TITLE) || title]
    )

    return h(
      'li',
      {
        staticClass: 'nav-item',
        class: [titleItemClass],
        attrs: { role: 'presentation' }
      },
      [$link]
    )
  }
})

// @vue/component
export const BTabs = /*#__PURE__*/ Vue.extend({
  name: NAME_TABS,
  mixins: [idMixin, normalizeSlotMixin],
  provide() {
    return {
      bvTabs: this
    }
  },
  model: {
    prop: 'value',
    event: 'input'
  },
  props: {
    ...navProps,
    tag: {
      type: String,
      default: 'div'
    },
    card: {
      type: Boolean,
      default: false
    },
    end: {
      // Synonym for 'bottom'
      type: Boolean,
      default: false
    },
    noFade: {
      type: Boolean,
      default: false
    },
    noNavStyle: {
      type: Boolean,
      default: false
    },
    noKeyNav: {
      type: Boolean,
      default: false
    },
    lazy: {
      // This prop is sniffed by the <b-tab> child
      type: Boolean,
      default: false
    },
    contentClass: {
      type: [String, Array, Object]
      // default: null
    },
    navClass: {
      type: [String, Array, Object]
      // default: null
    },
    navWrapperClass: {
      type: [String, Array, Object]
      // default: null
    },
    activeNavItemClass: {
      // Only applied to the currently active <b-nav-item>
      type: [String, Array, Object]
      // default: null
    },
    activeTabClass: {
      // Only applied to the currently active <b-tab>
      // This prop is sniffed by the <b-tab> child
      type: [String, Array, Object]
      // default: null
    },
    value: {
      // v-model
      type: Number,
      default: null
    }
  },
  data() {
    return {
      // Index of current tab
      currentTab: toInteger(this.value, -1),
      // Array of direct child <b-tab> instances, in DOM order
      tabs: [],
      // Array of child instances registered (for triggering reactive updates)
      registeredTabs: [],
      // Flag to know if we are mounted or not
      isMounted: false
    }
  },
  computed: {
    fade() {
      // This computed prop is sniffed by the tab child
      return !this.noFade
    },
    localNavClass() {
      const classes = []
      if (this.card && this.vertical) {
        classes.push('card-header', 'h-100', 'border-bottom-0', 'rounded-0')
      }
      return [...classes, this.navClass]
    }
  },
  watch: {
    currentTab(newVal) {
      let index = -1
      // Ensure only one tab is active at most
      this.tabs.forEach((tab, idx) => {
        if (newVal === idx && !tab.disabled) {
          tab.localActive = true
          index = idx
        } else {
          tab.localActive = false
        }
      })
      // Update the v-model
      this.$emit('input', index)
    },
    value(newVal, oldVal) {
      if (newVal !== oldVal) {
        newVal = toInteger(newVal, -1)
        oldVal = toInteger(oldVal, 0)
        const tabs = this.tabs
        if (tabs[newVal] && !tabs[newVal].disabled) {
          this.activateTab(tabs[newVal])
        } else {
          // Try next or prev tabs
          if (newVal < oldVal) {
            this.previousTab()
          } else {
            this.nextTab()
          }
        }
      }
    },
    registeredTabs() {
      // Each b-tab will register/unregister itself.
      // We use this to detect when tabs are added/removed
      // to trigger the update of the tabs.
      this.$nextTick(() => {
        requestAF(() => {
          this.updateTabs()
        })
      })
    },
    tabs(newVal, oldVal) {
      // If tabs added, removed, or re-ordered, we emit a `changed` event.
      // We use `tab._uid` instead of `tab.safeId()`, as the later is changed
      // in a nextTick if no explicit ID is provided, causing duplicate emits.
      if (!looseEqual(newVal.map(t => t._uid), oldVal.map(t => t._uid))) {
        // In a nextTick to ensure currentTab has been set first.
        this.$nextTick(() => {
          // We emit shallow copies of the new and old arrays of tabs, to
          // prevent users from potentially mutating the internal arrays.
          this.$emit('changed', newVal.slice(), oldVal.slice())
        })
      }
    },
    isMounted(newVal) {
      // Trigger an update after mounted.  Needed for tabs inside lazy modals.
      if (newVal) {
        requestAF(() => {
          this.updateTabs()
        })
      }
      // Enable or disable the observer
      this.setObserver(newVal)
    }
  },
  created() {
    // Create private non-reactive props
    this.$_observer = null
    this.currentTab = toInteger(this.value, -1)
    // For SSR and to make sure only a single tab is shown on mount
    // We wrap this in a `$nextTick()` to ensure the child tabs have been created
    this.$nextTick(() => {
      this.updateTabs()
    })
  },
  mounted() {
    // Call `updateTabs()` just in case...
    this.updateTabs()
    this.$nextTick(() => {
      // Flag we are now mounted and to switch to DOM for tab probing.
      // As this.$slots.default appears to lie about component instances
      // after b-tabs is destroyed and re-instantiated.
      // And this.$children does not respect DOM order.
      this.isMounted = true
    })
  },
  /* istanbul ignore next */
  deactivated() {
    this.isMounted = false
  },
  /* istanbul ignore next */
  activated() {
    this.currentTab = toInteger(this.value, -1)
    this.$nextTick(() => {
      this.updateTabs()
      this.isMounted = true
    })
  },
  beforeDestroy() {
    this.isMounted = false
  },
  destroyed() {
    // Ensure no references to child instances exist
    this.tabs = []
  },
  methods: {
    registerTab(tab) {
      if (!arrayIncludes(this.registeredTabs, tab)) {
        this.registeredTabs.push(tab)
        tab.$once('hook:destroyed', () => {
          this.unregisterTab(tab)
        })
      }
    },
    unregisterTab(tab) {
      this.registeredTabs = this.registeredTabs.slice().filter(t => t !== tab)
    },
    // DOM observer is needed to detect changes in order of tabs
    setObserver(on) {
      this.$_observer && this.$_observer.disconnect()
      this.$_observer = null
      if (on) {
        const self = this
        /* istanbul ignore next: difficult to test mutation observer in JSDOM */
        const handler = () => {
          // We delay the update to ensure that `tab.safeId()` has
          // updated with the final ID value.
          self.$nextTick(() => {
            requestAF(() => {
              self.updateTabs()
            })
          })
        }
        // Watch for changes to <b-tab> sub components
        this.$_observer = observeDom(this.$refs.tabsContainer, handler, {
          childList: true,
          subtree: false,
          attributes: true,
          attributeFilter: ['id']
        })
      }
    },
    getTabs() {
      // We use `registeredTabs` as the source of truth for child tab components
      // We also filter out any `<b-tab>` components that are extended
      // `<b-tab>` with a root child `<b-tab>`
      // See: https://github.com/bootstrap-vue/bootstrap-vue/issues/3260
      const tabs = this.registeredTabs.filter(
        tab => tab.$children.filter(t => t._isTab).length === 0
      )
      // DOM Order of Tabs
      let order = []
      if (this.isMounted && tabs.length > 0) {
        // We rely on the DOM when mounted to get the 'true' order of the `<b-tab>` children
        // `querySelectorAll()` always returns elements in document order, regardless of
        // order specified in the selector
        const selector = tabs.map(tab => `#${tab.safeId()}`).join(', ')
        order = selectAll(selector, this.$el)
          .map(el => el.id)
          .filter(identity)
      }
      // Stable sort keeps the original order if not found in the `order` array,
      // which will be an empty array before mount
      return stableSort(tabs, (a, b) => order.indexOf(a.safeId()) - order.indexOf(b.safeId()))
    },
    // Update list of `<b-tab>` children
    updateTabs() {
      // Probe tabs
      const tabs = this.getTabs()

      // Find *last* active non-disabled tab in current tabs
      // We trust tab state over `currentTab`, in case tabs were added/removed/re-ordered
      let tabIndex = tabs.indexOf(
        tabs
          .slice()
          .reverse()
          .find(tab => tab.localActive && !tab.disabled)
      )

      // Else try setting to `currentTab`
      if (tabIndex < 0) {
        const currentTab = this.currentTab
        if (currentTab >= tabs.length) {
          // Handle last tab being removed, so find the last non-disabled tab
          tabIndex = tabs.indexOf(
            tabs
              .slice()
              .reverse()
              .find(notDisabled)
          )
        } else if (tabs[currentTab] && !tabs[currentTab].disabled) {
          // Current tab is not disabled
          tabIndex = currentTab
        }
      }

      // Else find *first* non-disabled tab in current tabs
      if (tabIndex < 0) {
        tabIndex = tabs.indexOf(tabs.find(notDisabled))
      }

      // Set the current tab state to active
      tabs.forEach(tab => {
        // tab.localActive = idx === tabIndex && !tab.disabled
        tab.localActive = false
      })
      if (tabs[tabIndex]) {
        tabs[tabIndex].localActive = true
      }

      // Update the array of tab children
      this.tabs = tabs
      // Set the currentTab index (can be -1 if no non-disabled tabs)
      this.currentTab = tabIndex
    },
    // Find a button that controls a tab, given the tab reference
    // Returns the button vm instance
    getButtonForTab(tab) {
      return (this.$refs.buttons || []).find(btn => btn.tab === tab)
    },
    // Force a button to re-render its content, given a <b-tab> instance
    // Called by <b-tab> on `update()`
    updateButton(tab) {
      const button = this.getButtonForTab(tab)
      if (button && button.$forceUpdate) {
        button.$forceUpdate()
      }
    },
    // Activate a tab given a `<b-tab>` instance
    // Also accessed by `<b-tab>`
    activateTab(tab) {
      let result = false
      if (tab) {
        const index = this.tabs.indexOf(tab)
        if (!tab.disabled && index > -1 && index !== this.currentTab) {
          const tabEvt = new BvEvent('activate-tab', {
            cancelable: true,
            vueTarget: this,
            componentId: this.safeId()
          })
          this.$emit(tabEvt.type, index, this.currentTab, tabEvt)
          if (!tabEvt.defaultPrevented) {
            result = true
            this.currentTab = index
          }
        }
      }
      // Couldn't set tab, so ensure v-model is set to `this.currentTab`
      /* istanbul ignore next: should rarely happen */
      if (!result && this.currentTab !== this.value) {
        this.$emit('input', this.currentTab)
      }
      return result
    },
    // Deactivate a tab given a <b-tab> instance
    // Accessed by <b-tab>
    deactivateTab(tab) {
      if (tab) {
        // Find first non-disabled tab that isn't the one being deactivated
        // If no tabs are available, then don't deactivate current tab
        return this.activateTab(this.tabs.filter(t => t !== tab).find(notDisabled))
      }
      /* istanbul ignore next: should never/rarely happen */
      return false
    },
    // Focus a tab button given its <b-tab> instance
    focusButton(tab) {
      // Wrap in `$nextTick()` to ensure DOM has completed rendering/updating before focusing
      this.$nextTick(() => {
        attemptFocus(this.getButtonForTab(tab))
      })
    },
    // Emit a click event on a specified <b-tab> component instance
    emitTabClick(tab, evt) {
      if (isEvent(evt) && tab && tab.$emit && !tab.disabled) {
        tab.$emit('click', evt)
      }
    },
    // Click handler
    clickTab(tab, evt) {
      this.activateTab(tab)
      this.emitTabClick(tab, evt)
    },
    // Move to first non-disabled tab
    firstTab(focus) {
      const tab = this.tabs.find(notDisabled)
      if (this.activateTab(tab) && focus) {
        this.focusButton(tab)
        this.emitTabClick(tab, focus)
      }
    },
    // Move to previous non-disabled tab
    previousTab(focus) {
      const currentIndex = mathMax(this.currentTab, 0)
      const tab = this.tabs
        .slice(0, currentIndex)
        .reverse()
        .find(notDisabled)
      if (this.activateTab(tab) && focus) {
        this.focusButton(tab)
        this.emitTabClick(tab, focus)
      }
    },
    // Move to next non-disabled tab
    nextTab(focus) {
      const currentIndex = mathMax(this.currentTab, -1)
      const tab = this.tabs.slice(currentIndex + 1).find(notDisabled)
      if (this.activateTab(tab) && focus) {
        this.focusButton(tab)
        this.emitTabClick(tab, focus)
      }
    },
    // Move to last non-disabled tab
    lastTab(focus) {
      const tab = this.tabs
        .slice()
        .reverse()
        .find(notDisabled)
      if (this.activateTab(tab) && focus) {
        this.focusButton(tab)
        this.emitTabClick(tab, focus)
      }
    }
  },
  render(h) {
    const { tabs, noKeyNav, firstTab, previousTab, nextTab, lastTab } = this

    // Currently active tab
    const activeTab = tabs.find(tab => tab.localActive && !tab.disabled)

    // Tab button to allow focusing when no active tab found (keynav only)
    const fallbackTab = tabs.find(tab => !tab.disabled)

    // For each `<b-tab>` found create the tab buttons
    const buttons = tabs.map((tab, index) => {
      let tabIndex = null
      // Ensure at least one tab button is focusable when keynav enabled (if possible)
      if (!noKeyNav) {
        // Buttons are not in tab index unless active, or a fallback tab
        tabIndex = -1
        if (activeTab === tab || (!activeTab && fallbackTab === tab)) {
          // Place tab button in tab sequence
          tabIndex = null
        }
      }
      return h(BVTabButton, {
        key: tab._uid || index,
        ref: 'buttons',
        // Needed to make `this.$refs.buttons` an array
        refInFor: true,
        props: {
          tab,
          tabs,
          id: tab.controlledBy || (tab.safeId ? tab.safeId(`_BV_tab_button_`) : null),
          controls: tab.safeId ? tab.safeId() : null,
          tabIndex,
          setSize: tabs.length,
          posInSet: index + 1,
          noKeyNav
        },
        on: {
          click: evt => {
            this.clickTab(tab, evt)
          },
          first: firstTab,
          prev: previousTab,
          next: nextTab,
          last: lastTab
        }
      })
    })

    // Nav
    let nav = h(
      BNav,
      {
        ref: 'nav',
        class: this.localNavClass,
        attrs: {
          role: 'tablist',
          id: this.safeId('_BV_tab_controls_')
        },
        props: {
          fill: this.fill,
          justified: this.justified,
          align: this.align,
          tabs: !this.noNavStyle && !this.pills,
          pills: !this.noNavStyle && this.pills,
          vertical: this.vertical,
          small: this.small,
          cardHeader: this.card && !this.vertical
        }
      },
      [this.normalizeSlot('tabs-start') || h(), buttons, this.normalizeSlot('tabs-end') || h()]
    )
    nav = h(
      'div',
      {
        key: 'bv-tabs-nav',
        class: [
          {
            'card-header': this.card && !this.vertical && !this.end,
            'card-footer': this.card && !this.vertical && this.end,
            'col-auto': this.vertical
          },
          this.navWrapperClass
        ]
      },
      [nav]
    )

    let empty = h()
    if (!tabs || tabs.length === 0) {
      empty = h(
        'div',
        { key: 'bv-empty-tab', class: ['tab-pane', 'active', { 'card-body': this.card }] },
        this.normalizeSlot('empty')
      )
    }

    // Main content section
    const content = h(
      'div',
      {
        ref: 'tabsContainer',
        key: 'bv-tabs-container',
        staticClass: 'tab-content',
        class: [{ col: this.vertical }, this.contentClass],
        attrs: { id: this.safeId('_BV_tab_container_') }
      },
      concat(this.normalizeSlot(), empty)
    )

    // Render final output
    return h(
      this.tag,
      {
        staticClass: 'tabs',
        class: {
          row: this.vertical,
          'no-gutters': this.vertical && this.card
        },
        attrs: { id: this.safeId() }
      },
      [this.end ? content : h(), [nav], this.end ? h() : content]
    )
  }
})

Zerion Mini Shell 1.0