|
|
diff --git dist/converse.js dist/converse.js
|
|
|
index 072ebf1..7ebef4d 100644
|
|
|
--- dist/converse.js
|
|
|
+++ dist/converse.js
|
|
|
@@ -17098,1710 +17098,16 @@ module.exports = keys;
|
|
|
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
|
|
} else { var bsn; }
|
|
|
})(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 <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',
|
|
|
- stringToast = 'Toast',
|
|
|
- // options DATA API
|
|
|
- dataAutohide = 'data-autohide',
|
|
|
- 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',
|
|
|
- dataDismissible = 'data-dismissible',
|
|
|
- dataTrigger = 'data-trigger',
|
|
|
- dataAnimation = 'data-animation',
|
|
|
- dataContainer = 'data-container',
|
|
|
- dataPlacement = 'data-placement',
|
|
|
- dataDelay = 'data-delay',
|
|
|
- // option keys
|
|
|
- backdrop = 'backdrop',
|
|
|
- keyboard = 'keyboard',
|
|
|
- delay = 'delay',
|
|
|
- content = 'content',
|
|
|
- target = 'target',
|
|
|
- currentTarget = 'currentTarget',
|
|
|
- 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',
|
|
|
- scrollWidth = 'scrollWidth',
|
|
|
- height = 'height',
|
|
|
- // aria
|
|
|
- ariaExpanded = 'aria-expanded',
|
|
|
- ariaHidden = 'aria-hidden',
|
|
|
- ariaSelected = 'aria-selected',
|
|
|
- // event names
|
|
|
- clickEvent = 'click',
|
|
|
- focusEvent = 'focus',
|
|
|
- hoverEvent = 'hover',
|
|
|
- keydownEvent = 'keydown',
|
|
|
- keyupEvent = 'keyup',
|
|
|
- resizeEvent = 'resize',
|
|
|
- // passive
|
|
|
- scrollEvent = 'scroll',
|
|
|
- // passive
|
|
|
- mouseHover = 'onmouseleave' in DOC ? ['mouseenter', 'mouseleave'] : ['mouseover', 'mouseout'],
|
|
|
- // touch since 2.0.26
|
|
|
- touchEvents = {
|
|
|
- start: 'touchstart',
|
|
|
- end: 'touchend',
|
|
|
- move: 'touchmove'
|
|
|
- },
|
|
|
- // passive
|
|
|
- // 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
|
|
|
- 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 setFocus(element) {
|
|
|
- element.focus ? element.focus() : element.setActive();
|
|
|
- },
|
|
|
- // class manipulation, since 2.0.0 requires polyfill.js
|
|
|
- addClass = function addClass(element, classNAME) {
|
|
|
- element.classList.add(classNAME);
|
|
|
- },
|
|
|
- removeClass = function removeClass(element, classNAME) {
|
|
|
- element.classList.remove(classNAME);
|
|
|
- },
|
|
|
- hasClass = function hasClass(element, classNAME) {
|
|
|
- // since 2.0.0
|
|
|
- return element.classList[contains](classNAME);
|
|
|
- },
|
|
|
- // selection methods
|
|
|
- getElementsByClassName = function getElementsByClassName(element, classNAME) {
|
|
|
- // returns Array
|
|
|
- return [].slice.call(element[getElementsByCLASSNAME](classNAME));
|
|
|
- },
|
|
|
- queryElement = function queryElement(selector, parent) {
|
|
|
- var lookUp = parent ? parent : DOC;
|
|
|
- return typeof selector === 'object' ? selector : lookUp.querySelector(selector);
|
|
|
- },
|
|
|
- getClosest = function getClosest(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 on(element, event, handler, options) {
|
|
|
- options = options || false;
|
|
|
- element.addEventListener(event, handler, options);
|
|
|
- },
|
|
|
- off = function off(element, event, handler, options) {
|
|
|
- options = options || false;
|
|
|
- element.removeEventListener(event, handler, options);
|
|
|
- },
|
|
|
- one = function one(element, event, handler, options) {
|
|
|
- // one since 2.0.4
|
|
|
- on(element, event, function handlerWrapper(e) {
|
|
|
- handler(e);
|
|
|
- off(element, event, handlerWrapper, options);
|
|
|
- }, options);
|
|
|
- },
|
|
|
- // determine support for passive events
|
|
|
- supportPassive = function () {
|
|
|
- // Test via a getter in the options object to see if the passive property is accessed
|
|
|
- var result = false;
|
|
|
-
|
|
|
- try {
|
|
|
- var opts = Object.defineProperty({}, 'passive', {
|
|
|
- get: function get() {
|
|
|
- result = true;
|
|
|
- }
|
|
|
- });
|
|
|
- one(globalObject, 'testPassive', null, opts);
|
|
|
- } catch (e) {}
|
|
|
-
|
|
|
- return result;
|
|
|
- }(),
|
|
|
- // event options
|
|
|
- // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection
|
|
|
- passiveHandler = supportPassive ? {
|
|
|
- passive: true
|
|
|
- } : false,
|
|
|
- // transitions
|
|
|
- getTransitionDurationFromElement = function getTransitionDurationFromElement(element) {
|
|
|
- var duration = supportTransitions ? globalObject[getComputedStyle](element)[transitionDuration] : 0;
|
|
|
- duration = parseFloat(duration);
|
|
|
- duration = typeof duration === 'number' && !isNaN(duration) ? duration * 1000 : 0;
|
|
|
- return duration; // we take a short offset to make sure we fire on the next frame after animation
|
|
|
- },
|
|
|
- emulateTransitionEnd = function emulateTransitionEnd(element, handler) {
|
|
|
- // emulateTransitionEnd since 2.0.4
|
|
|
- var called = 0,
|
|
|
- duration = getTransitionDurationFromElement(element);
|
|
|
- duration ? one(element, transitionEndEvent, function (e) {
|
|
|
- !called && handler(e), called = 1;
|
|
|
- }) : setTimeout(function () {
|
|
|
- !called && handler(), called = 1;
|
|
|
- }, 17);
|
|
|
- },
|
|
|
- bootstrapCustomEvent = function bootstrapCustomEvent(eventName, componentName, related) {
|
|
|
- var OriginalCustomEvent = new CustomEvent(eventName + '.bs.' + componentName);
|
|
|
- OriginalCustomEvent.relatedTarget = related;
|
|
|
- this.dispatchEvent(OriginalCustomEvent);
|
|
|
- },
|
|
|
- // tooltip / popover stuff
|
|
|
- getScroll = function getScroll() {
|
|
|
- // also Affix and ScrollSpy uses it
|
|
|
- return {
|
|
|
- y: globalObject.pageYOffset || HTML[scrollTop],
|
|
|
- x: globalObject.pageXOffset || HTML[scrollLeft]
|
|
|
- };
|
|
|
- },
|
|
|
- styleTip = function styleTip(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 - (isPopover ? arrowWidth : 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.27';
|
|
|
- /* Native Javascript for Bootstrap 4 | Alert
|
|
|
- -------------------------------------------*/
|
|
|
- // ALERT DEFINITION
|
|
|
- // ================
|
|
|
-
|
|
|
- var Alert = function Alert(element) {
|
|
|
- // initialization element
|
|
|
- element = queryElement(element); // bind, target alert, duration and stuff
|
|
|
-
|
|
|
- var self = this,
|
|
|
- component = 'alert',
|
|
|
- alert = getClosest(element, '.' + component),
|
|
|
- triggerHandler = function triggerHandler() {
|
|
|
- hasClass(alert, 'fade') ? emulateTransitionEnd(alert, transitionEndHandler) : transitionEndHandler();
|
|
|
- },
|
|
|
- // handlers
|
|
|
- clickHandler = function clickHandler(e) {
|
|
|
- alert = getClosest(e[target], '.' + component);
|
|
|
- element = queryElement('[' + dataDismiss + '="' + component + '"]', alert);
|
|
|
- element && alert && (element === e[target] || element[contains](e[target])) && self.close();
|
|
|
- },
|
|
|
- transitionEndHandler = function transitionEndHandler() {
|
|
|
- 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 Button(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',
|
|
|
- LABEL = 'LABEL',
|
|
|
- INPUT = 'INPUT',
|
|
|
- // private methods
|
|
|
- keyHandler = function keyHandler(e) {
|
|
|
- var key = e.which || e.keyCode;
|
|
|
- key === 32 && e[target] === DOC.activeElement && toggle(e);
|
|
|
- },
|
|
|
- preventScroll = function preventScroll(e) {
|
|
|
- var key = e.which || e.keyCode;
|
|
|
- key === 32 && e[preventDefault]();
|
|
|
- },
|
|
|
- toggle = function toggle(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 labels = getElementsByClassName(label[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
|
|
|
- // don't trigger if already active (the OR condition is a hack to check if the buttons were selected with key press and NOT mouse click)
|
|
|
- if (!input[checked] || e.screenX === 0 && e.screenY == 0) {
|
|
|
- addClass(label, active);
|
|
|
- addClass(label, focusEvent);
|
|
|
- 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);
|
|
|
- },
|
|
|
- focusHandler = function focusHandler(e) {
|
|
|
- addClass(e[target][parentNode], focusEvent);
|
|
|
- },
|
|
|
- blurHandler = function blurHandler(e) {
|
|
|
- removeClass(e[target][parentNode], focusEvent);
|
|
|
- }; // init
|
|
|
-
|
|
|
-
|
|
|
- if (!(stringButton in element)) {
|
|
|
- // prevent adding event handlers twice
|
|
|
- on(element, clickEvent, toggle);
|
|
|
- on(element, keyupEvent, keyHandler), on(element, keydownEvent, preventScroll);
|
|
|
- var allBtns = getElementsByClassName(element, 'btn');
|
|
|
-
|
|
|
- for (var i = 0; i < allBtns.length; i++) {
|
|
|
- var input = allBtns[i][getElementsByTagName](INPUT)[0];
|
|
|
- on(input, focusEvent, focusHandler), on(input, 'blur', blurHandler);
|
|
|
- }
|
|
|
- } // 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"]']);
|
|
|
- /* Native Javascript for Bootstrap 4 | Collapse
|
|
|
- -----------------------------------------------*/
|
|
|
- // COLLAPSE DEFINITION
|
|
|
- // ===================
|
|
|
-
|
|
|
- var Collapse = function Collapse(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 openAction(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 closeAction(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 getTarget() {
|
|
|
- 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('[' + dataTarget + '="#' + activeCollapse.id + '"]', accordion) || queryElement('[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 Dropdown(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++) {
|
|
|
- set[i][children][length] && set[i][children][0].tagName === 'A' && newSet[push](set[i][children][0]);
|
|
|
- set[i].tagName === 'A' && newSet[push](set[i]);
|
|
|
- }
|
|
|
-
|
|
|
- return newSet;
|
|
|
- }(),
|
|
|
- // preventDefault on empty anchor links
|
|
|
- preventEmptyAnchor = function preventEmptyAnchor(anchor) {
|
|
|
- (anchor.href && anchor.href.slice(-1) === '#' || anchor[parentNode] && anchor[parentNode].href && anchor[parentNode].href.slice(-1) === '#') && this[preventDefault]();
|
|
|
- },
|
|
|
- // toggle dismissible events
|
|
|
- toggleDismiss = function toggleDismiss() {
|
|
|
- var type = element[open] ? on : off;
|
|
|
- type(DOC, clickEvent, dismissHandler);
|
|
|
- type(DOC, keydownEvent, preventScroll);
|
|
|
- type(DOC, keyupEvent, keyHandler);
|
|
|
- type(DOC, focusEvent, dismissHandler, true);
|
|
|
- },
|
|
|
- // handlers
|
|
|
- dismissHandler = function dismissHandler(e) {
|
|
|
- var eventTarget = e[target],
|
|
|
- hasData = eventTarget && (eventTarget[getAttribute](dataToggle) || eventTarget[parentNode] && getAttribute in eventTarget[parentNode] && eventTarget[parentNode][getAttribute](dataToggle));
|
|
|
-
|
|
|
- if (e.type === focusEvent && (eventTarget === element || eventTarget === menu || menu[contains](eventTarget))) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- 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 clickHandler(e) {
|
|
|
- relatedTarget = element;
|
|
|
- show();
|
|
|
- preventEmptyAnchor.call(e, e[target]);
|
|
|
- },
|
|
|
- preventScroll = function preventScroll(e) {
|
|
|
- var key = e.which || e.keyCode;
|
|
|
-
|
|
|
- if (key === 38 || key === 40) {
|
|
|
- e[preventDefault]();
|
|
|
- }
|
|
|
- },
|
|
|
- keyHandler = function keyHandler(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) {
|
|
|
- // navigate up | down
|
|
|
- idx = isSameElement ? 0 : key === 38 ? idx > 1 ? idx - 1 : 0 : key === 40 ? idx < menuItems[length] - 1 ? idx + 1 : idx : idx;
|
|
|
- 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 show() {
|
|
|
- bootstrapCustomEvent.call(parent, showEvent, component, relatedTarget);
|
|
|
- addClass(menu, showClass);
|
|
|
- addClass(parent, showClass);
|
|
|
- element[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 hide() {
|
|
|
- bootstrapCustomEvent.call(parent, hideEvent, component, relatedTarget);
|
|
|
- removeClass(menu, showClass);
|
|
|
- removeClass(parent, showClass);
|
|
|
- element[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"]']);
|
|
|
- /* Native Javascript for Bootstrap 4 | Modal
|
|
|
- -------------------------------------------*/
|
|
|
- // MODAL DEFINITION
|
|
|
- // ===============
|
|
|
-
|
|
|
- var Modal = function Modal(element, options) {
|
|
|
- // element can be the modal/triggering button
|
|
|
- // the modal (both JavaScript / DATA API init) / triggering button element (DATA API)
|
|
|
- element = queryElement(element); // strings
|
|
|
-
|
|
|
- var component = 'modal',
|
|
|
- staticString = 'static',
|
|
|
- modalTrigger = 'modalTrigger',
|
|
|
- paddingRight = 'paddingRight',
|
|
|
- modalBackdropString = 'modal-backdrop',
|
|
|
- isAnimating = 'isAnimating',
|
|
|
- // determine modal, triggering element
|
|
|
- btnCheck = element[getAttribute](dataTarget) || element[getAttribute]('href'),
|
|
|
- checkModal = queryElement(btnCheck),
|
|
|
- modal = hasClass(element, component) ? element : checkModal;
|
|
|
-
|
|
|
- if (hasClass(element, component)) {
|
|
|
- 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[animation] = hasClass(modal, 'fade') ? true : false;
|
|
|
- this[content] = options[content]; // JavaScript only
|
|
|
- // set an initial state of the modal
|
|
|
-
|
|
|
- modal[isAnimating] = false; // bind, constants, event targets and other vars
|
|
|
-
|
|
|
- var self = this,
|
|
|
- relatedTarget = null,
|
|
|
- bodyIsOverflowing,
|
|
|
- scrollBarWidth,
|
|
|
- overlay,
|
|
|
- overlayDelay,
|
|
|
- modalTimer,
|
|
|
- // also find fixed-top / fixed-bottom items
|
|
|
- fixedItems = getElementsByClassName(HTML, fixedTop).concat(getElementsByClassName(HTML, fixedBottom)),
|
|
|
- // private methods
|
|
|
- getWindowWidth = function getWindowWidth() {
|
|
|
- var htmlRect = HTML[getBoundingClientRect]();
|
|
|
- return globalObject[innerWidth] || htmlRect[right] - Math.abs(htmlRect[left]);
|
|
|
- },
|
|
|
- setScrollbar = function setScrollbar() {
|
|
|
- var bodyStyle = globalObject[getComputedStyle](DOC[body]),
|
|
|
- bodyPad = parseInt(bodyStyle[paddingRight], 10),
|
|
|
- itemPad;
|
|
|
-
|
|
|
- if (bodyIsOverflowing) {
|
|
|
- DOC[body][style][paddingRight] = bodyPad + scrollBarWidth + 'px';
|
|
|
- modal[style][paddingRight] = 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 resetScrollbar() {
|
|
|
- DOC[body][style][paddingRight] = '';
|
|
|
- modal[style][paddingRight] = '';
|
|
|
-
|
|
|
- if (fixedItems[length]) {
|
|
|
- for (var i = 0; i < fixedItems[length]; i++) {
|
|
|
- fixedItems[i][style][paddingRight] = '';
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- measureScrollbar = function measureScrollbar() {
|
|
|
- // thx walsh
|
|
|
- var scrollDiv = DOC[createElement]('div'),
|
|
|
- widthValue;
|
|
|
- scrollDiv.className = component + '-scrollbar-measure'; // this is here to stay
|
|
|
-
|
|
|
- DOC[body][appendChild](scrollDiv);
|
|
|
- widthValue = scrollDiv[offsetWidth] - scrollDiv[clientWidth];
|
|
|
- DOC[body].removeChild(scrollDiv);
|
|
|
- return widthValue;
|
|
|
- },
|
|
|
- checkScrollbar = function checkScrollbar() {
|
|
|
- bodyIsOverflowing = DOC[body][clientWidth] < getWindowWidth();
|
|
|
- scrollBarWidth = measureScrollbar();
|
|
|
- },
|
|
|
- createOverlay = function createOverlay() {
|
|
|
- var newOverlay = DOC[createElement]('div');
|
|
|
- overlay = queryElement('.' + modalBackdropString);
|
|
|
-
|
|
|
- if (overlay === null) {
|
|
|
- newOverlay[setAttribute]('class', modalBackdropString + (self[animation] ? ' fade' : ''));
|
|
|
- overlay = newOverlay;
|
|
|
- DOC[body][appendChild](overlay);
|
|
|
- }
|
|
|
-
|
|
|
- modalOverlay = 1;
|
|
|
- },
|
|
|
- removeOverlay = function removeOverlay() {
|
|
|
- overlay = queryElement('.' + modalBackdropString);
|
|
|
-
|
|
|
- if (overlay && overlay !== null && typeof overlay === 'object') {
|
|
|
- modalOverlay = 0;
|
|
|
- DOC[body].removeChild(overlay);
|
|
|
- overlay = null;
|
|
|
- }
|
|
|
- },
|
|
|
- // triggers
|
|
|
- triggerShow = function triggerShow() {
|
|
|
- setFocus(modal);
|
|
|
- modal[isAnimating] = false;
|
|
|
- bootstrapCustomEvent.call(modal, shownEvent, component, relatedTarget);
|
|
|
- on(globalObject, resizeEvent, self.update, passiveHandler);
|
|
|
- on(modal, clickEvent, dismissHandler);
|
|
|
- on(DOC, keydownEvent, keyHandler);
|
|
|
- },
|
|
|
- triggerHide = function triggerHide() {
|
|
|
- modal[style].display = '';
|
|
|
- element && setFocus(element);
|
|
|
- bootstrapCustomEvent.call(modal, hiddenEvent, component);
|
|
|
-
|
|
|
- (function () {
|
|
|
- if (!getElementsByClassName(DOC, component + ' ' + showClass)[0]) {
|
|
|
- resetScrollbar();
|
|
|
- removeClass(DOC[body], component + '-open');
|
|
|
- overlay && hasClass(overlay, 'fade') ? (removeClass(overlay, showClass), emulateTransitionEnd(overlay, removeOverlay)) : removeOverlay();
|
|
|
- off(globalObject, resizeEvent, self.update, passiveHandler);
|
|
|
- off(modal, clickEvent, dismissHandler);
|
|
|
- off(DOC, keydownEvent, keyHandler);
|
|
|
- }
|
|
|
- })();
|
|
|
-
|
|
|
- modal[isAnimating] = false;
|
|
|
- },
|
|
|
- // handlers
|
|
|
- clickHandler = function clickHandler(e) {
|
|
|
- if (modal[isAnimating]) return;
|
|
|
- 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 keyHandler(e) {
|
|
|
- if (modal[isAnimating]) return;
|
|
|
-
|
|
|
- if (self[keyboard] && e.which == 27 && hasClass(modal, showClass)) {
|
|
|
- self.hide();
|
|
|
- }
|
|
|
- },
|
|
|
- dismissHandler = function dismissHandler(e) {
|
|
|
- if (modal[isAnimating]) return;
|
|
|
- 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 () {
|
|
|
- if (hasClass(modal, showClass) || modal[isAnimating]) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- clearTimeout(modalTimer);
|
|
|
- modalTimer = setTimeout(function () {
|
|
|
- modal[isAnimating] = true;
|
|
|
- bootstrapCustomEvent.call(modal, showEvent, component, relatedTarget); // we elegantly hide any opened modal
|
|
|
-
|
|
|
- var currentOpen = getElementsByClassName(DOC, component + ' ' + showClass)[0];
|
|
|
-
|
|
|
- if (currentOpen && currentOpen !== modal) {
|
|
|
- modalTrigger in currentOpen && currentOpen[modalTrigger][stringModal].hide();
|
|
|
- stringModal in currentOpen && currentOpen[stringModal].hide();
|
|
|
- }
|
|
|
-
|
|
|
- if (self[backdrop]) {
|
|
|
- !modalOverlay && !overlay && createOverlay();
|
|
|
- }
|
|
|
-
|
|
|
- if (overlay && !hasClass(overlay, showClass)) {
|
|
|
- overlay[offsetWidth]; // force reflow to enable trasition
|
|
|
-
|
|
|
- overlayDelay = getTransitionDurationFromElement(overlay);
|
|
|
- addClass(overlay, showClass);
|
|
|
- }
|
|
|
-
|
|
|
- setTimeout(function () {
|
|
|
- modal[style].display = 'block';
|
|
|
- checkScrollbar();
|
|
|
- setScrollbar();
|
|
|
- addClass(DOC[body], component + '-open');
|
|
|
- addClass(modal, showClass);
|
|
|
- modal[setAttribute](ariaHidden, false);
|
|
|
- hasClass(modal, 'fade') ? emulateTransitionEnd(modal, triggerShow) : triggerShow();
|
|
|
- }, supportTransitions && overlay && overlayDelay ? overlayDelay : 1);
|
|
|
- }, 1);
|
|
|
- };
|
|
|
-
|
|
|
- this.hide = function () {
|
|
|
- if (modal[isAnimating] || !hasClass(modal, showClass)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- clearTimeout(modalTimer);
|
|
|
- modalTimer = setTimeout(function () {
|
|
|
- modal[isAnimating] = true;
|
|
|
- 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 ? overlayDelay : 2);
|
|
|
- }, 2);
|
|
|
- };
|
|
|
-
|
|
|
- this.setContent = function (content) {
|
|
|
- queryElement('.' + component + '-content', modal)[innerHTML] = content;
|
|
|
- };
|
|
|
-
|
|
|
- this.update = function () {
|
|
|
- if (hasClass(modal, showClass)) {
|
|
|
- checkScrollbar();
|
|
|
- setScrollbar();
|
|
|
- }
|
|
|
- }; // 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]);
|
|
|
- }
|
|
|
-
|
|
|
- if (element) {
|
|
|
- element[stringModal] = self;
|
|
|
- modal[modalTrigger] = element;
|
|
|
- } else {
|
|
|
- modal[stringModal] = self;
|
|
|
- }
|
|
|
- }; // DATA API
|
|
|
-
|
|
|
-
|
|
|
- supports[push]([stringModal, Modal, '[' + dataToggle + '="modal"]']);
|
|
|
- /* Native Javascript for Bootstrap 4 | Popover
|
|
|
- ----------------------------------------------*/
|
|
|
- // POPOVER DEFINITION
|
|
|
- // ==================
|
|
|
-
|
|
|
- var Popover = function Popover(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',
|
|
|
- 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 = options.title || element[getAttribute](dataTitle) || null,
|
|
|
- contentString = options.content || element[getAttribute](dataContent) || null;
|
|
|
- if (!contentString && !this[template]) return; // invalidate
|
|
|
- // constants, vars
|
|
|
-
|
|
|
- var popover = null,
|
|
|
- timer = 0,
|
|
|
- placementSetting = this[placement],
|
|
|
- // handlers
|
|
|
- dismissibleHandler = function dismissibleHandler(e) {
|
|
|
- if (popover !== null && e[target] === queryElement('.close', popover)) {
|
|
|
- self.hide();
|
|
|
- }
|
|
|
- },
|
|
|
- // private methods
|
|
|
- removePopover = function removePopover() {
|
|
|
- self[container].removeChild(popover);
|
|
|
- timer = null;
|
|
|
- popover = null;
|
|
|
- },
|
|
|
- createPopover = function createPopover() {
|
|
|
- titleString = options.title || element[getAttribute](dataTitle);
|
|
|
- contentString = options.content || element[getAttribute](dataContent); // fixing https://github.com/thednp/bootstrap.native/issues/233
|
|
|
-
|
|
|
- contentString = !!contentString ? contentString.trim() : null;
|
|
|
- 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);
|
|
|
- self[template] = self[template].trim();
|
|
|
- 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 showPopover() {
|
|
|
- !hasClass(popover, showClass) && addClass(popover, showClass);
|
|
|
- },
|
|
|
- updatePopover = function updatePopover() {
|
|
|
- styleTip(element, popover, placementSetting, self[container]);
|
|
|
- },
|
|
|
- // event toggle
|
|
|
- dismissHandlerToggle = function dismissHandlerToggle(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, passiveHandler);
|
|
|
- },
|
|
|
- // triggers
|
|
|
- showTrigger = function showTrigger() {
|
|
|
- dismissHandlerToggle(on);
|
|
|
- bootstrapCustomEvent.call(element, shownEvent, component);
|
|
|
- },
|
|
|
- hideTrigger = function hideTrigger() {
|
|
|
- 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"]']);
|
|
|
- /* Native Javascript for Bootstrap 4 | Tab
|
|
|
- -----------------------------------------*/
|
|
|
- // TAB DEFINITION
|
|
|
- // ==============
|
|
|
-
|
|
|
- var Tab = function Tab(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 triggerEnd() {
|
|
|
- tabsContentContainer[style][height] = '';
|
|
|
- removeClass(tabsContentContainer, collapsing);
|
|
|
- tabs[isAnimating] = false;
|
|
|
- },
|
|
|
- triggerShow = function triggerShow() {
|
|
|
- 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 triggerHide() {
|
|
|
- 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 getActiveTab() {
|
|
|
- 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 getActiveContent() {
|
|
|
- return queryElement(getActiveTab()[getAttribute]('href'));
|
|
|
- },
|
|
|
- // handler
|
|
|
- clickHandler = function clickHandler(e) {
|
|
|
- e[preventDefault]();
|
|
|
- next = e[currentTarget];
|
|
|
- !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);
|
|
|
- activeTab[setAttribute](ariaSelected, 'false');
|
|
|
- addClass(next, active);
|
|
|
- next[setAttribute](ariaSelected, 'true');
|
|
|
-
|
|
|
- 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"]']);
|
|
|
- /* Native Javascript for Bootstrap 4 | Toast
|
|
|
- ---------------------------------------------*/
|
|
|
- // TOAST DEFINITION
|
|
|
- // ==================
|
|
|
-
|
|
|
- var Toast = function Toast(element, options) {
|
|
|
- // initialization element
|
|
|
- element = queryElement(element); // set options
|
|
|
-
|
|
|
- options = options || {}; // DATA API
|
|
|
-
|
|
|
- var animationData = element[getAttribute](dataAnimation),
|
|
|
- autohideData = element[getAttribute](dataAutohide),
|
|
|
- delayData = element[getAttribute](dataDelay),
|
|
|
- // strings
|
|
|
- component = 'toast',
|
|
|
- autohide = 'autohide',
|
|
|
- animation = 'animation',
|
|
|
- showing = 'showing',
|
|
|
- hide = 'hide',
|
|
|
- fade = 'fade'; // set instance options
|
|
|
-
|
|
|
- this[animation] = options[animation] === false || animationData === 'false' ? 0 : 1; // true by default
|
|
|
-
|
|
|
- this[autohide] = options[autohide] === false || autohideData === 'false' ? 0 : 1; // true by default
|
|
|
-
|
|
|
- this[delay] = parseInt(options[delay] || delayData) || 500; // 500ms default
|
|
|
- // bind,toast and timer
|
|
|
-
|
|
|
- var self = this,
|
|
|
- timer = 0,
|
|
|
- // get the toast element
|
|
|
- toast = getClosest(element, '.toast'); // private methods
|
|
|
- // animation complete
|
|
|
-
|
|
|
- var showComplete = function showComplete() {
|
|
|
- removeClass(toast, showing);
|
|
|
- addClass(toast, showClass);
|
|
|
- bootstrapCustomEvent.call(toast, shownEvent, component);
|
|
|
-
|
|
|
- if (self[autohide]) {
|
|
|
- self.hide();
|
|
|
- }
|
|
|
- },
|
|
|
- hideComplete = function hideComplete() {
|
|
|
- addClass(toast, hide);
|
|
|
- bootstrapCustomEvent.call(toast, hiddenEvent, component);
|
|
|
- },
|
|
|
- close = function close() {
|
|
|
- removeClass(toast, showClass);
|
|
|
- self[animation] ? emulateTransitionEnd(toast, hideComplete) : hideComplete();
|
|
|
- },
|
|
|
- disposeComplete = function disposeComplete() {
|
|
|
- clearTimeout(timer);
|
|
|
- timer = null;
|
|
|
- addClass(toast, hide);
|
|
|
- off(element, clickEvent, self.hide);
|
|
|
- element[stringToast] = null;
|
|
|
- element = null;
|
|
|
- toast = null;
|
|
|
- }; // public methods
|
|
|
-
|
|
|
-
|
|
|
- this.show = function () {
|
|
|
- if (toast) {
|
|
|
- bootstrapCustomEvent.call(toast, showEvent, component);
|
|
|
- self[animation] && addClass(toast, fade);
|
|
|
- removeClass(toast, hide);
|
|
|
- addClass(toast, showing);
|
|
|
- self[animation] ? emulateTransitionEnd(toast, showComplete) : showComplete();
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- this.hide = function (noTimer) {
|
|
|
- if (toast && hasClass(toast, showClass)) {
|
|
|
- bootstrapCustomEvent.call(toast, hideEvent, component);
|
|
|
-
|
|
|
- if (noTimer) {
|
|
|
- close();
|
|
|
- } else {
|
|
|
- timer = setTimeout(close, self[delay]);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- this.dispose = function () {
|
|
|
- if (toast && hasClass(toast, showClass)) {
|
|
|
- removeClass(toast, showClass);
|
|
|
- self[animation] ? emulateTransitionEnd(toast, disposeComplete) : disposeComplete();
|
|
|
- }
|
|
|
- }; // init
|
|
|
-
|
|
|
-
|
|
|
- if (!(stringToast in element)) {
|
|
|
- // prevent adding event handlers twice
|
|
|
- on(element, clickEvent, self.hide);
|
|
|
- }
|
|
|
-
|
|
|
- element[stringToast] = self;
|
|
|
- }; // TOAST DATA API
|
|
|
- // =================
|
|
|
-
|
|
|
-
|
|
|
- supports[push]([stringToast, Toast, '[' + dataDismiss + '="toast"]']);
|
|
|
- /* Native Javascript for Bootstrap 4 | Tooltip
|
|
|
- ---------------------------------------------*/
|
|
|
- // TOOLTIP DEFINITION
|
|
|
- // ==================
|
|
|
-
|
|
|
- var Tooltip = function Tooltip(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 removeToolTip() {
|
|
|
- self[container].removeChild(tooltip);
|
|
|
- tooltip = null;
|
|
|
- timer = null;
|
|
|
- },
|
|
|
- createToolTip = function createToolTip() {
|
|
|
- titleString = element[getAttribute](title) || element[getAttribute](dataTitle) || element[getAttribute](dataOriginalTitle); // read the title again
|
|
|
-
|
|
|
- if (titleString && titleString !== "") {
|
|
|
- // invalidate, maybe markup changed
|
|
|
- tooltip = DOC[createElement](div);
|
|
|
- tooltip[setAttribute]('role', component);
|
|
|
- tooltip[style][left] = '0';
|
|
|
- tooltip[style][top] = '0'; // 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 updateTooltip() {
|
|
|
- styleTip(element, tooltip, placementSetting, self[container]);
|
|
|
- },
|
|
|
- showTooltip = function showTooltip() {
|
|
|
- !hasClass(tooltip, showClass) && addClass(tooltip, showClass);
|
|
|
- },
|
|
|
- // triggers
|
|
|
- showTrigger = function showTrigger() {
|
|
|
- on(globalObject, resizeEvent, self.hide, passiveHandler);
|
|
|
- bootstrapCustomEvent.call(element, shownEvent, component);
|
|
|
- },
|
|
|
- hideTrigger = function hideTrigger() {
|
|
|
- off(globalObject, resizeEvent, self.hide, passiveHandler);
|
|
|
- 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;
|
|
|
-
|
|
|
- if (createToolTip() !== false) {
|
|
|
- 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"]']);
|
|
|
- /* Native Javascript for Bootstrap | Initialize Data API
|
|
|
- --------------------------------------------------------*/
|
|
|
-
|
|
|
- var initializeDataAPI = function initializeDataAPI(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,
|
|
|
- Collapse: Collapse,
|
|
|
- Dropdown: Dropdown,
|
|
|
- Modal: Modal,
|
|
|
- Popover: Popover,
|
|
|
- Tab: Tab,
|
|
|
- Toast: Toast,
|
|
|
- Tooltip: Tooltip
|
|
|
- };
|
|
|
+ return {
|
|
|
+ Alert: bootstrap.Alert,
|
|
|
+ Button: bootstrap.Button,
|
|
|
+ Collapse: bootstrap.Collapse,
|
|
|
+ Dropdown: bootstrap.Dropdown,
|
|
|
+ Modal: bootstrap.Modal,
|
|
|
+ Popover: bootstrap.Popover,
|
|
|
+ Tab: bootstrap.Tab,
|
|
|
+ Tooltip: bootstrap.Tooltip
|
|
|
+ };
|
|
|
});
|
|
|
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(12)))
|
|
|
|