2018-09-29 23:02:13 +00:00
// Native Javascript for Bootstrap 4 v2.0.24 | © dnp_theme | MIT-License
2018-07-30 22:05:37 +00:00
( function ( root , factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD support:
define ( [ ] , factory ) ;
} else if ( typeof module === 'object' && module . exports ) {
// CommonJS-like:
module . exports = factory ( ) ;
} else {
// Browser globals (root is window)
var bsn = factory ( ) ;
root . Alert = bsn . Alert ;
root . Button = bsn . Button ;
root . Carousel = bsn . Carousel ;
root . Collapse = bsn . Collapse ;
root . Dropdown = bsn . Dropdown ;
root . Modal = bsn . Modal ;
root . Popover = bsn . Popover ;
root . ScrollSpy = bsn . ScrollSpy ;
root . Tab = bsn . Tab ;
root . Tooltip = bsn . Tooltip ;
}
} ( this , function ( ) {
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | I n t e r n a l U t i l i t y F u n c t i o n s
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
"use strict" ;
// globals
var globalObject = typeof global !== 'undefined' ? global : this || window ,
DOC = document , HTML = DOC . documentElement , body = 'body' , // allow the library to be used in <head>
// Native Javascript for Bootstrap Global Object
BSN = globalObject . BSN = { } ,
supports = BSN . supports = [ ] ,
// function toggle attributes
dataToggle = 'data-toggle' ,
dataDismiss = 'data-dismiss' ,
dataSpy = 'data-spy' ,
dataRide = 'data-ride' ,
// components
stringAlert = 'Alert' ,
stringButton = 'Button' ,
stringCarousel = 'Carousel' ,
stringCollapse = 'Collapse' ,
stringDropdown = 'Dropdown' ,
stringModal = 'Modal' ,
stringPopover = 'Popover' ,
stringScrollSpy = 'ScrollSpy' ,
stringTab = 'Tab' ,
stringTooltip = 'Tooltip' ,
// options DATA API
databackdrop = 'data-backdrop' ,
dataKeyboard = 'data-keyboard' ,
dataTarget = 'data-target' ,
dataInterval = 'data-interval' ,
dataHeight = 'data-height' ,
dataPause = 'data-pause' ,
dataTitle = 'data-title' ,
dataOriginalTitle = 'data-original-title' ,
dataOriginalText = 'data-original-text' ,
dataDismissible = 'data-dismissible' ,
dataTrigger = 'data-trigger' ,
dataAnimation = 'data-animation' ,
dataContainer = 'data-container' ,
dataPlacement = 'data-placement' ,
dataDelay = 'data-delay' ,
dataOffsetTop = 'data-offset-top' ,
dataOffsetBottom = 'data-offset-bottom' ,
// option keys
backdrop = 'backdrop' , keyboard = 'keyboard' , delay = 'delay' ,
content = 'content' , target = 'target' ,
interval = 'interval' , pause = 'pause' , animation = 'animation' ,
placement = 'placement' , container = 'container' ,
// box model
offsetTop = 'offsetTop' , offsetBottom = 'offsetBottom' ,
offsetLeft = 'offsetLeft' ,
scrollTop = 'scrollTop' , scrollLeft = 'scrollLeft' ,
clientWidth = 'clientWidth' , clientHeight = 'clientHeight' ,
offsetWidth = 'offsetWidth' , offsetHeight = 'offsetHeight' ,
innerWidth = 'innerWidth' , innerHeight = 'innerHeight' ,
scrollHeight = 'scrollHeight' , height = 'height' ,
// aria
ariaExpanded = 'aria-expanded' ,
ariaHidden = 'aria-hidden' ,
// event names
clickEvent = 'click' ,
hoverEvent = 'hover' ,
keydownEvent = 'keydown' ,
keyupEvent = 'keyup' ,
resizeEvent = 'resize' ,
scrollEvent = 'scroll' ,
// originalEvents
showEvent = 'show' ,
shownEvent = 'shown' ,
hideEvent = 'hide' ,
hiddenEvent = 'hidden' ,
closeEvent = 'close' ,
closedEvent = 'closed' ,
slidEvent = 'slid' ,
slideEvent = 'slide' ,
changeEvent = 'change' ,
// other
getAttribute = 'getAttribute' ,
setAttribute = 'setAttribute' ,
hasAttribute = 'hasAttribute' ,
createElement = 'createElement' ,
appendChild = 'appendChild' ,
innerHTML = 'innerHTML' ,
getElementsByTagName = 'getElementsByTagName' ,
preventDefault = 'preventDefault' ,
getBoundingClientRect = 'getBoundingClientRect' ,
querySelectorAll = 'querySelectorAll' ,
getElementsByCLASSNAME = 'getElementsByClassName' ,
getComputedStyle = 'getComputedStyle' ,
indexOf = 'indexOf' ,
parentNode = 'parentNode' ,
length = 'length' ,
toLowerCase = 'toLowerCase' ,
Transition = 'Transition' ,
Duration = 'Duration' ,
Webkit = 'Webkit' ,
style = 'style' ,
push = 'push' ,
tabindex = 'tabindex' ,
contains = 'contains' ,
active = 'active' ,
showClass = 'show' ,
collapsing = 'collapsing' ,
disabled = 'disabled' ,
loading = 'loading' ,
left = 'left' ,
right = 'right' ,
top = 'top' ,
bottom = 'bottom' ,
// tooltip / popover
mouseHover = ( 'onmouseleave' in DOC ) ? [ 'mouseenter' , 'mouseleave' ] : [ 'mouseover' , 'mouseout' ] ,
tipPositions = /\b(top|bottom|left|right)+/ ,
// modal
modalOverlay = 0 ,
fixedTop = 'fixed-top' ,
fixedBottom = 'fixed-bottom' ,
// transitionEnd since 2.0.4
supportTransitions = Webkit + Transition in HTML [ style ] || Transition [ toLowerCase ] ( ) in HTML [ style ] ,
transitionEndEvent = Webkit + Transition in HTML [ style ] ? Webkit [ toLowerCase ] ( ) + Transition + 'End' : Transition [ toLowerCase ] ( ) + 'end' ,
transitionDuration = Webkit + Duration in HTML [ style ] ? Webkit [ toLowerCase ] ( ) + Transition + Duration : Transition [ toLowerCase ] ( ) + Duration ,
// set new focus element since 2.0.3
setFocus = function ( element ) {
element . focus ? element . focus ( ) : element . setActive ( ) ;
} ,
// class manipulation, since 2.0.0 requires polyfill.js
addClass = function ( element , classNAME ) {
element . classList . add ( classNAME ) ;
} ,
removeClass = function ( element , classNAME ) {
element . classList . remove ( classNAME ) ;
} ,
hasClass = function ( element , classNAME ) { // since 2.0.0
return element . classList [ contains ] ( classNAME ) ;
} ,
// selection methods
getElementsByClassName = function ( element , classNAME ) { // returns Array
return [ ] . slice . call ( element [ getElementsByCLASSNAME ] ( classNAME ) ) ;
} ,
queryElement = function ( selector , parent ) {
var lookUp = parent ? parent : DOC ;
return typeof selector === 'object' ? selector : lookUp . querySelector ( selector ) ;
} ,
getClosest = function ( element , selector ) { //element is the element and selector is for the closest parent element to find
// source http://gomakethings.com/climbing-up-and-down-the-dom-tree-with-vanilla-javascript/
var firstChar = selector . charAt ( 0 ) , selectorSubstring = selector . substr ( 1 ) ;
if ( firstChar === '.' ) { // If selector is a class
for ( ; element && element !== DOC ; element = element [ parentNode ] ) { // Get closest match
if ( queryElement ( selector , element [ parentNode ] ) !== null && hasClass ( element , selectorSubstring ) ) { return element ; }
}
} else if ( firstChar === '#' ) { // If selector is an ID
for ( ; element && element !== DOC ; element = element [ parentNode ] ) { // Get closest match
if ( element . id === selectorSubstring ) { return element ; }
}
}
return false ;
} ,
// event attach jQuery style / trigger since 1.2.0
on = function ( element , event , handler ) {
element . addEventListener ( event , handler , false ) ;
} ,
off = function ( element , event , handler ) {
element . removeEventListener ( event , handler , false ) ;
} ,
one = function ( element , event , handler ) { // one since 2.0.4
on ( element , event , function handlerWrapper ( e ) {
handler ( e ) ;
off ( element , event , handlerWrapper ) ;
} ) ;
} ,
getTransitionDurationFromElement = function ( element ) {
var duration = globalObject [ getComputedStyle ] ( element ) [ transitionDuration ] ;
duration = parseFloat ( duration ) ;
duration = typeof duration === 'number' && ! isNaN ( duration ) ? duration * 1000 : 0 ;
return duration + 50 ; // we take a short offset to make sure we fire on the next frame after animation
} ,
emulateTransitionEnd = function ( element , handler ) { // emulateTransitionEnd since 2.0.4
var called = 0 , duration = getTransitionDurationFromElement ( element ) ;
supportTransitions && one ( element , transitionEndEvent , function ( e ) { handler ( e ) ; called = 1 ; } ) ;
setTimeout ( function ( ) { ! called && handler ( ) ; } , duration ) ;
} ,
bootstrapCustomEvent = function ( eventName , componentName , related ) {
var OriginalCustomEvent = new CustomEvent ( eventName + '.bs.' + componentName ) ;
OriginalCustomEvent . relatedTarget = related ;
this . dispatchEvent ( OriginalCustomEvent ) ;
} ,
// tooltip / popover stuff
getScroll = function ( ) { // also Affix and ScrollSpy uses it
return {
y : globalObject . pageYOffset || HTML [ scrollTop ] ,
x : globalObject . pageXOffset || HTML [ scrollLeft ]
}
} ,
styleTip = function ( link , element , position , parent ) { // both popovers and tooltips (target,tooltip,placement,elementToAppendTo)
var elementDimensions = { w : element [ offsetWidth ] , h : element [ offsetHeight ] } ,
windowWidth = ( HTML [ clientWidth ] || DOC [ body ] [ clientWidth ] ) ,
windowHeight = ( HTML [ clientHeight ] || DOC [ body ] [ clientHeight ] ) ,
rect = link [ getBoundingClientRect ] ( ) ,
scroll = parent === DOC [ body ] ? getScroll ( ) : { x : parent [ offsetLeft ] + parent [ scrollLeft ] , y : parent [ offsetTop ] + parent [ scrollTop ] } ,
linkDimensions = { w : rect [ right ] - rect [ left ] , h : rect [ bottom ] - rect [ top ] } ,
isPopover = hasClass ( element , 'popover' ) ,
topPosition , leftPosition ,
arrow = queryElement ( '.arrow' , element ) ,
arrowTop , arrowLeft , arrowWidth , arrowHeight ,
halfTopExceed = rect [ top ] + linkDimensions . h / 2 - elementDimensions . h / 2 < 0 ,
halfLeftExceed = rect [ left ] + linkDimensions . w / 2 - elementDimensions . w / 2 < 0 ,
halfRightExceed = rect [ left ] + elementDimensions . w / 2 + linkDimensions . w / 2 >= windowWidth ,
halfBottomExceed = rect [ top ] + elementDimensions . h / 2 + linkDimensions . h / 2 >= windowHeight ,
topExceed = rect [ top ] - elementDimensions . h < 0 ,
leftExceed = rect [ left ] - elementDimensions . w < 0 ,
bottomExceed = rect [ top ] + elementDimensions . h + linkDimensions . h >= windowHeight ,
rightExceed = rect [ left ] + elementDimensions . w + linkDimensions . w >= windowWidth ;
// recompute position
position = ( position === left || position === right ) && leftExceed && rightExceed ? top : position ; // first, when both left and right limits are exceeded, we fall back to top|bottom
position = position === top && topExceed ? bottom : position ;
position = position === bottom && bottomExceed ? top : position ;
position = position === left && leftExceed ? right : position ;
position = position === right && rightExceed ? left : position ;
// update tooltip/popover class
element . className [ indexOf ] ( position ) === - 1 && ( element . className = element . className . replace ( tipPositions , position ) ) ;
// we check the computed width & height and update here
arrowWidth = arrow [ offsetWidth ] ; arrowHeight = arrow [ offsetHeight ] ;
// apply styling to tooltip or popover
if ( position === left || position === right ) { // secondary|side positions
if ( position === left ) { // LEFT
leftPosition = rect [ left ] + scroll . x - elementDimensions . w - ( isPopover ? arrowWidth : 0 ) ;
} else { // RIGHT
leftPosition = rect [ left ] + scroll . x + linkDimensions . w ;
}
// adjust top and arrow
if ( halfTopExceed ) {
topPosition = rect [ top ] + scroll . y ;
arrowTop = linkDimensions . h / 2 - arrowWidth ;
} else if ( halfBottomExceed ) {
topPosition = rect [ top ] + scroll . y - elementDimensions . h + linkDimensions . h ;
arrowTop = elementDimensions . h - linkDimensions . h / 2 - arrowWidth ;
} else {
topPosition = rect [ top ] + scroll . y - elementDimensions . h / 2 + linkDimensions . h / 2 ;
arrowTop = elementDimensions . h / 2 - ( isPopover ? arrowHeight * 0.9 : arrowHeight / 2 ) ;
}
} else if ( position === top || position === bottom ) { // primary|vertical positions
if ( position === top ) { // TOP
topPosition = rect [ top ] + scroll . y - elementDimensions . h - ( isPopover ? arrowHeight : 0 ) ;
} else { // BOTTOM
topPosition = rect [ top ] + scroll . y + linkDimensions . h ;
}
// adjust left | right and also the arrow
if ( halfLeftExceed ) {
leftPosition = 0 ;
arrowLeft = rect [ left ] + linkDimensions . w / 2 - arrowWidth ;
} else if ( halfRightExceed ) {
leftPosition = windowWidth - elementDimensions . w * 1.01 ;
arrowLeft = elementDimensions . w - ( windowWidth - rect [ left ] ) + linkDimensions . w / 2 - arrowWidth / 2 ;
} else {
leftPosition = rect [ left ] + scroll . x - elementDimensions . w / 2 + linkDimensions . w / 2 ;
arrowLeft = elementDimensions . w / 2 - arrowWidth / 2 ;
}
}
// apply style to tooltip/popover and its arrow
element [ style ] [ top ] = topPosition + 'px' ;
element [ style ] [ left ] = leftPosition + 'px' ;
arrowTop && ( arrow [ style ] [ top ] = arrowTop + 'px' ) ;
arrowLeft && ( arrow [ style ] [ left ] = arrowLeft + 'px' ) ;
} ;
2018-09-29 23:02:13 +00:00
BSN . version = '2.0.24' ;
2018-07-30 22:05:37 +00:00
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | A l e r t
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// ALERT DEFINITION
// ================
var Alert = function ( element ) {
// initialization element
element = queryElement ( element ) ;
// bind, target alert, duration and stuff
var self = this , component = 'alert' ,
alert = getClosest ( element , '.' + component ) ,
triggerHandler = function ( ) { hasClass ( alert , 'fade' ) ? emulateTransitionEnd ( alert , transitionEndHandler ) : transitionEndHandler ( ) ; } ,
// handlers
clickHandler = function ( e ) {
alert = getClosest ( e [ target ] , '.' + component ) ;
element = queryElement ( '[' + dataDismiss + '="' + component + '"]' , alert ) ;
element && alert && ( element === e [ target ] || element [ contains ] ( e [ target ] ) ) && self . close ( ) ;
} ,
transitionEndHandler = function ( ) {
bootstrapCustomEvent . call ( alert , closedEvent , component ) ;
off ( element , clickEvent , clickHandler ) ; // detach it's listener
alert [ parentNode ] . removeChild ( alert ) ;
} ;
// public method
this . close = function ( ) {
if ( alert && element && hasClass ( alert , showClass ) ) {
bootstrapCustomEvent . call ( alert , closeEvent , component ) ;
removeClass ( alert , showClass ) ;
alert && triggerHandler ( ) ;
}
} ;
// init
if ( ! ( stringAlert in element ) ) { // prevent adding event handlers twice
on ( element , clickEvent , clickHandler ) ;
}
element [ stringAlert ] = self ;
} ;
// ALERT DATA API
// ==============
supports [ push ] ( [ stringAlert , Alert , '[' + dataDismiss + '="alert"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | B u t t o n
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// BUTTON DEFINITION
// ===================
var Button = function ( element ) {
// initialization element
element = queryElement ( element ) ;
// constant
var toggled = false , // toggled makes sure to prevent triggering twice the change.bs.button events
// strings
component = 'button' ,
checked = 'checked' ,
reset = 'reset' ,
LABEL = 'LABEL' ,
INPUT = 'INPUT' ,
// private methods
keyHandler = function ( e ) {
var key = e . which || e . keyCode ;
key === 32 && e [ target ] === DOC . activeElement && toggle ( e ) ;
} ,
preventScroll = function ( e ) {
var key = e . which || e . keyCode ;
key === 32 && e [ preventDefault ] ( ) ;
} ,
toggle = function ( e ) {
var label = e [ target ] . tagName === LABEL ? e [ target ] : e [ target ] [ parentNode ] . tagName === LABEL ? e [ target ] [ parentNode ] : null ; // the .btn label
if ( ! label ) return ; //react if a label or its immediate child is clicked
var eventTarget = e [ target ] , // the button itself, the target of the handler function
labels = getElementsByClassName ( eventTarget [ parentNode ] , 'btn' ) , // all the button group buttons
input = label [ getElementsByTagName ] ( INPUT ) [ 0 ] ;
if ( ! input ) return ; //return if no input found
// manage the dom manipulation
if ( input . type === 'checkbox' ) { //checkboxes
if ( ! input [ checked ] ) {
addClass ( label , active ) ;
input [ getAttribute ] ( checked ) ;
input [ setAttribute ] ( checked , checked ) ;
input [ checked ] = true ;
} else {
removeClass ( label , active ) ;
input [ getAttribute ] ( checked ) ;
input . removeAttribute ( checked ) ;
input [ checked ] = false ;
}
if ( ! toggled ) { // prevent triggering the event twice
toggled = true ;
bootstrapCustomEvent . call ( input , changeEvent , component ) ; //trigger the change for the input
bootstrapCustomEvent . call ( element , changeEvent , component ) ; //trigger the change for the btn-group
}
}
if ( input . type === 'radio' && ! toggled ) { // radio buttons
if ( ! input [ checked ] ) { // don't trigger if already active
addClass ( label , active ) ;
input [ setAttribute ] ( checked , checked ) ;
input [ checked ] = true ;
bootstrapCustomEvent . call ( input , changeEvent , component ) ; //trigger the change for the input
bootstrapCustomEvent . call ( element , changeEvent , component ) ; //trigger the change for the btn-group
toggled = true ;
for ( var i = 0 , ll = labels [ length ] ; i < ll ; i ++ ) {
var otherLabel = labels [ i ] , otherInput = otherLabel [ getElementsByTagName ] ( INPUT ) [ 0 ] ;
if ( otherLabel !== label && hasClass ( otherLabel , active ) ) {
removeClass ( otherLabel , active ) ;
otherInput . removeAttribute ( checked ) ;
otherInput [ checked ] = false ;
bootstrapCustomEvent . call ( otherInput , changeEvent , component ) ; // trigger the change
}
}
}
}
setTimeout ( function ( ) { toggled = false ; } , 50 ) ;
} ;
// init
if ( ! ( stringButton in element ) ) { // prevent adding event handlers twice
on ( element , clickEvent , toggle ) ;
queryElement ( '[' + tabindex + ']' , element ) && on ( element , keyupEvent , keyHandler ) ,
on ( element , keydownEvent , preventScroll ) ;
}
// activate items on load
var labelsToACtivate = getElementsByClassName ( element , 'btn' ) , lbll = labelsToACtivate [ length ] ;
for ( var i = 0 ; i < lbll ; i ++ ) {
! hasClass ( labelsToACtivate [ i ] , active ) && queryElement ( 'input:checked' , labelsToACtivate [ i ] )
&& addClass ( labelsToACtivate [ i ] , active ) ;
}
element [ stringButton ] = this ;
} ;
// BUTTON DATA API
// =================
supports [ push ] ( [ stringButton , Button , '[' + dataToggle + '="buttons"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | C a r o u s e l
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
// CAROUSEL DEFINITION
// ===================
var Carousel = function ( element , options ) {
// initialization element
element = queryElement ( element ) ;
// set options
options = options || { } ;
// DATA API
var intervalAttribute = element [ getAttribute ] ( dataInterval ) ,
intervalOption = options [ interval ] ,
intervalData = intervalAttribute === 'false' ? 0 : parseInt ( intervalAttribute ) ,
pauseData = element [ getAttribute ] ( dataPause ) === hoverEvent || false ,
keyboardData = element [ getAttribute ] ( dataKeyboard ) === 'true' || false ,
// strings
component = 'carousel' ,
paused = 'paused' ,
direction = 'direction' ,
carouselItem = 'carousel-item' ,
dataSlideTo = 'data-slide-to' ;
this [ keyboard ] = options [ keyboard ] === true || keyboardData ;
this [ pause ] = ( options [ pause ] === hoverEvent || pauseData ) ? hoverEvent : false ; // false / hover
this [ interval ] = typeof intervalOption === 'number' ? intervalOption
: intervalOption === false || intervalData === 0 || intervalData === false ? 0
2018-09-29 23:02:13 +00:00
: isNaN ( intervalData ) ? 5000 // bootstrap carousel default interval
: intervalData ;
2018-07-30 22:05:37 +00:00
// bind, event targets
var self = this , index = element . index = 0 , timer = element . timer = 0 ,
isSliding = false , // isSliding prevents click event handlers when animation is running
slides = getElementsByClassName ( element , carouselItem ) , total = slides [ length ] ,
slideDirection = this [ direction ] = left ,
leftArrow = getElementsByClassName ( element , component + '-control-prev' ) [ 0 ] ,
rightArrow = getElementsByClassName ( element , component + '-control-next' ) [ 0 ] ,
indicator = queryElement ( '.' + component + '-indicators' , element ) ,
indicators = indicator && indicator [ getElementsByTagName ] ( "LI" ) || [ ] ;
// handlers
var pauseHandler = function ( ) {
if ( self [ interval ] !== false && ! hasClass ( element , paused ) ) {
addClass ( element , paused ) ;
! isSliding && clearInterval ( timer ) ;
}
} ,
resumeHandler = function ( ) {
if ( self [ interval ] !== false && hasClass ( element , paused ) ) {
removeClass ( element , paused ) ;
! isSliding && clearInterval ( timer ) ;
! isSliding && self . cycle ( ) ;
}
} ,
indicatorHandler = function ( e ) {
e [ preventDefault ] ( ) ;
if ( isSliding ) return ;
var eventTarget = e [ target ] ; // event target | the current active item
if ( eventTarget && ! hasClass ( eventTarget , active ) && eventTarget [ getAttribute ] ( dataSlideTo ) ) {
index = parseInt ( eventTarget [ getAttribute ] ( dataSlideTo ) , 10 ) ;
} else { return false ; }
self . slideTo ( index ) ; //Do the slide
} ,
controlsHandler = function ( e ) {
e [ preventDefault ] ( ) ;
if ( isSliding ) return ;
var eventTarget = e . currentTarget || e . srcElement ;
if ( eventTarget === rightArrow ) {
index ++ ;
} else if ( eventTarget === leftArrow ) {
index -- ;
}
self . slideTo ( index ) ; //Do the slide
} ,
keyHandler = function ( e ) {
if ( isSliding ) return ;
switch ( e . which ) {
case 39 :
index ++ ;
break ;
case 37 :
index -- ;
break ;
default : return ;
}
self . slideTo ( index ) ; //Do the slide
} ,
// private methods
isElementInScrollRange = function ( ) {
var rect = element [ getBoundingClientRect ] ( ) ,
viewportHeight = globalObject [ innerHeight ] || HTML [ clientHeight ]
return rect [ top ] <= viewportHeight && rect [ bottom ] >= 0 ; // bottom && top
} ,
setActivePage = function ( pageIndex ) { //indicators
for ( var i = 0 , icl = indicators [ length ] ; i < icl ; i ++ ) {
removeClass ( indicators [ i ] , active ) ;
}
if ( indicators [ pageIndex ] ) addClass ( indicators [ pageIndex ] , active ) ;
} ;
// public methods
this . cycle = function ( ) {
timer = setInterval ( function ( ) {
isElementInScrollRange ( ) && ( index ++ , self . slideTo ( index ) ) ;
} , this [ interval ] ) ;
} ;
this . slideTo = function ( next ) {
if ( isSliding ) return ; // when controled via methods, make sure to check again
var activeItem = this . getActiveIndex ( ) , // the current active
orientation ;
2018-09-29 23:02:13 +00:00
// first return if we're on the same item #227
if ( activeItem === next ) {
return ;
// or determine slideDirection
} else if ( ( activeItem < next ) || ( activeItem === 0 && next === total - 1 ) ) {
2018-07-30 22:05:37 +00:00
slideDirection = self [ direction ] = left ; // next
} else if ( ( activeItem > next ) || ( activeItem === total - 1 && next === 0 ) ) {
slideDirection = self [ direction ] = right ; // prev
}
// find the right next index
if ( next < 0 ) { next = total - 1 ; }
else if ( next === total ) { next = 0 ; }
// update index
index = next ;
orientation = slideDirection === left ? 'next' : 'prev' ; //determine type
bootstrapCustomEvent . call ( element , slideEvent , component , slides [ next ] ) ; // here we go with the slide
isSliding = true ;
clearInterval ( timer ) ;
setActivePage ( next ) ;
if ( supportTransitions && hasClass ( element , 'slide' ) ) {
addClass ( slides [ next ] , carouselItem + '-' + orientation ) ;
slides [ next ] [ offsetWidth ] ;
addClass ( slides [ next ] , carouselItem + '-' + slideDirection ) ;
addClass ( slides [ activeItem ] , carouselItem + '-' + slideDirection ) ;
one ( slides [ next ] , transitionEndEvent , function ( e ) {
var timeout = e [ target ] !== slides [ next ] ? e . elapsedTime * 1000 + 100 : 20 ;
isSliding && setTimeout ( function ( ) {
isSliding = false ;
addClass ( slides [ next ] , active ) ;
removeClass ( slides [ activeItem ] , active ) ;
removeClass ( slides [ next ] , carouselItem + '-' + orientation ) ;
removeClass ( slides [ next ] , carouselItem + '-' + slideDirection ) ;
removeClass ( slides [ activeItem ] , carouselItem + '-' + slideDirection ) ;
bootstrapCustomEvent . call ( element , slidEvent , component , slides [ next ] ) ;
if ( ! DOC . hidden && self [ interval ] && ! hasClass ( element , paused ) ) {
self . cycle ( ) ;
}
} , timeout ) ;
} ) ;
} else {
addClass ( slides [ next ] , active ) ;
slides [ next ] [ offsetWidth ] ;
removeClass ( slides [ activeItem ] , active ) ;
setTimeout ( function ( ) {
isSliding = false ;
if ( self [ interval ] && ! hasClass ( element , paused ) ) {
self . cycle ( ) ;
}
bootstrapCustomEvent . call ( element , slidEvent , component , slides [ next ] ) ;
} , 100 ) ;
}
} ;
this . getActiveIndex = function ( ) {
return slides [ indexOf ] ( getElementsByClassName ( element , carouselItem + ' active' ) [ 0 ] ) || 0 ;
} ;
// init
if ( ! ( stringCarousel in element ) ) { // prevent adding event handlers twice
if ( self [ pause ] && self [ interval ] ) {
on ( element , mouseHover [ 0 ] , pauseHandler ) ;
on ( element , mouseHover [ 1 ] , resumeHandler ) ;
on ( element , 'touchstart' , pauseHandler ) ;
on ( element , 'touchend' , resumeHandler ) ;
}
rightArrow && on ( rightArrow , clickEvent , controlsHandler ) ;
leftArrow && on ( leftArrow , clickEvent , controlsHandler ) ;
indicator && on ( indicator , clickEvent , indicatorHandler ) ;
self [ keyboard ] === true && on ( globalObject , keydownEvent , keyHandler ) ;
}
if ( self . getActiveIndex ( ) < 0 ) {
slides [ length ] && addClass ( slides [ 0 ] , active ) ;
indicators [ length ] && setActivePage ( 0 ) ;
}
if ( self [ interval ] ) { self . cycle ( ) ; }
element [ stringCarousel ] = self ;
} ;
// CAROUSEL DATA API
// =================
supports [ push ] ( [ stringCarousel , Carousel , '[' + dataRide + '="carousel"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | C o l l a p s e
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// COLLAPSE DEFINITION
// ===================
var Collapse = function ( element , options ) {
// initialization element
element = queryElement ( element ) ;
// set options
options = options || { } ;
// event targets and constants
var accordion = null , collapse = null , self = this ,
accordionData = element [ getAttribute ] ( 'data-parent' ) ,
activeCollapse , activeElement ,
// component strings
component = 'collapse' ,
collapsed = 'collapsed' ,
isAnimating = 'isAnimating' ,
// private methods
openAction = function ( collapseElement , toggle ) {
bootstrapCustomEvent . call ( collapseElement , showEvent , component ) ;
collapseElement [ isAnimating ] = true ;
addClass ( collapseElement , collapsing ) ;
removeClass ( collapseElement , component ) ;
collapseElement [ style ] [ height ] = collapseElement [ scrollHeight ] + 'px' ;
emulateTransitionEnd ( collapseElement , function ( ) {
collapseElement [ isAnimating ] = false ;
collapseElement [ setAttribute ] ( ariaExpanded , 'true' ) ;
toggle [ setAttribute ] ( ariaExpanded , 'true' ) ;
removeClass ( collapseElement , collapsing ) ;
addClass ( collapseElement , component ) ;
addClass ( collapseElement , showClass ) ;
collapseElement [ style ] [ height ] = '' ;
bootstrapCustomEvent . call ( collapseElement , shownEvent , component ) ;
} ) ;
} ,
closeAction = function ( collapseElement , toggle ) {
bootstrapCustomEvent . call ( collapseElement , hideEvent , component ) ;
collapseElement [ isAnimating ] = true ;
collapseElement [ style ] [ height ] = collapseElement [ scrollHeight ] + 'px' ; // set height first
removeClass ( collapseElement , component ) ;
removeClass ( collapseElement , showClass ) ;
addClass ( collapseElement , collapsing ) ;
collapseElement [ offsetWidth ] ; // force reflow to enable transition
collapseElement [ style ] [ height ] = '0px' ;
emulateTransitionEnd ( collapseElement , function ( ) {
collapseElement [ isAnimating ] = false ;
collapseElement [ setAttribute ] ( ariaExpanded , 'false' ) ;
toggle [ setAttribute ] ( ariaExpanded , 'false' ) ;
removeClass ( collapseElement , collapsing ) ;
addClass ( collapseElement , component ) ;
collapseElement [ style ] [ height ] = '' ;
bootstrapCustomEvent . call ( collapseElement , hiddenEvent , component ) ;
} ) ;
} ,
getTarget = function ( ) {
var href = element . href && element [ getAttribute ] ( 'href' ) ,
parent = element [ getAttribute ] ( dataTarget ) ,
id = href || ( parent && parent . charAt ( 0 ) === '#' ) && parent ;
return id && queryElement ( id ) ;
} ;
// public methods
this . toggle = function ( e ) {
e [ preventDefault ] ( ) ;
if ( ! hasClass ( collapse , showClass ) ) { self . show ( ) ; }
else { self . hide ( ) ; }
} ;
this . hide = function ( ) {
if ( collapse [ isAnimating ] ) return ;
closeAction ( collapse , element ) ;
addClass ( element , collapsed ) ;
} ;
this . show = function ( ) {
if ( accordion ) {
activeCollapse = queryElement ( '.' + component + '.' + showClass , accordion ) ;
activeElement = activeCollapse && ( queryElement ( '[' + dataToggle + '="' + component + '"][' + dataTarget + '="#' + activeCollapse . id + '"]' , accordion )
|| queryElement ( '[' + dataToggle + '="' + component + '"][href="#' + activeCollapse . id + '"]' , accordion ) ) ;
}
if ( ! collapse [ isAnimating ] || activeCollapse && ! activeCollapse [ isAnimating ] ) {
if ( activeElement && activeCollapse !== collapse ) {
closeAction ( activeCollapse , activeElement ) ;
addClass ( activeElement , collapsed ) ;
}
openAction ( collapse , element ) ;
removeClass ( element , collapsed ) ;
}
} ;
// init
if ( ! ( stringCollapse in element ) ) { // prevent adding event handlers twice
on ( element , clickEvent , self . toggle ) ;
}
collapse = getTarget ( ) ;
collapse [ isAnimating ] = false ; // when true it will prevent click handlers
accordion = queryElement ( options . parent ) || accordionData && getClosest ( element , accordionData ) ;
element [ stringCollapse ] = self ;
} ;
// COLLAPSE DATA API
// =================
supports [ push ] ( [ stringCollapse , Collapse , '[' + dataToggle + '="collapse"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | D r o p d o w n
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
// DROPDOWN DEFINITION
// ===================
var Dropdown = function ( element , option ) {
// initialization element
element = queryElement ( element ) ;
// set option
this . persist = option === true || element [ getAttribute ] ( 'data-persist' ) === 'true' || false ;
// constants, event targets, strings
var self = this , children = 'children' ,
parent = element [ parentNode ] ,
component = 'dropdown' , open = 'open' ,
relatedTarget = null ,
menu = queryElement ( '.dropdown-menu' , parent ) ,
menuItems = ( function ( ) {
var set = menu [ children ] , newSet = [ ] ;
for ( var i = 0 ; i < set [ length ] ; i ++ ) {
2018-11-07 23:52:28 +00:00
//set[i][children][length] && (set[i][children][0].tagName === 'A' && newSet[push](set[i][children][0]));
//start patch: push all child elements, not only first
if ( set [ i ] [ children ] [ length ] ) {
for ( var j = 0 ; j < set [ i ] [ children ] [ length ] ; j ++ ) {
set [ i ] [ children ] [ j ] . tagName === 'A' && newSet [ push ] ( set [ i ] [ children ] [ j ] ) ;
}
}
//end patch
2018-07-30 22:05:37 +00:00
set [ i ] . tagName === 'A' && newSet [ push ] ( set [ i ] ) ;
}
return newSet ;
} ) ( ) ,
// preventDefault on empty anchor links
preventEmptyAnchor = function ( anchor ) {
( anchor . href && anchor . href . slice ( - 1 ) === '#' || anchor [ parentNode ] && anchor [ parentNode ] . href
&& anchor [ parentNode ] . href . slice ( - 1 ) === '#' ) && this [ preventDefault ] ( ) ;
} ,
// toggle dismissible events
toggleDismiss = function ( ) {
var type = element [ open ] ? on : off ;
type ( DOC , clickEvent , dismissHandler ) ;
type ( DOC , keydownEvent , preventScroll ) ;
type ( DOC , keyupEvent , keyHandler ) ;
} ,
// handlers
dismissHandler = function ( e ) {
var eventTarget = e [ target ] , hasData = eventTarget && ( stringDropdown in eventTarget || stringDropdown in eventTarget [ parentNode ] ) ;
if ( ( eventTarget === menu || menu [ contains ] ( eventTarget ) ) && ( self . persist || hasData ) ) { return ; }
else {
relatedTarget = eventTarget === element || element [ contains ] ( eventTarget ) ? element : null ;
hide ( ) ;
}
preventEmptyAnchor . call ( e , eventTarget ) ;
} ,
clickHandler = function ( e ) {
relatedTarget = element ;
show ( ) ;
preventEmptyAnchor . call ( e , e [ target ] ) ;
} ,
preventScroll = function ( e ) {
var key = e . which || e . keyCode ;
if ( key === 38 || key === 40 ) { e [ preventDefault ] ( ) ; }
} ,
keyHandler = function ( e ) {
var key = e . which || e . keyCode ,
activeItem = DOC . activeElement ,
idx = menuItems [ indexOf ] ( activeItem ) ,
isSameElement = activeItem === element ,
isInsideMenu = menu [ contains ] ( activeItem ) ,
isMenuItem = activeItem [ parentNode ] === menu || activeItem [ parentNode ] [ parentNode ] === menu ;
if ( isMenuItem || isSameElement ) { // navigate up | down
2018-11-07 23:52:28 +00:00
/ * i d x = i s S a m e E l e m e n t ? 0
: key === 38 ? ( idx > 1 ? idx - 1 : 0 )
: key === 40 ? ( idx < menuItems [ length ] - 1 ? idx + 1 : idx ) : idx ;
* /
//start patch: skip hidden elements
do {
idx = isSameElement ? 0
2018-07-30 22:05:37 +00:00
: key === 38 ? ( idx > 1 ? idx - 1 : 0 )
: key === 40 ? ( idx < menuItems [ length ] - 1 ? idx + 1 : idx ) : idx ;
2018-11-08 22:42:45 +00:00
if ( idx == 0 || idx == menuItems [ length ] - 1 )
break ;
2018-11-07 23:52:28 +00:00
} while ( ! menuItems [ idx ] . offsetHeight )
//end patch
2018-07-30 22:05:37 +00:00
menuItems [ idx ] && setFocus ( menuItems [ idx ] ) ;
}
if ( ( menuItems [ length ] && isMenuItem // menu has items
|| ! menuItems [ length ] && ( isInsideMenu || isSameElement ) // menu might be a form
|| ! isInsideMenu ) // or the focused element is not in the menu at all
&& element [ open ] && key === 27 // menu must be open
) {
self . toggle ( ) ;
relatedTarget = null ;
}
} ,
// private methods
show = function ( ) {
bootstrapCustomEvent . call ( parent , showEvent , component , relatedTarget ) ;
addClass ( menu , showClass ) ;
addClass ( parent , showClass ) ;
menu [ setAttribute ] ( ariaExpanded , true ) ;
bootstrapCustomEvent . call ( parent , shownEvent , component , relatedTarget ) ;
element [ open ] = true ;
off ( element , clickEvent , clickHandler ) ;
setTimeout ( function ( ) {
setFocus ( menu [ getElementsByTagName ] ( 'INPUT' ) [ 0 ] || element ) ; // focus the first input item | element
toggleDismiss ( ) ;
} , 1 ) ;
} ,
hide = function ( ) {
bootstrapCustomEvent . call ( parent , hideEvent , component , relatedTarget ) ;
removeClass ( menu , showClass ) ;
removeClass ( parent , showClass ) ;
menu [ setAttribute ] ( ariaExpanded , false ) ;
bootstrapCustomEvent . call ( parent , hiddenEvent , component , relatedTarget ) ;
element [ open ] = false ;
toggleDismiss ( ) ;
setFocus ( element ) ;
setTimeout ( function ( ) { on ( element , clickEvent , clickHandler ) ; } , 1 ) ;
} ;
// set initial state to closed
element [ open ] = false ;
// public methods
this . toggle = function ( ) {
if ( hasClass ( parent , showClass ) && element [ open ] ) { hide ( ) ; }
else { show ( ) ; }
} ;
// init
if ( ! ( stringDropdown in element ) ) { // prevent adding event handlers twice
! tabindex in menu && menu [ setAttribute ] ( tabindex , '0' ) ; // Fix onblur on Chrome | Safari
on ( element , clickEvent , clickHandler ) ;
}
element [ stringDropdown ] = self ;
} ;
// DROPDOWN DATA API
// =================
supports [ push ] ( [ stringDropdown , Dropdown , '[' + dataToggle + '="dropdown"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | M o d a l
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// MODAL DEFINITION
// ===============
var Modal = function ( element , options ) { // element can be the modal/triggering button
// the modal (both JavaScript / DATA API init) / triggering button element (DATA API)
element = queryElement ( element ) ;
// determine modal, triggering element
var btnCheck = element [ getAttribute ] ( dataTarget ) || element [ getAttribute ] ( 'href' ) ,
checkModal = queryElement ( btnCheck ) ,
modal = hasClass ( element , 'modal' ) ? element : checkModal ,
overlayDelay ,
// strings
component = 'modal' ,
staticString = 'static' ,
paddingLeft = 'paddingLeft' ,
paddingRight = 'paddingRight' ,
modalBackdropString = 'modal-backdrop' ;
if ( hasClass ( element , 'modal' ) ) { element = null ; } // modal is now independent of it's triggering element
if ( ! modal ) { return ; } // invalidate
// set options
options = options || { } ;
this [ keyboard ] = options [ keyboard ] === false || modal [ getAttribute ] ( dataKeyboard ) === 'false' ? false : true ;
this [ backdrop ] = options [ backdrop ] === staticString || modal [ getAttribute ] ( databackdrop ) === staticString ? staticString : true ;
this [ backdrop ] = options [ backdrop ] === false || modal [ getAttribute ] ( databackdrop ) === 'false' ? false : this [ backdrop ] ;
this [ content ] = options [ content ] ; // JavaScript only
// bind, constants, event targets and other vars
var self = this , relatedTarget = null ,
bodyIsOverflowing , modalIsOverflowing , scrollbarWidth , overlay ,
// also find fixed-top / fixed-bottom items
fixedItems = getElementsByClassName ( HTML , fixedTop ) . concat ( getElementsByClassName ( HTML , fixedBottom ) ) ,
// private methods
getWindowWidth = function ( ) {
var htmlRect = HTML [ getBoundingClientRect ] ( ) ;
return globalObject [ innerWidth ] || ( htmlRect [ right ] - Math . abs ( htmlRect [ left ] ) ) ;
} ,
setScrollbar = function ( ) {
var bodyStyle = globalObject [ getComputedStyle ] ( DOC [ body ] ) ,
bodyPad = parseInt ( ( bodyStyle [ paddingRight ] ) , 10 ) , itemPad ;
if ( bodyIsOverflowing ) {
DOC [ body ] [ style ] [ paddingRight ] = ( bodyPad + scrollbarWidth ) + 'px' ;
if ( fixedItems [ length ] ) {
for ( var i = 0 ; i < fixedItems [ length ] ; i ++ ) {
itemPad = globalObject [ getComputedStyle ] ( fixedItems [ i ] ) [ paddingRight ] ;
fixedItems [ i ] [ style ] [ paddingRight ] = ( parseInt ( itemPad ) + scrollbarWidth ) + 'px' ;
}
}
}
} ,
resetScrollbar = function ( ) {
DOC [ body ] [ style ] [ paddingRight ] = '' ;
if ( fixedItems [ length ] ) {
for ( var i = 0 ; i < fixedItems [ length ] ; i ++ ) {
fixedItems [ i ] [ style ] [ paddingRight ] = '' ;
}
}
} ,
measureScrollbar = function ( ) { // thx walsh
var scrollDiv = DOC [ createElement ] ( 'div' ) , scrollBarWidth ;
scrollDiv . className = component + '-scrollbar-measure' ; // this is here to stay
DOC [ body ] [ appendChild ] ( scrollDiv ) ;
scrollBarWidth = scrollDiv [ offsetWidth ] - scrollDiv [ clientWidth ] ;
DOC [ body ] . removeChild ( scrollDiv ) ;
return scrollBarWidth ;
} ,
checkScrollbar = function ( ) {
bodyIsOverflowing = DOC [ body ] [ clientWidth ] < getWindowWidth ( ) ;
modalIsOverflowing = modal [ scrollHeight ] > HTML [ clientHeight ] ;
scrollbarWidth = measureScrollbar ( ) ;
} ,
adjustDialog = function ( ) {
modal [ style ] [ paddingLeft ] = ! bodyIsOverflowing && modalIsOverflowing ? scrollbarWidth + 'px' : '' ;
modal [ style ] [ paddingRight ] = bodyIsOverflowing && ! modalIsOverflowing ? scrollbarWidth + 'px' : '' ;
} ,
resetAdjustments = function ( ) {
modal [ style ] [ paddingLeft ] = '' ;
modal [ style ] [ paddingRight ] = '' ;
} ,
createOverlay = function ( ) {
modalOverlay = 1 ;
var newOverlay = DOC [ createElement ] ( 'div' ) ;
overlay = queryElement ( '.' + modalBackdropString ) ;
if ( overlay === null ) {
newOverlay [ setAttribute ] ( 'class' , modalBackdropString + ' fade' ) ;
overlay = newOverlay ;
DOC [ body ] [ appendChild ] ( overlay ) ;
}
} ,
removeOverlay = function ( ) {
overlay = queryElement ( '.' + modalBackdropString ) ;
if ( overlay && overlay !== null && typeof overlay === 'object' ) {
modalOverlay = 0 ;
DOC [ body ] . removeChild ( overlay ) ; overlay = null ;
}
bootstrapCustomEvent . call ( modal , hiddenEvent , component ) ;
} ,
keydownHandlerToggle = function ( ) {
if ( hasClass ( modal , showClass ) ) {
on ( DOC , keydownEvent , keyHandler ) ;
} else {
off ( DOC , keydownEvent , keyHandler ) ;
}
} ,
resizeHandlerToggle = function ( ) {
if ( hasClass ( modal , showClass ) ) {
on ( globalObject , resizeEvent , self . update ) ;
} else {
off ( globalObject , resizeEvent , self . update ) ;
}
} ,
dismissHandlerToggle = function ( ) {
if ( hasClass ( modal , showClass ) ) {
on ( modal , clickEvent , dismissHandler ) ;
} else {
off ( modal , clickEvent , dismissHandler ) ;
}
} ,
// triggers
triggerShow = function ( ) {
setFocus ( modal ) ;
bootstrapCustomEvent . call ( modal , shownEvent , component , relatedTarget ) ;
} ,
triggerHide = function ( ) {
modal [ style ] . display = '' ;
element && ( setFocus ( element ) ) ;
( function ( ) {
if ( ! getElementsByClassName ( DOC , component + ' ' + showClass ) [ 0 ] ) {
resetAdjustments ( ) ;
resetScrollbar ( ) ;
removeClass ( DOC [ body ] , component + '-open' ) ;
overlay && hasClass ( overlay , 'fade' ) ? ( removeClass ( overlay , showClass ) , emulateTransitionEnd ( overlay , removeOverlay ) )
: removeOverlay ( ) ;
resizeHandlerToggle ( ) ;
dismissHandlerToggle ( ) ;
keydownHandlerToggle ( ) ;
}
} ( ) ) ;
} ,
// handlers
clickHandler = function ( e ) {
var clickTarget = e [ target ] ;
clickTarget = clickTarget [ hasAttribute ] ( dataTarget ) || clickTarget [ hasAttribute ] ( 'href' ) ? clickTarget : clickTarget [ parentNode ] ;
if ( clickTarget === element && ! hasClass ( modal , showClass ) ) {
modal . modalTrigger = element ;
relatedTarget = element ;
self . show ( ) ;
e [ preventDefault ] ( ) ;
}
} ,
keyHandler = function ( e ) {
if ( self [ keyboard ] && e . which == 27 && hasClass ( modal , showClass ) ) {
self . hide ( ) ;
}
} ,
dismissHandler = function ( e ) {
var clickTarget = e [ target ] ;
if ( hasClass ( modal , showClass ) && ( clickTarget [ parentNode ] [ getAttribute ] ( dataDismiss ) === component
|| clickTarget [ getAttribute ] ( dataDismiss ) === component
|| ( clickTarget === modal && self [ backdrop ] !== staticString ) ) ) {
self . hide ( ) ; relatedTarget = null ;
e [ preventDefault ] ( ) ;
}
} ;
// public methods
this . toggle = function ( ) {
if ( hasClass ( modal , showClass ) ) { this . hide ( ) ; } else { this . show ( ) ; }
} ;
this . show = function ( ) {
bootstrapCustomEvent . call ( modal , showEvent , component , relatedTarget ) ;
// we elegantly hide any opened modal
var currentOpen = getElementsByClassName ( DOC , component + ' ' + showClass ) [ 0 ] ;
currentOpen && currentOpen !== modal && currentOpen . modalTrigger [ stringModal ] . hide ( ) ;
if ( this [ backdrop ] ) {
! modalOverlay && createOverlay ( ) ;
}
if ( overlay && modalOverlay && ! hasClass ( overlay , showClass ) ) {
overlay [ offsetWidth ] ; // force reflow to enable trasition
overlayDelay = getTransitionDurationFromElement ( overlay ) ;
addClass ( overlay , showClass ) ;
}
setTimeout ( function ( ) {
modal [ style ] . display = 'block' ;
checkScrollbar ( ) ;
setScrollbar ( ) ;
adjustDialog ( ) ;
addClass ( DOC [ body ] , component + '-open' ) ;
addClass ( modal , showClass ) ;
modal [ setAttribute ] ( ariaHidden , false ) ;
resizeHandlerToggle ( ) ;
dismissHandlerToggle ( ) ;
keydownHandlerToggle ( ) ;
hasClass ( modal , 'fade' ) ? emulateTransitionEnd ( modal , triggerShow ) : triggerShow ( ) ;
} , supportTransitions && overlay ? overlayDelay : 0 ) ;
} ;
this . hide = function ( ) {
bootstrapCustomEvent . call ( modal , hideEvent , component ) ;
overlay = queryElement ( '.' + modalBackdropString ) ;
overlayDelay = overlay && getTransitionDurationFromElement ( overlay ) ;
removeClass ( modal , showClass ) ;
modal [ setAttribute ] ( ariaHidden , true ) ;
setTimeout ( function ( ) {
hasClass ( modal , 'fade' ) ? emulateTransitionEnd ( modal , triggerHide ) : triggerHide ( ) ;
} , supportTransitions && overlay ? overlayDelay : 0 ) ;
} ;
this . setContent = function ( content ) {
queryElement ( '.' + component + '-content' , modal ) [ innerHTML ] = content ;
} ;
this . update = function ( ) {
if ( hasClass ( modal , showClass ) ) {
checkScrollbar ( ) ;
setScrollbar ( ) ;
adjustDialog ( ) ;
}
} ;
// init
// prevent adding event handlers over and over
// modal is independent of a triggering element
if ( ! ! element && ! ( stringModal in element ) ) {
on ( element , clickEvent , clickHandler ) ;
}
if ( ! ! self [ content ] ) { self . setContent ( self [ content ] ) ; }
! ! element && ( element [ stringModal ] = self ) ;
} ;
// DATA API
supports [ push ] ( [ stringModal , Modal , '[' + dataToggle + '="modal"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | P o p o v e r
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
// POPOVER DEFINITION
// ==================
var Popover = function ( element , options ) {
// initialization element
element = queryElement ( element ) ;
// set options
options = options || { } ;
// DATA API
var triggerData = element [ getAttribute ] ( dataTrigger ) , // click / hover / focus
animationData = element [ getAttribute ] ( dataAnimation ) , // true / false
placementData = element [ getAttribute ] ( dataPlacement ) ,
dismissibleData = element [ getAttribute ] ( dataDismissible ) ,
delayData = element [ getAttribute ] ( dataDelay ) ,
containerData = element [ getAttribute ] ( dataContainer ) ,
// internal strings
component = 'popover' ,
template = 'template' ,
trigger = 'trigger' ,
classString = 'class' ,
div = 'div' ,
fade = 'fade' ,
content = 'content' ,
dataContent = 'data-content' ,
dismissible = 'dismissible' ,
closeBtn = '<button type="button" class="close">× </button>' ,
// check container
containerElement = queryElement ( options [ container ] ) ,
containerDataElement = queryElement ( containerData ) ,
// maybe the element is inside a modal
modal = getClosest ( element , '.modal' ) ,
// maybe the element is inside a fixed navbar
navbarFixedTop = getClosest ( element , '.' + fixedTop ) ,
navbarFixedBottom = getClosest ( element , '.' + fixedBottom ) ;
// set instance options
this [ template ] = options [ template ] ? options [ template ] : null ; // JavaScript only
this [ trigger ] = options [ trigger ] ? options [ trigger ] : triggerData || hoverEvent ;
this [ animation ] = options [ animation ] && options [ animation ] !== fade ? options [ animation ] : animationData || fade ;
this [ placement ] = options [ placement ] ? options [ placement ] : placementData || top ;
this [ delay ] = parseInt ( options [ delay ] || delayData ) || 200 ;
this [ dismissible ] = options [ dismissible ] || dismissibleData === 'true' ? true : false ;
this [ container ] = containerElement ? containerElement
: containerDataElement ? containerDataElement
: navbarFixedTop ? navbarFixedTop
: navbarFixedBottom ? navbarFixedBottom
: modal ? modal : DOC [ body ] ;
// bind, content
var self = this ,
titleString = element [ getAttribute ] ( dataTitle ) || null ,
contentString = element [ getAttribute ] ( dataContent ) || null ;
if ( ! contentString && ! this [ template ] ) return ; // invalidate
// constants, vars
var popover = null , timer = 0 , placementSetting = this [ placement ] ,
// handlers
dismissibleHandler = function ( e ) {
if ( popover !== null && e [ target ] === queryElement ( '.close' , popover ) ) {
self . hide ( ) ;
}
} ,
// private methods
removePopover = function ( ) {
self [ container ] . removeChild ( popover ) ;
timer = null ; popover = null ;
} ,
createPopover = function ( ) {
titleString = element [ getAttribute ] ( dataTitle ) ; // check content again
contentString = element [ getAttribute ] ( dataContent ) ;
popover = DOC [ createElement ] ( div ) ;
// popover arrow
var popoverArrow = DOC [ createElement ] ( div ) ;
popoverArrow [ setAttribute ] ( classString , 'arrow' ) ;
popover [ appendChild ] ( popoverArrow ) ;
if ( contentString !== null && self [ template ] === null ) { //create the popover from data attributes
popover [ setAttribute ] ( 'role' , 'tooltip' ) ;
if ( titleString !== null ) {
var popoverTitle = DOC [ createElement ] ( 'h3' ) ;
popoverTitle [ setAttribute ] ( classString , component + '-header' ) ;
popoverTitle [ innerHTML ] = self [ dismissible ] ? titleString + closeBtn : titleString ;
popover [ appendChild ] ( popoverTitle ) ;
}
//set popover content
var popoverContent = DOC [ createElement ] ( div ) ;
popoverContent [ setAttribute ] ( classString , component + '-body' ) ;
popoverContent [ innerHTML ] = self [ dismissible ] && titleString === null ? contentString + closeBtn : contentString ;
popover [ appendChild ] ( popoverContent ) ;
} else { // or create the popover from template
var popoverTemplate = DOC [ createElement ] ( div ) ;
popoverTemplate [ innerHTML ] = self [ template ] ;
popover [ innerHTML ] = popoverTemplate . firstChild [ innerHTML ] ;
}
//append to the container
self [ container ] [ appendChild ] ( popover ) ;
popover [ style ] . display = 'block' ;
popover [ setAttribute ] ( classString , component + ' bs-' + component + '-' + placementSetting + ' ' + self [ animation ] ) ;
} ,
showPopover = function ( ) {
! hasClass ( popover , showClass ) && ( addClass ( popover , showClass ) ) ;
} ,
updatePopover = function ( ) {
styleTip ( element , popover , placementSetting , self [ container ] ) ;
} ,
// event toggle
dismissHandlerToggle = function ( type ) {
if ( clickEvent == self [ trigger ] || 'focus' == self [ trigger ] ) {
! self [ dismissible ] && type ( element , 'blur' , self . hide ) ;
}
self [ dismissible ] && type ( DOC , clickEvent , dismissibleHandler ) ;
type ( globalObject , resizeEvent , self . hide ) ;
} ,
// triggers
showTrigger = function ( ) {
dismissHandlerToggle ( on ) ;
bootstrapCustomEvent . call ( element , shownEvent , component ) ;
} ,
hideTrigger = function ( ) {
dismissHandlerToggle ( off ) ;
removePopover ( ) ;
bootstrapCustomEvent . call ( element , hiddenEvent , component ) ;
} ;
// public methods / handlers
this . toggle = function ( ) {
if ( popover === null ) { self . show ( ) ; }
else { self . hide ( ) ; }
} ;
this . show = function ( ) {
clearTimeout ( timer ) ;
timer = setTimeout ( function ( ) {
if ( popover === null ) {
placementSetting = self [ placement ] ; // we reset placement in all cases
createPopover ( ) ;
updatePopover ( ) ;
showPopover ( ) ;
bootstrapCustomEvent . call ( element , showEvent , component ) ;
! ! self [ animation ] ? emulateTransitionEnd ( popover , showTrigger ) : showTrigger ( ) ;
}
} , 20 ) ;
} ;
this . hide = function ( ) {
clearTimeout ( timer ) ;
timer = setTimeout ( function ( ) {
if ( popover && popover !== null && hasClass ( popover , showClass ) ) {
bootstrapCustomEvent . call ( element , hideEvent , component ) ;
removeClass ( popover , showClass ) ;
! ! self [ animation ] ? emulateTransitionEnd ( popover , hideTrigger ) : hideTrigger ( ) ;
}
} , self [ delay ] ) ;
} ;
// init
if ( ! ( stringPopover in element ) ) { // prevent adding event handlers twice
if ( self [ trigger ] === hoverEvent ) {
on ( element , mouseHover [ 0 ] , self . show ) ;
if ( ! self [ dismissible ] ) { on ( element , mouseHover [ 1 ] , self . hide ) ; }
} else if ( clickEvent == self [ trigger ] || 'focus' == self [ trigger ] ) {
on ( element , self [ trigger ] , self . toggle ) ;
}
}
element [ stringPopover ] = self ;
} ;
// POPOVER DATA API
// ================
supports [ push ] ( [ stringPopover , Popover , '[' + dataToggle + '="popover"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | S c r o l l S p y
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// SCROLLSPY DEFINITION
// ====================
var ScrollSpy = function ( element , options ) {
// initialization element, the element we spy on
element = queryElement ( element ) ;
// DATA API
var targetData = queryElement ( element [ getAttribute ] ( dataTarget ) ) ,
offsetData = element [ getAttribute ] ( 'data-offset' ) ;
// set options
options = options || { } ;
if ( ! options [ target ] && ! targetData ) { return ; } // invalidate
// event targets, constants
var self = this , spyTarget = options [ target ] && queryElement ( options [ target ] ) || targetData ,
links = spyTarget && spyTarget [ getElementsByTagName ] ( 'A' ) ,
offset = parseInt ( offsetData || options [ 'offset' ] ) || 10 ,
items = [ ] , targetItems = [ ] , scrollOffset ,
scrollTarget = element [ offsetHeight ] < element [ scrollHeight ] ? element : globalObject , // determine which is the real scrollTarget
isWindow = scrollTarget === globalObject ;
// populate items and targets
for ( var i = 0 , il = links [ length ] ; i < il ; i ++ ) {
var href = links [ i ] [ getAttribute ] ( 'href' ) ,
targetItem = href && href . charAt ( 0 ) === '#' && href . slice ( - 1 ) !== '#' && queryElement ( href ) ;
if ( ! ! targetItem ) {
items [ push ] ( links [ i ] ) ;
targetItems [ push ] ( targetItem ) ;
}
}
// private methods
var updateItem = function ( index ) {
var item = items [ index ] ,
targetItem = targetItems [ index ] , // the menu item targets this element
dropdown = item [ parentNode ] [ parentNode ] ,
dropdownLink = hasClass ( dropdown , 'dropdown' ) && dropdown [ getElementsByTagName ] ( 'A' ) [ 0 ] ,
targetRect = isWindow && targetItem [ getBoundingClientRect ] ( ) ,
isActive = hasClass ( item , active ) || false ,
topEdge = ( isWindow ? targetRect [ top ] + scrollOffset : targetItem [ offsetTop ] ) - offset ,
bottomEdge = isWindow ? targetRect [ bottom ] + scrollOffset - offset : targetItems [ index + 1 ] ? targetItems [ index + 1 ] [ offsetTop ] - offset : element [ scrollHeight ] ,
inside = scrollOffset >= topEdge && bottomEdge > scrollOffset ;
if ( ! isActive && inside ) {
if ( ! hasClass ( item , active ) ) {
addClass ( item , active ) ;
if ( dropdownLink && ! hasClass ( dropdownLink , active ) ) {
addClass ( dropdownLink , active ) ;
}
bootstrapCustomEvent . call ( element , 'activate' , 'scrollspy' , items [ index ] ) ;
}
} else if ( ! inside ) {
if ( hasClass ( item , active ) ) {
removeClass ( item , active ) ;
if ( dropdownLink && hasClass ( dropdownLink , active ) && ! getElementsByClassName ( item [ parentNode ] , active ) . length ) {
removeClass ( dropdownLink , active ) ;
}
}
} else if ( ! inside && ! isActive || isActive && inside ) {
return ;
}
} ,
updateItems = function ( ) {
scrollOffset = isWindow ? getScroll ( ) . y : element [ scrollTop ] ;
for ( var index = 0 , itl = items [ length ] ; index < itl ; index ++ ) {
updateItem ( index )
}
} ;
// public method
this . refresh = function ( ) {
updateItems ( ) ;
}
// init
if ( ! ( stringScrollSpy in element ) ) { // prevent adding event handlers twice
on ( scrollTarget , scrollEvent , self . refresh ) ;
on ( globalObject , resizeEvent , self . refresh ) ;
}
self . refresh ( ) ;
element [ stringScrollSpy ] = self ;
} ;
// SCROLLSPY DATA API
// ==================
supports [ push ] ( [ stringScrollSpy , ScrollSpy , '[' + dataSpy + '="scroll"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | T a b
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// TAB DEFINITION
// ==============
var Tab = function ( element , options ) {
// initialization element
element = queryElement ( element ) ;
// DATA API
var heightData = element [ getAttribute ] ( dataHeight ) ,
// strings
component = 'tab' , height = 'height' , float = 'float' , isAnimating = 'isAnimating' ;
// set options
options = options || { } ;
this [ height ] = supportTransitions ? ( options [ height ] || heightData === 'true' ) : false ;
// bind, event targets
var self = this , next ,
tabs = getClosest ( element , '.nav' ) ,
tabsContentContainer = false ,
dropdown = tabs && queryElement ( '.dropdown-toggle' , tabs ) ,
activeTab , activeContent , nextContent , containerHeight , equalContents , nextHeight ,
// trigger
triggerEnd = function ( ) {
tabsContentContainer [ style ] [ height ] = '' ;
removeClass ( tabsContentContainer , collapsing ) ;
tabs [ isAnimating ] = false ;
} ,
triggerShow = function ( ) {
if ( tabsContentContainer ) { // height animation
if ( equalContents ) {
triggerEnd ( ) ;
} else {
setTimeout ( function ( ) { // enables height animation
tabsContentContainer [ style ] [ height ] = nextHeight + 'px' ; // height animation
tabsContentContainer [ offsetWidth ] ;
emulateTransitionEnd ( tabsContentContainer , triggerEnd ) ;
} , 50 ) ;
}
} else {
tabs [ isAnimating ] = false ;
}
bootstrapCustomEvent . call ( next , shownEvent , component , activeTab ) ;
} ,
triggerHide = function ( ) {
if ( tabsContentContainer ) {
activeContent [ style ] [ float ] = left ;
nextContent [ style ] [ float ] = left ;
containerHeight = activeContent [ scrollHeight ] ;
}
addClass ( nextContent , active ) ;
bootstrapCustomEvent . call ( next , showEvent , component , activeTab ) ;
removeClass ( activeContent , active ) ;
bootstrapCustomEvent . call ( activeTab , hiddenEvent , component , next ) ;
if ( tabsContentContainer ) {
nextHeight = nextContent [ scrollHeight ] ;
equalContents = nextHeight === containerHeight ;
addClass ( tabsContentContainer , collapsing ) ;
tabsContentContainer [ style ] [ height ] = containerHeight + 'px' ; // height animation
tabsContentContainer [ offsetHeight ] ;
activeContent [ style ] [ float ] = '' ;
nextContent [ style ] [ float ] = '' ;
}
if ( hasClass ( nextContent , 'fade' ) ) {
setTimeout ( function ( ) {
addClass ( nextContent , showClass ) ;
emulateTransitionEnd ( nextContent , triggerShow ) ;
} , 20 ) ;
} else { triggerShow ( ) ; }
} ;
if ( ! tabs ) return ; // invalidate
// set default animation state
tabs [ isAnimating ] = false ;
// private methods
var getActiveTab = function ( ) {
var activeTabs = getElementsByClassName ( tabs , active ) , activeTab ;
if ( activeTabs [ length ] === 1 && ! hasClass ( activeTabs [ 0 ] [ parentNode ] , 'dropdown' ) ) {
activeTab = activeTabs [ 0 ] ;
} else if ( activeTabs [ length ] > 1 ) {
activeTab = activeTabs [ activeTabs [ length ] - 1 ] ;
}
return activeTab ;
} ,
getActiveContent = function ( ) {
return queryElement ( getActiveTab ( ) [ getAttribute ] ( 'href' ) ) ;
} ,
// handler
clickHandler = function ( e ) {
var href = e [ target ] [ getAttribute ] ( 'href' ) ;
e [ preventDefault ] ( ) ;
next = e [ target ] [ getAttribute ] ( dataToggle ) === component || ( href && href . charAt ( 0 ) === '#' )
? e [ target ] : e [ target ] [ parentNode ] ; // allow for child elements like icons to use the handler
! tabs [ isAnimating ] && ! hasClass ( next , active ) && self . show ( ) ;
} ;
// public method
this . show = function ( ) { // the tab we clicked is now the next tab
next = next || element ;
nextContent = queryElement ( next [ getAttribute ] ( 'href' ) ) ; //this is the actual object, the next tab content to activate
activeTab = getActiveTab ( ) ;
activeContent = getActiveContent ( ) ;
tabs [ isAnimating ] = true ;
removeClass ( activeTab , active ) ;
addClass ( next , active ) ;
if ( dropdown ) {
if ( ! hasClass ( element [ parentNode ] , 'dropdown-menu' ) ) {
if ( hasClass ( dropdown , active ) ) removeClass ( dropdown , active ) ;
} else {
if ( ! hasClass ( dropdown , active ) ) addClass ( dropdown , active ) ;
}
}
bootstrapCustomEvent . call ( activeTab , hideEvent , component , next ) ;
if ( hasClass ( activeContent , 'fade' ) ) {
removeClass ( activeContent , showClass ) ;
emulateTransitionEnd ( activeContent , triggerHide ) ;
} else { triggerHide ( ) ; }
} ;
// init
if ( ! ( stringTab in element ) ) { // prevent adding event handlers twice
on ( element , clickEvent , clickHandler ) ;
}
if ( self [ height ] ) { tabsContentContainer = getActiveContent ( ) [ parentNode ] ; }
element [ stringTab ] = self ;
} ;
// TAB DATA API
// ============
supports [ push ] ( [ stringTab , Tab , '[' + dataToggle + '="tab"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | T o o l t i p
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
// TOOLTIP DEFINITION
// ==================
var Tooltip = function ( element , options ) {
// initialization element
element = queryElement ( element ) ;
// set options
options = options || { } ;
// DATA API
var animationData = element [ getAttribute ] ( dataAnimation ) ,
placementData = element [ getAttribute ] ( dataPlacement ) ,
delayData = element [ getAttribute ] ( dataDelay ) ,
containerData = element [ getAttribute ] ( dataContainer ) ,
// strings
component = 'tooltip' ,
classString = 'class' ,
title = 'title' ,
fade = 'fade' ,
div = 'div' ,
// check container
containerElement = queryElement ( options [ container ] ) ,
containerDataElement = queryElement ( containerData ) ,
// maybe the element is inside a modal
modal = getClosest ( element , '.modal' ) ,
// maybe the element is inside a fixed navbar
navbarFixedTop = getClosest ( element , '.' + fixedTop ) ,
navbarFixedBottom = getClosest ( element , '.' + fixedBottom ) ;
// set instance options
this [ animation ] = options [ animation ] && options [ animation ] !== fade ? options [ animation ] : animationData || fade ;
this [ placement ] = options [ placement ] ? options [ placement ] : placementData || top ;
this [ delay ] = parseInt ( options [ delay ] || delayData ) || 200 ;
this [ container ] = containerElement ? containerElement
: containerDataElement ? containerDataElement
: navbarFixedTop ? navbarFixedTop
: navbarFixedBottom ? navbarFixedBottom
: modal ? modal : DOC [ body ] ;
// bind, event targets, title and constants
var self = this , timer = 0 , placementSetting = this [ placement ] , tooltip = null ,
titleString = element [ getAttribute ] ( title ) || element [ getAttribute ] ( dataTitle ) || element [ getAttribute ] ( dataOriginalTitle ) ;
if ( ! titleString || titleString == "" ) return ; // invalidate
// private methods
var removeToolTip = function ( ) {
self [ container ] . removeChild ( tooltip ) ;
tooltip = null ; timer = null ;
} ,
createToolTip = function ( ) {
titleString = element [ getAttribute ] ( title ) || element [ getAttribute ] ( dataTitle ) || element [ getAttribute ] ( dataOriginalTitle ) ; // read the title again
if ( ! titleString || titleString == "" ) return false ; // invalidate
tooltip = DOC [ createElement ] ( div ) ;
tooltip [ setAttribute ] ( 'role' , component ) ;
// tooltip arrow
var tooltipArrow = DOC [ createElement ] ( div ) ;
tooltipArrow [ setAttribute ] ( classString , 'arrow' ) ;
tooltip [ appendChild ] ( tooltipArrow ) ;
var tooltipInner = DOC [ createElement ] ( div ) ;
tooltipInner [ setAttribute ] ( classString , component + '-inner' ) ;
tooltip [ appendChild ] ( tooltipInner ) ;
tooltipInner [ innerHTML ] = titleString ;
self [ container ] [ appendChild ] ( tooltip ) ;
tooltip [ setAttribute ] ( classString , component + ' bs-' + component + '-' + placementSetting + ' ' + self [ animation ] ) ;
} ,
updateTooltip = function ( ) {
styleTip ( element , tooltip , placementSetting , self [ container ] ) ;
} ,
showTooltip = function ( ) {
! hasClass ( tooltip , showClass ) && ( addClass ( tooltip , showClass ) ) ;
} ,
// triggers
showTrigger = function ( ) {
on ( globalObject , resizeEvent , self . hide ) ;
bootstrapCustomEvent . call ( element , shownEvent , component ) ;
} ,
hideTrigger = function ( ) {
off ( globalObject , resizeEvent , self . hide ) ;
removeToolTip ( ) ;
bootstrapCustomEvent . call ( element , hiddenEvent , component ) ;
} ;
// public methods
this . show = function ( ) {
clearTimeout ( timer ) ;
timer = setTimeout ( function ( ) {
if ( tooltip === null ) {
placementSetting = self [ placement ] ; // we reset placement in all cases
if ( createToolTip ( ) == false ) return ;
updateTooltip ( ) ;
showTooltip ( ) ;
bootstrapCustomEvent . call ( element , showEvent , component ) ;
! ! self [ animation ] ? emulateTransitionEnd ( tooltip , showTrigger ) : showTrigger ( ) ;
}
} , 20 ) ;
} ;
this . hide = function ( ) {
clearTimeout ( timer ) ;
timer = setTimeout ( function ( ) {
if ( tooltip && hasClass ( tooltip , showClass ) ) {
bootstrapCustomEvent . call ( element , hideEvent , component ) ;
removeClass ( tooltip , showClass ) ;
! ! self [ animation ] ? emulateTransitionEnd ( tooltip , hideTrigger ) : hideTrigger ( ) ;
}
} , self [ delay ] ) ;
} ;
this . toggle = function ( ) {
if ( ! tooltip ) { self . show ( ) ; }
else { self . hide ( ) ; }
} ;
// init
if ( ! ( stringTooltip in element ) ) { // prevent adding event handlers twice
element [ setAttribute ] ( dataOriginalTitle , titleString ) ;
element . removeAttribute ( title ) ;
on ( element , mouseHover [ 0 ] , self . show ) ;
on ( element , mouseHover [ 1 ] , self . hide ) ;
}
element [ stringTooltip ] = self ;
} ;
// TOOLTIP DATA API
// =================
supports [ push ] ( [ stringTooltip , Tooltip , '[' + dataToggle + '="tooltip"]' ] ) ;
/ * N a t i v e J a v a s c r i p t f o r B o o t s t r a p 4 | I n i t i a l i z e D a t a A P I
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
var initializeDataAPI = function ( constructor , collection ) {
for ( var i = 0 , l = collection [ length ] ; i < l ; i ++ ) {
new constructor ( collection [ i ] ) ;
}
} ,
initCallback = BSN . initCallback = function ( lookUp ) {
lookUp = lookUp || DOC ;
for ( var i = 0 , l = supports [ length ] ; i < l ; i ++ ) {
initializeDataAPI ( supports [ i ] [ 1 ] , lookUp [ querySelectorAll ] ( supports [ i ] [ 2 ] ) ) ;
}
} ;
// bulk initialize all components
DOC [ body ] ? initCallback ( ) : on ( DOC , 'DOMContentLoaded' , function ( ) { initCallback ( ) ; } ) ;
return {
Alert : Alert ,
Button : Button ,
Carousel : Carousel ,
Collapse : Collapse ,
Dropdown : Dropdown ,
Modal : Modal ,
Popover : Popover ,
ScrollSpy : ScrollSpy ,
Tab : Tab ,
Tooltip : Tooltip
} ;
} ) ) ;