Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F100947777
tab.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Feb 4, 05:24
Size
8 KB
Mime Type
text/x-c++
Expires
Thu, Feb 6, 05:24 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
24061908
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
tab.js
View Options
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.2.3): tab.js
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* --------------------------------------------------------------------------
*/
import
{
defineJQueryPlugin
,
getElementFromSelector
,
getNextActiveElement
,
isDisabled
}
from
'./util/index'
import
EventHandler
from
'./dom/event-handler'
import
SelectorEngine
from
'./dom/selector-engine'
import
BaseComponent
from
'./base-component'
/**
* Constants
*/
const
NAME
=
'tab'
const
DATA_KEY
=
'bs.tab'
const
EVENT_KEY
=
`
.
$
{
DATA_KEY
}
`
const
EVENT_HIDE
=
`
hide$
{
EVENT_KEY
}
`
const
EVENT_HIDDEN
=
`
hidden$
{
EVENT_KEY
}
`
const
EVENT_SHOW
=
`
show$
{
EVENT_KEY
}
`
const
EVENT_SHOWN
=
`
shown$
{
EVENT_KEY
}
`
const
EVENT_CLICK_DATA_API
=
`
click$
{
EVENT_KEY
}
`
const
EVENT_KEYDOWN
=
`
keydown$
{
EVENT_KEY
}
`
const
EVENT_LOAD_DATA_API
=
`
load$
{
EVENT_KEY
}
`
const
ARROW_LEFT_KEY
=
'ArrowLeft'
const
ARROW_RIGHT_KEY
=
'ArrowRight'
const
ARROW_UP_KEY
=
'ArrowUp'
const
ARROW_DOWN_KEY
=
'ArrowDown'
const
CLASS_NAME_ACTIVE
=
'active'
const
CLASS_NAME_FADE
=
'fade'
const
CLASS_NAME_SHOW
=
'show'
const
CLASS_DROPDOWN
=
'dropdown'
const
SELECTOR_DROPDOWN_TOGGLE
=
'.dropdown-toggle'
const
SELECTOR_DROPDOWN_MENU
=
'.dropdown-menu'
const
NOT_SELECTOR_DROPDOWN_TOGGLE
=
':not(.dropdown-toggle)'
const
SELECTOR_TAB_PANEL
=
'.list-group, .nav, [role="tablist"]'
const
SELECTOR_OUTER
=
'.nav-item, .list-group-item'
const
SELECTOR_INNER
=
`
.
nav
-
link$
{
NOT_SELECTOR_DROPDOWN_TOGGLE
},
.
list
-
group
-
item$
{
NOT_SELECTOR_DROPDOWN_TOGGLE
},
[
role
=
"tab"
]
$
{
NOT_SELECTOR_DROPDOWN_TOGGLE
}
`
const
SELECTOR_DATA_TOGGLE
=
'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'
// todo:v6: could be only `tab`
const
SELECTOR_INNER_ELEM
=
`
$
{
SELECTOR_INNER
},
$
{
SELECTOR_DATA_TOGGLE
}
`
const
SELECTOR_DATA_TOGGLE_ACTIVE
=
`
.
$
{
CLASS_NAME_ACTIVE
}[
data
-
bs
-
toggle
=
"tab"
],
.
$
{
CLASS_NAME_ACTIVE
}[
data
-
bs
-
toggle
=
"pill"
],
.
$
{
CLASS_NAME_ACTIVE
}[
data
-
bs
-
toggle
=
"list"
]
`
/**
* Class definition
*/
class
Tab
extends
BaseComponent
{
constructor
(
element
)
{
super
(
element
)
this
.
_parent
=
this
.
_element
.
closest
(
SELECTOR_TAB_PANEL
)
if
(
!
this
.
_parent
)
{
return
// todo: should Throw exception on v6
// throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
}
// Set up initial aria attributes
this
.
_setInitialAttributes
(
this
.
_parent
,
this
.
_getChildren
())
EventHandler
.
on
(
this
.
_element
,
EVENT_KEYDOWN
,
event
=>
this
.
_keydown
(
event
))
}
// Getters
static
get
NAME
()
{
return
NAME
}
// Public
show
()
{
// Shows this elem and deactivate the active sibling if exists
const
innerElem
=
this
.
_element
if
(
this
.
_elemIsActive
(
innerElem
))
{
return
}
// Search for active tab on same parent to deactivate it
const
active
=
this
.
_getActiveElem
()
const
hideEvent
=
active
?
EventHandler
.
trigger
(
active
,
EVENT_HIDE
,
{
relatedTarget
:
innerElem
})
:
null
const
showEvent
=
EventHandler
.
trigger
(
innerElem
,
EVENT_SHOW
,
{
relatedTarget
:
active
})
if
(
showEvent
.
defaultPrevented
||
(
hideEvent
&&
hideEvent
.
defaultPrevented
))
{
return
}
this
.
_deactivate
(
active
,
innerElem
)
this
.
_activate
(
innerElem
,
active
)
}
// Private
_activate
(
element
,
relatedElem
)
{
if
(
!
element
)
{
return
}
element
.
classList
.
add
(
CLASS_NAME_ACTIVE
)
this
.
_activate
(
getElementFromSelector
(
element
))
// Search and activate/show the proper section
const
complete
=
()
=>
{
if
(
element
.
getAttribute
(
'role'
)
!==
'tab'
)
{
element
.
classList
.
add
(
CLASS_NAME_SHOW
)
return
}
element
.
removeAttribute
(
'tabindex'
)
element
.
setAttribute
(
'aria-selected'
,
true
)
this
.
_toggleDropDown
(
element
,
true
)
EventHandler
.
trigger
(
element
,
EVENT_SHOWN
,
{
relatedTarget
:
relatedElem
})
}
this
.
_queueCallback
(
complete
,
element
,
element
.
classList
.
contains
(
CLASS_NAME_FADE
))
}
_deactivate
(
element
,
relatedElem
)
{
if
(
!
element
)
{
return
}
element
.
classList
.
remove
(
CLASS_NAME_ACTIVE
)
element
.
blur
()
this
.
_deactivate
(
getElementFromSelector
(
element
))
// Search and deactivate the shown section too
const
complete
=
()
=>
{
if
(
element
.
getAttribute
(
'role'
)
!==
'tab'
)
{
element
.
classList
.
remove
(
CLASS_NAME_SHOW
)
return
}
element
.
setAttribute
(
'aria-selected'
,
false
)
element
.
setAttribute
(
'tabindex'
,
'-1'
)
this
.
_toggleDropDown
(
element
,
false
)
EventHandler
.
trigger
(
element
,
EVENT_HIDDEN
,
{
relatedTarget
:
relatedElem
})
}
this
.
_queueCallback
(
complete
,
element
,
element
.
classList
.
contains
(
CLASS_NAME_FADE
))
}
_keydown
(
event
)
{
if
(
!
([
ARROW_LEFT_KEY
,
ARROW_RIGHT_KEY
,
ARROW_UP_KEY
,
ARROW_DOWN_KEY
].
includes
(
event
.
key
)))
{
return
}
event
.
stopPropagation
()
// stopPropagation/preventDefault both added to support up/down keys without scrolling the page
event
.
preventDefault
()
const
isNext
=
[
ARROW_RIGHT_KEY
,
ARROW_DOWN_KEY
].
includes
(
event
.
key
)
const
nextActiveElement
=
getNextActiveElement
(
this
.
_getChildren
().
filter
(
element
=>
!
isDisabled
(
element
)),
event
.
target
,
isNext
,
true
)
if
(
nextActiveElement
)
{
nextActiveElement
.
focus
({
preventScroll
:
true
})
Tab
.
getOrCreateInstance
(
nextActiveElement
).
show
()
}
}
_getChildren
()
{
// collection of inner elements
return
SelectorEngine
.
find
(
SELECTOR_INNER_ELEM
,
this
.
_parent
)
}
_getActiveElem
()
{
return
this
.
_getChildren
().
find
(
child
=>
this
.
_elemIsActive
(
child
))
||
null
}
_setInitialAttributes
(
parent
,
children
)
{
this
.
_setAttributeIfNotExists
(
parent
,
'role'
,
'tablist'
)
for
(
const
child
of
children
)
{
this
.
_setInitialAttributesOnChild
(
child
)
}
}
_setInitialAttributesOnChild
(
child
)
{
child
=
this
.
_getInnerElement
(
child
)
const
isActive
=
this
.
_elemIsActive
(
child
)
const
outerElem
=
this
.
_getOuterElement
(
child
)
child
.
setAttribute
(
'aria-selected'
,
isActive
)
if
(
outerElem
!==
child
)
{
this
.
_setAttributeIfNotExists
(
outerElem
,
'role'
,
'presentation'
)
}
if
(
!
isActive
)
{
child
.
setAttribute
(
'tabindex'
,
'-1'
)
}
this
.
_setAttributeIfNotExists
(
child
,
'role'
,
'tab'
)
// set attributes to the related panel too
this
.
_setInitialAttributesOnTargetPanel
(
child
)
}
_setInitialAttributesOnTargetPanel
(
child
)
{
const
target
=
getElementFromSelector
(
child
)
if
(
!
target
)
{
return
}
this
.
_setAttributeIfNotExists
(
target
,
'role'
,
'tabpanel'
)
if
(
child
.
id
)
{
this
.
_setAttributeIfNotExists
(
target
,
'aria-labelledby'
,
`#
$
{
child
.
id
}
`
)
}
}
_toggleDropDown
(
element
,
open
)
{
const
outerElem
=
this
.
_getOuterElement
(
element
)
if
(
!
outerElem
.
classList
.
contains
(
CLASS_DROPDOWN
))
{
return
}
const
toggle
=
(
selector
,
className
)
=>
{
const
element
=
SelectorEngine
.
findOne
(
selector
,
outerElem
)
if
(
element
)
{
element
.
classList
.
toggle
(
className
,
open
)
}
}
toggle
(
SELECTOR_DROPDOWN_TOGGLE
,
CLASS_NAME_ACTIVE
)
toggle
(
SELECTOR_DROPDOWN_MENU
,
CLASS_NAME_SHOW
)
outerElem
.
setAttribute
(
'aria-expanded'
,
open
)
}
_setAttributeIfNotExists
(
element
,
attribute
,
value
)
{
if
(
!
element
.
hasAttribute
(
attribute
))
{
element
.
setAttribute
(
attribute
,
value
)
}
}
_elemIsActive
(
elem
)
{
return
elem
.
classList
.
contains
(
CLASS_NAME_ACTIVE
)
}
// Try to get the inner element (usually the .nav-link)
_getInnerElement
(
elem
)
{
return
elem
.
matches
(
SELECTOR_INNER_ELEM
)
?
elem
:
SelectorEngine
.
findOne
(
SELECTOR_INNER_ELEM
,
elem
)
}
// Try to get the outer element (usually the .nav-item)
_getOuterElement
(
elem
)
{
return
elem
.
closest
(
SELECTOR_OUTER
)
||
elem
}
// Static
static
jQueryInterface
(
config
)
{
return
this
.
each
(
function
()
{
const
data
=
Tab
.
getOrCreateInstance
(
this
)
if
(
typeof
config
!==
'string'
)
{
return
}
if
(
data
[
config
]
===
undefined
||
config
.
startsWith
(
'_'
)
||
config
===
'constructor'
)
{
throw
new
TypeError
(
`
No
method
named
"${config}"
`
)
}
data
[
config
]()
})
}
}
/**
* Data API implementation
*/
EventHandler
.
on
(
document
,
EVENT_CLICK_DATA_API
,
SELECTOR_DATA_TOGGLE
,
function
(
event
)
{
if
([
'A'
,
'AREA'
].
includes
(
this
.
tagName
))
{
event
.
preventDefault
()
}
if
(
isDisabled
(
this
))
{
return
}
Tab
.
getOrCreateInstance
(
this
).
show
()
})
/**
* Initialize on focus
*/
EventHandler
.
on
(
window
,
EVENT_LOAD_DATA_API
,
()
=>
{
for
(
const
element
of
SelectorEngine
.
find
(
SELECTOR_DATA_TOGGLE_ACTIVE
))
{
Tab
.
getOrCreateInstance
(
element
)
}
})
/**
* jQuery
*/
defineJQueryPlugin
(
Tab
)
export
default
Tab
Event Timeline
Log In to Comment