Skip to content
GitLab
Explore
Projects
Groups
Snippets
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Bootstrap
bootstrap
Commits
7f08061e
Commit
7f08061e
authored
7 years ago
by
Alessandro Chitolina
Committed by
XhmikosR
6 years ago
Browse files
Options
Download
Email Patches
Plain Diff
rewritten tab without jquery
parent
90261b48
5 merge requests
!31948
Examples/Floating-labels: fix bad behavior with autofill
,
!30064
test
,
!29779
Responsive sizing
,
!28882
fix custom-select-indicator in IE10
,
!28721
Hot test
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
js/src/dom/selectorEngine.js
+69
-13
js/src/dom/selectorEngine.js
js/src/tab.js
+56
-62
js/src/tab.js
js/tests/unit/tab.js
+9
-6
js/tests/unit/tab.js
js/tests/visual/tab.html
+3
-0
js/tests/visual/tab.html
with
137 additions
and
81 deletions
+137
-81
js/src/dom/selectorEngine.js
+
69
-
13
View file @
7f08061e
import
Util
from
'
../util
'
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-beta): dom/selectorEngine.js
...
...
@@ -27,17 +29,13 @@ const SelectorEngine = (() => {
if
(
!
Element
.
prototype
.
closest
)
{
fnClosest
=
(
element
,
selector
)
=>
{
let
ancestor
=
element
if
(
!
document
.
documentElement
.
contains
(
element
))
{
return
null
}
do
{
if
(
fnMatches
.
call
(
ancestor
,
selector
))
{
return
ancestor
}
ancestor
=
ancestor
.
parentElement
}
while
(
ancestor
!==
null
)
}
while
(
ancestor
!==
null
&&
ancestor
.
nodeType
===
Node
.
ELEMENT_NODE
)
return
null
}
...
...
@@ -48,12 +46,67 @@ const SelectorEngine = (() => {
}
}
const
scopeSelectorRegex
=
/:scope
\b
/
const
supportScopeQuery
=
(()
=>
{
const
element
=
document
.
createElement
(
'
div
'
)
try
{
element
.
querySelectorAll
(
'
:scope *
'
)
}
catch
(
e
)
{
return
false
}
return
true
})()
let
findFn
=
null
let
findOneFn
=
null
if
(
supportScopeQuery
)
{
findFn
=
Element
.
prototype
.
querySelectorAll
findOneFn
=
Element
.
prototype
.
querySelector
}
else
{
findFn
=
function
(
selector
)
{
if
(
!
scopeSelectorRegex
.
test
(
selector
))
{
return
this
.
querySelectorAll
(
selector
)
}
const
hasId
=
Boolean
(
this
.
id
)
if
(
!
hasId
)
{
this
.
id
=
Util
.
getUID
(
'
scope
'
)
}
let
nodeList
=
null
try
{
selector
=
selector
.
replace
(
scopeSelectorRegex
,
`#
${
this
.
id
}
`
)
nodeList
=
this
.
querySelectorAll
(
selector
)
}
finally
{
if
(
!
hasId
)
{
this
.
removeAttribute
(
'
id
'
)
}
}
return
nodeList
}
findOneFn
=
function
(
selector
)
{
if
(
!
scopeSelectorRegex
.
test
(
selector
))
{
return
this
.
querySelector
(
selector
)
}
const
matches
=
findFn
.
call
(
this
,
selector
)
if
(
typeof
matches
[
0
]
!==
'
undefined
'
)
{
return
matches
[
0
]
}
return
null
}
}
return
{
matches
(
element
,
selector
)
{
return
fnMatches
.
call
(
element
,
selector
)
},
find
(
selector
,
element
=
document
)
{
find
(
selector
,
element
=
document
.
documentElement
)
{
if
(
typeof
selector
!==
'
string
'
)
{
return
null
}
...
...
@@ -62,21 +115,24 @@ const SelectorEngine = (() => {
return
SelectorEngine
.
findOne
(
selector
,
element
)
}
return
element
.
querySelectorAll
(
selector
)
return
findFn
.
call
(
element
,
selector
)
},
findOne
(
selector
,
element
=
document
)
{
findOne
(
selector
,
element
=
document
.
documentElement
)
{
if
(
typeof
selector
!==
'
string
'
)
{
return
null
}
let
selectorType
=
'
querySelector
'
if
(
selector
.
indexOf
(
'
#
'
)
===
0
)
{
selectorType
=
'
getElementById
'
selector
=
selector
.
substr
(
1
,
selector
.
length
)
return
findOneFn
.
call
(
element
,
selector
)
},
children
(
element
,
selector
)
{
if
(
typeof
selector
!==
'
string
'
)
{
return
null
}
return
element
[
selectorType
](
selector
)
const
children
=
Util
.
makeArray
(
element
.
children
)
return
children
.
filter
((
child
)
=>
this
.
matches
(
child
,
selector
))
},
closest
(
element
,
selector
)
{
...
...
This diff is collapsed.
Click to expand it.
js/src/tab.js
+
56
-
62
View file @
7f08061e
...
...
@@ -5,7 +5,9 @@
* --------------------------------------------------------------------------
*/
import
$
from
'
jquery
'
import
Data
from
'
./dom/data
'
import
EventHandler
from
'
./dom/eventHandler
'
import
SelectorEngine
from
'
./dom/selectorEngine
'
import
Util
from
'
./util
'
/**
...
...
@@ -19,7 +21,6 @@ const VERSION = '4.3.1'
const
DATA_KEY
=
'
bs.tab
'
const
EVENT_KEY
=
`.
${
DATA_KEY
}
`
const
DATA_API_KEY
=
'
.data-api
'
const
JQUERY_NO_CONFLICT
=
$
.
fn
[
NAME
]
const
Event
=
{
HIDE
:
`hide
${
EVENT_KEY
}
`
,
...
...
@@ -41,10 +42,10 @@ const Selector = {
DROPDOWN
:
'
.dropdown
'
,
NAV_LIST_GROUP
:
'
.nav, .list-group
'
,
ACTIVE
:
'
.active
'
,
ACTIVE_UL
:
'
> li > .active
'
,
ACTIVE_UL
:
'
:scope
> li > .active
'
,
DATA_TOGGLE
:
'
[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]
'
,
DROPDOWN_TOGGLE
:
'
.dropdown-toggle
'
,
DROPDOWN_ACTIVE_CHILD
:
'
> .dropdown-menu .active
'
DROPDOWN_ACTIVE_CHILD
:
'
:scope
> .dropdown-menu .active
'
}
/**
...
...
@@ -56,6 +57,8 @@ const Selector = {
class
Tab
{
constructor
(
element
)
{
this
.
_element
=
element
Data
.
setData
(
this
.
_element
,
DATA_KEY
,
this
)
}
// Getters
...
...
@@ -68,39 +71,37 @@ class Tab {
show
()
{
if
(
this
.
_element
.
parentNode
&&
this
.
_element
.
parentNode
.
nodeType
===
Node
.
ELEMENT_NODE
&&
$
(
this
.
_element
).
hasClas
s
(
ClassName
.
ACTIVE
)
||
$
(
this
.
_element
).
hasClas
s
(
ClassName
.
DISABLED
))
{
this
.
_element
.
parentNode
.
nodeType
===
Node
.
ELEMENT_NODE
&&
this
.
_element
.
classList
.
contain
s
(
ClassName
.
ACTIVE
)
||
this
.
_element
.
classList
.
contain
s
(
ClassName
.
DISABLED
))
{
return
}
let
target
let
previous
const
listElement
=
$
(
this
.
_element
).
closest
(
Selector
.
NAV_LIST_GROUP
)
[
0
]
const
listElement
=
SelectorEngine
.
closest
(
this
.
_element
,
Selector
.
NAV_LIST_GROUP
)
const
selector
=
Util
.
getSelectorFromElement
(
this
.
_element
)
if
(
listElement
)
{
const
itemSelector
=
listElement
.
nodeName
===
'
UL
'
||
listElement
.
nodeName
===
'
OL
'
?
Selector
.
ACTIVE_UL
:
Selector
.
ACTIVE
previous
=
$
.
makeArray
(
$
(
listElement
)
.
find
(
itemSelector
))
previous
=
Util
.
makeArray
(
SelectorEngine
.
find
(
itemSelector
,
listElement
))
previous
=
previous
[
previous
.
length
-
1
]
}
const
hideEvent
=
$
.
Event
(
Event
.
HIDE
,
{
relatedTarget
:
this
.
_element
})
const
showEvent
=
$
.
Event
(
Event
.
SHOW
,
{
relatedTarget
:
previous
})
let
hideEvent
=
null
if
(
previous
)
{
$
(
previous
).
trigger
(
hideEvent
)
hideEvent
=
EventHandler
.
trigger
(
previous
,
Event
.
HIDE
,
{
relatedTarget
:
this
.
_element
})
}
$
(
this
.
_element
).
trigger
(
showEvent
)
const
showEvent
=
EventHandler
.
trigger
(
this
.
_element
,
Event
.
SHOW
,
{
relatedTarget
:
previous
})
if
(
showEvent
.
isD
efaultPrevented
()
||
hideEvent
.
isD
efaultPrevented
()
)
{
if
(
showEvent
.
d
efaultPrevented
||
hideEvent
!==
null
&&
hideEvent
.
d
efaultPrevented
)
{
return
}
...
...
@@ -114,16 +115,12 @@ class Tab {
)
const
complete
=
()
=>
{
const
hiddenEvent
=
$
.
Event
(
Event
.
HIDDEN
,
{
EventHandler
.
trigger
(
previous
,
Event
.
HIDDEN
,
{
relatedTarget
:
this
.
_element
})
const
shownEvent
=
$
.
Event
(
Event
.
SHOWN
,
{
EventHandler
.
trigger
(
this
.
_element
,
Event
.
SHOWN
,
{
relatedTarget
:
previous
})
$
(
previous
).
trigger
(
hiddenEvent
)
$
(
this
.
_element
).
trigger
(
shownEvent
)
}
if
(
target
)
{
...
...
@@ -134,7 +131,7 @@ class Tab {
}
dispose
()
{
$
.
removeData
(
this
.
_element
,
DATA_KEY
)
Data
.
removeData
(
this
.
_element
,
DATA_KEY
)
this
.
_element
=
null
}
...
...
@@ -142,11 +139,13 @@ class Tab {
_activate
(
element
,
container
,
callback
)
{
const
activeElements
=
container
&&
(
container
.
nodeName
===
'
UL
'
||
container
.
nodeName
===
'
OL
'
)
?
$
(
container
).
find
(
Selector
.
ACTIVE_UL
)
:
$
(
container
).
children
(
Selector
.
ACTIVE
)
?
SelectorEngine
.
find
(
Selector
.
ACTIVE_UL
,
container
)
:
SelectorEngine
.
children
(
container
,
Selector
.
ACTIVE
)
const
active
=
activeElements
[
0
]
const
isTransitioning
=
callback
&&
(
active
&&
active
.
classList
.
contains
(
ClassName
.
FADE
))
const
active
=
activeElements
[
0
]
const
isTransitioning
=
callback
&&
(
active
&&
$
(
active
).
hasClass
(
ClassName
.
FADE
))
const
complete
=
()
=>
this
.
_transitionComplete
(
element
,
active
,
...
...
@@ -155,10 +154,9 @@ class Tab {
if
(
active
&&
isTransitioning
)
{
const
transitionDuration
=
Util
.
getTransitionDurationFromElement
(
active
)
active
.
classList
.
remove
(
ClassName
.
SHOW
)
$
(
active
)
.
removeClass
(
ClassName
.
SHOW
)
.
one
(
Util
.
TRANSITION_END
,
complete
)
EventHandler
.
one
(
active
,
Util
.
TRANSITION_END
,
complete
)
Util
.
emulateTransitionEnd
(
active
,
transitionDuration
)
}
else
{
complete
()
...
...
@@ -167,14 +165,12 @@ class Tab {
_transitionComplete
(
element
,
active
,
callback
)
{
if
(
active
)
{
$
(
active
)
.
remove
Class
(
ClassName
.
ACTIVE
)
active
.
classList
.
remove
(
ClassName
.
ACTIVE
)
const
dropdownChild
=
$
(
active
.
parentNode
).
find
(
Selector
.
DROPDOWN_ACTIVE_CHILD
)[
0
]
const
dropdownChild
=
SelectorEngine
.
findOne
(
Selector
.
DROPDOWN_ACTIVE_CHILD
,
active
.
parentNode
)
if
(
dropdownChild
)
{
$
(
dropdownChild
)
.
remove
Class
(
ClassName
.
ACTIVE
)
dropdownChild
.
classList
.
remove
(
ClassName
.
ACTIVE
)
}
if
(
active
.
getAttribute
(
'
role
'
)
===
'
tab
'
)
{
...
...
@@ -182,7 +178,7 @@ class Tab {
}
}
$
(
element
).
addClass
(
ClassName
.
ACTIVE
)
element
.
classList
.
add
(
ClassName
.
ACTIVE
)
if
(
element
.
getAttribute
(
'
role
'
)
===
'
tab
'
)
{
element
.
setAttribute
(
'
aria-selected
'
,
true
)
}
...
...
@@ -193,13 +189,12 @@ class Tab {
element
.
classList
.
add
(
ClassName
.
SHOW
)
}
if
(
element
.
parentNode
&&
$
(
element
.
parentNode
).
hasClas
s
(
ClassName
.
DROPDOWN_MENU
))
{
const
dropdownElement
=
$
(
ele
ment
).
closest
(
Selector
.
DROPDOWN
)
[
0
]
if
(
element
.
parentNode
&&
element
.
parentNode
.
classList
.
contain
s
(
ClassName
.
DROPDOWN_MENU
))
{
const
dropdownElement
=
S
ele
ctorEngine
.
closest
(
element
,
Selector
.
DROPDOWN
)
if
(
dropdownElement
)
{
const
dropdownToggleList
=
[].
slice
.
call
(
dropdownElement
.
querySelectorAll
(
Selector
.
DROPDOWN_TOGGLE
))
$
(
dropdownToggleList
).
addClass
(
ClassName
.
ACTIVE
)
Util
.
makeArray
(
dropdownElement
.
querySelectorAll
(
Selector
.
DROPDOWN_TOGGLE
))
.
forEach
((
dropdown
)
=>
dropdown
.
classList
.
add
(
ClassName
.
ACTIVE
))
}
element
.
setAttribute
(
'
aria-expanded
'
,
true
)
...
...
@@ -214,13 +209,7 @@ class Tab {
static
_jQueryInterface
(
config
)
{
return
this
.
each
(
function
()
{
const
$this
=
$
(
this
)
let
data
=
$this
.
data
(
DATA_KEY
)
if
(
!
data
)
{
data
=
new
Tab
(
this
)
$this
.
data
(
DATA_KEY
,
data
)
}
const
data
=
Data
.
getData
(
this
,
DATA_KEY
)
||
new
Tab
(
this
)
if
(
typeof
config
===
'
string
'
)
{
if
(
typeof
data
[
config
]
===
'
undefined
'
)
{
...
...
@@ -238,11 +227,12 @@ class Tab {
* ------------------------------------------------------------------------
*/
$
(
document
)
.
on
(
Event
.
CLICK_DATA_API
,
Selector
.
DATA_TOGGLE
,
function
(
event
)
{
event
.
preventDefault
()
Tab
.
_jQueryInterface
.
call
(
$
(
this
),
'
show
'
)
})
EventHandler
.
on
(
document
,
Event
.
CLICK_DATA_API
,
Selector
.
DATA_TOGGLE
,
function
(
event
)
{
event
.
preventDefault
()
const
data
=
Data
.
getData
(
this
,
DATA_KEY
)
||
new
Tab
(
this
)
data
.
show
()
})
/**
* ------------------------------------------------------------------------
...
...
@@ -250,11 +240,15 @@ $(document)
* ------------------------------------------------------------------------
*/
$
.
fn
[
NAME
]
=
Tab
.
_jQueryInterface
$
.
fn
[
NAME
].
Constructor
=
Tab
$
.
fn
[
NAME
].
noConflict
=
()
=>
{
$
.
fn
[
NAME
]
=
JQUERY_NO_CONFLICT
return
Tab
.
_jQueryInterface
const
$
=
Util
.
jQuery
if
(
typeof
$
!==
'
undefined
'
)
{
const
JQUERY_NO_CONFLICT
=
$
.
fn
[
NAME
]
$
.
fn
[
NAME
]
=
Tab
.
_jQueryInterface
$
.
fn
[
NAME
].
Constructor
=
Tab
$
.
fn
[
NAME
].
noConflict
=
()
=>
{
$
.
fn
[
NAME
]
=
JQUERY_NO_CONFLICT
return
Tab
.
_jQueryInterface
}
}
export
default
Tab
This diff is collapsed.
Click to expand it.
js/tests/unit/tab.js
+
9
-
6
View file @
7f08061e
...
...
@@ -320,7 +320,7 @@ $(function () {
'
</ul>
'
var
$tabs
=
$
(
tabsHTML
).
appendTo
(
'
#qunit-fixture
'
)
$tabs
.
find
(
'
li:last-child a
'
)
.
trigger
(
'
click
'
)
EventHandler
.
trigger
(
$tabs
.
find
(
'
li:last-child a
'
)
[
0
],
'
click
'
)
assert
.
notOk
(
$tabs
.
find
(
'
li:first-child a
'
).
hasClass
(
'
active
'
))
assert
.
ok
(
$tabs
.
find
(
'
li:last-child a
'
).
hasClass
(
'
active
'
))
})
...
...
@@ -339,7 +339,7 @@ $(function () {
'
</ul>
'
var
$tabs
=
$
(
tabsHTML
).
appendTo
(
'
#qunit-fixture
'
)
$tabs
.
find
(
'
li:first-child a
'
)
.
trigger
(
'
click
'
)
EventHandler
.
trigger
(
$tabs
.
find
(
'
li:first-child a
'
)
[
0
],
'
click
'
)
assert
.
ok
(
$tabs
.
find
(
'
li:first-child a
'
).
hasClass
(
'
active
'
))
assert
.
notOk
(
$tabs
.
find
(
'
li:last-child a
'
).
hasClass
(
'
active
'
))
assert
.
notOk
(
$tabs
.
find
(
'
li:last-child .dropdown-menu a:first-child
'
).
hasClass
(
'
active
'
))
...
...
@@ -378,9 +378,10 @@ $(function () {
$
(
'
#tab1
'
).
on
(
'
shown.bs.tab
'
,
function
()
{
assert
.
ok
(
$
(
'
#x-tab1
'
).
hasClass
(
'
active
'
))
$
(
'
#tabNested2
'
).
trigger
(
$
.
Event
(
'
click
'
)
)
EventHandler
.
trigger
(
$
(
'
#tabNested2
'
)[
0
],
'
click
'
)
})
.
trigger
(
$
.
Event
(
'
click
'
))
EventHandler
.
trigger
(
$
(
'
#tab1
'
)[
0
],
'
click
'
)
})
QUnit
.
test
(
'
should not remove fade class if no active pane is present
'
,
function
(
assert
)
{
...
...
@@ -410,9 +411,11 @@ $(function () {
done
()
})
.
trigger
(
$
.
Event
(
'
click
'
))
EventHandler
.
trigger
(
$
(
'
#tab-home
'
)[
0
],
'
click
'
)
})
.
trigger
(
$
.
Event
(
'
click
'
))
EventHandler
.
trigger
(
$
(
'
#tab-profile
'
)[
0
],
'
click
'
)
})
QUnit
.
test
(
'
should handle removed tabs
'
,
function
(
assert
)
{
...
...
This diff is collapsed.
Click to expand it.
js/tests/visual/tab.html
+
3
-
0
View file @
7f08061e
...
...
@@ -227,7 +227,10 @@
<script
src=
"../../../node_modules/jquery/dist/jquery.slim.min.js"
></script>
<script
src=
"../../../node_modules/popper.js/dist/umd/popper.min.js"
></script>
<script
src=
"../../dist/dom/data.js"
></script>
<script
src=
"../../dist/dom/eventHandler.js"
></script>
<script
src=
"../../dist/dom/manipulator.js"
></script>
<script
src=
"../../dist/dom/selectorEngine.js"
></script>
<script
src=
"../../dist/util.js"
></script>
<script
src=
"../../dist/tab.js"
></script>
<script
src=
"../../dist/dropdown.js"
></script>
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment
Menu
Explore
Projects
Groups
Snippets