// Native Javascript for Bootstrap 4 v2.0.24 | © dnp_theme | MIT-License (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 () { /* Native Javascript for Bootstrap 4 | Internal Utility Functions ----------------------------------------------------------------*/ "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 // 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'); }; BSN.version = '2.0.24'; /* Native Javascript for Bootstrap 4 | Alert -------------------------------------------*/ // 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"]']); /* Native Javascript for Bootstrap 4 | Button ---------------------------------------------*/ // 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= 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; // 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 ) ) { 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"]' ] ); /* Native Javascript for Bootstrap 4 | Collapse -----------------------------------------------*/ // 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"]' ] ); /* Native Javascript for Bootstrap 4 | Dropdown ----------------------------------------------*/ // 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; i1?idx-1:0) : key === 40 ? (idx