(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i { scope = scope ? scope : document; return scope.querySelector(selector); }; const getAll = (selector, scope) => { scope = scope ? scope : document; return scope.querySelectorAll(selector); }; const nav = get("nav"); const profile = get("#profile"); const loading = get("#loading"); const content = get("#content"); const toggle = get(".toggle"); const avatarAnimation = anime({ targets: '#avatar #moon', rotate: '1turn', transformOrigin: "center center 0", duration: 5000 }); const showSidenavCategories = anime({ targets: '#sidenav-categories li', translateY: [-10, 0], duration: 1200, opacity: [0,1], delay: function(el, i) { return i * 60; } }); const showSidenavUsers = anime({ targets: '#sidenav-users li', translateY: [-10, 0], duration: 1200, opacity: [0,1], delay: function(el, i) { return i * 60; } }); const showSidenavAdmins = anime({ targets: '#sidenav-admins li', translateY: [-10, 0], duration: 1200, opacity: [0,1], delay: function(el, i) { return i * 60; } }); function isHidden(el) { return (el.offsetParent === null) } function removeLoadingScreen () { anime({ targets: "#loading", opacity: 0, duration: 1000, easing: "easeOutExpo", complete: () => { loading.style.display = "none"; } }); } // loading animation anime({ targets: '#morphing #moon', rotate: '1turn', transformOrigin: "center center 0", duration: 5000, loop: true }); // toggle stats on when window resizes window.addEventListener("resize", () => { let mobileHiddens = getAll(".js-mobile-hidden"); if(window.innerWidth > 768) { for (var i = 0; i < mobileHiddens.length; i++) { mobileHiddens[i].classList.remove('hidden'); } if (get("[data-tab='section-stats']") && get("[data-tab='section-stats']").classList.contains('active')) { get("[data-tab='section-library']").click(); } if (content.classList.contains("hidden")) { content.classList.remove("hidden"); content.classList.add("flex"); profile.style.top = 0; } } else { for (var i = 0; i < mobileHiddens.length; i++) { mobileHiddens[i].classList.add('hidden'); } } }) // show loading screen if images loaded faster than 200ms setTimeout(() => { imagesloaded(get("body"), () => { let tabs = getAll(".js-tab"); let panes = getAll(".js-tab-pane"); let mobileHiddens = getAll(".js-mobile-hidden"); let sidenavCategoriesTrigger = get("#sidenav-categories-trigger"); let sidenavCategories = get("#sidenav-categories"); let sidenavCategoriesIcon = get("#sidenav-categories-icon"); let sidenavUsersTrigger = get("#sidenav-users-trigger"); let sidenavUsers = get("#sidenav-users"); let sidenavUsersIcon = get("#sidenav-users-icon"); let sidenavAdminsTrigger = get("#sidenav-admins-trigger"); let sidenavAdmins = get("#sidenav-admins"); let sidenavAdminsIcon = get("#sidenav-admins-icon"); let books = getAll(".js-book"); let mobileReoadTriggers = getAll(".mobile-home-trigger"); removeLoadingScreen(); // bind click event to sideNav sidenavCategoriesTrigger.addEventListener("click", sidenavCategoriesClick); sidenavUsersTrigger.addEventListener("click", sidenavUsersClick); if (sidenavAdminsTrigger) sidenavAdminsTrigger.addEventListener("click", sidenavAdminsClick); // bind click event to each tab for (var i = 0; i < tabs.length; i++) { tabs[i].addEventListener("click", tabClick); } for (let i = 0; i < mobileReoadTriggers.length; i++) { mobileReoadTriggers[i].addEventListener("click", event => { location.reload(); }) } for (var i = 0; i < books.length; i++) { /*tippy(books[i], { html: "#popup", placement: "right", theme: "light rounded", arrow: true, arrowTransform: "scaleX(1.3)", distance: 20, maxWidth: "200px", animation: "fade", trigger: "click", interactive: true, });*/ books[i].addEventListener("click", function() { location.href = this.getAttribute("data-href"); }) } // disable/enable tippy if on mobile/desktop device tippy.browser.onUserInputChange = type => { const method = type === 'touch' || this.window.innerWidth < 768 ? 'disable' : 'enable'; for (let i = 0; i < books.length; i++) { books[i]._tippy[method](); } } function sidenavCategoriesClick (event) { if (sidenavCategories.classList.contains("hidden")) { sidenavCategories.classList.remove("hidden"); sidenavCategoriesIcon.classList.remove("rotate"); showSidenavCategories.restart(); } else { sidenavCategories.classList.add("hidden"); sidenavCategoriesIcon.classList.add("rotate"); } } function sidenavUsersClick (event) { if (sidenavUsers.classList.contains("hidden")) { sidenavUsers.classList.remove("hidden"); sidenavUsersIcon.classList.remove("rotate"); showSidenavUsers.restart(); } else { sidenavUsers.classList.add("hidden"); sidenavUsersIcon.classList.add("rotate"); } } function sidenavAdminsClick (event) { if (sidenavAdmins.classList.contains("hidden")) { sidenavAdmins.classList.remove("hidden"); sidenavAdminsIcon.classList.remove("rotate"); showSidenavAdmins.restart(); } else { sidenavAdmins.classList.add("hidden"); sidenavAdminsIcon.classList.add("rotate"); } } if (window.innerWidth > 768) { for (var i = 0; i < mobileHiddens.length; i++) { mobileHiddens[i].classList.remove('hidden'); } } // each click event is scoped to the tab_container function tabClick (event) { let clickedTab = event.target; let activePane = get(`#${clickedTab.getAttribute("data-tab")}`); // remove all active tab classes for (let i = 0; i < tabs.length; i++) { tabs[i].classList.remove('active'); } // remove all active pane classes for (var i = 0; i < panes.length; i++) { panes[i].classList.remove('active'); } // apply active classes on desired tab and pane clickedTab.classList.add('active'); activePane.classList.add('active'); } }); }, 1000); get("#mobile-nav-trigger").addEventListener("click", event => { if (isHidden(nav)) { toggle.classList.add("open"); nav.classList.remove("hidden"); } else { toggle.classList.remove("open"); nav.classList.add("hidden"); } }); /*get("#mobile-profile-trigger").addEventListener("click", event => { profile.classList.remove("hidden"); profile.style.top = "63px"; content.classList.remove("flex"); content.classList.add("hidden"); nav.classList.add("hidden"); toggle.classList.remove("open"); });*/ // avatar animation if (get("#avatar")) { get("#avatar").addEventListener("mouseenter", event => { avatarAnimation.restart(); }, false); get("#avatar").addEventListener("mouseleave", event => { avatarAnimation.reverse(); }, false); } },{"animejs":2,"imagesloaded":4,"tippy.js":5}],2:[function(require,module,exports){ (function (global){ /* 2017 Julian Garnier Released under the MIT license */ var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(e,r,p){if(p.get||p.set)throw new TypeError("ES3 does not support getters and setters.");e!=Array.prototype&&e!=Object.prototype&&(e[r]=p.value)};$jscomp.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global&&null!=global?global:e};$jscomp.global=$jscomp.getGlobal(this);$jscomp.SYMBOL_PREFIX="jscomp_symbol_"; $jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0;$jscomp.Symbol=function(e){return $jscomp.SYMBOL_PREFIX+(e||"")+$jscomp.symbolCounter_++}; $jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var e=$jscomp.global.Symbol.iterator;e||(e=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[e]&&$jscomp.defineProperty(Array.prototype,e,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(e){var r=0;return $jscomp.iteratorPrototype(function(){return rb&&(b+=1);1b?c:b<2/3?a+(c-a)*(2/3-b)*6:a}var d=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a)||/hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(a);a=parseInt(d[1])/360;var b=parseInt(d[2])/100,f=parseInt(d[3])/100,d=d[4]||1;if(0==b)f=b=a=f;else{var n=.5>f?f*(1+b):f+b-f*b,k=2*f-n,f=c(k,n,a+1/3),b=c(k,n,a);a=c(k,n,a-1/3)}return"rgba("+ 255*f+","+255*b+","+255*a+","+d+")"}function y(a){if(a=/([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(a))return a[2]}function V(a){if(-1=g.currentTime)for(var G=0;G=w||!k)g.began||(g.began=!0,f("begin")),f("run");if(q>n&&q=k&&r!==k||!k)b(k),x||e();f("update");a>=k&&(g.remaining?(t=h,"alternate"===g.direction&&(g.reversed=!g.reversed)):(g.pause(),g.completed||(g.completed=!0,f("complete"),"Promise"in window&&(p(),m=c()))),l=0)}a=void 0===a?{}:a;var h,t,l=0,p=null,m=c(),g=fa(a);g.reset=function(){var a=g.direction,c=g.loop;g.currentTime= 0;g.progress=0;g.paused=!0;g.began=!1;g.completed=!1;g.reversed="reverse"===a;g.remaining="alternate"===a&&1===c?2:c;b(0);for(a=g.children.length;a--;)g.children[a].reset()};g.tick=function(a){h=a;t||(t=h);k((l+h-t)*q.speed)};g.seek=function(a){k(d(a))};g.pause=function(){var a=v.indexOf(g);-1=c&&0<=b&&1>=b){var e=new Float32Array(11);if(c!==d||b!==f)for(var k=0;11>k;++k)e[k]=a(.1*k,c,b);return function(k){if(c===d&&b===f)return k;if(0===k)return 0;if(1===k)return 1;for(var h=0,l=1;10!==l&&e[l]<=k;++l)h+=.1;--l;var l=h+(k-e[l])/(e[l+1]-e[l])*.1,n=3*(1-3*b+3*c)*l*l+2*(3*b-6*c)*l+3*c;if(.001<=n){for(h=0;4>h;++h){n=3*(1-3*b+3*c)*l*l+2*(3*b-6*c)*l+3*c;if(0===n)break;var m=a(l,c,b)-k,l=l-m/n}k=l}else if(0=== n)k=l;else{var l=h,h=h+.1,g=0;do m=l+(h-l)/2,n=a(m,c,b)-k,0++g);k=m}return a(k,d,f)}}}}(),Q=function(){function a(a,b){return 0===a||1===a?a:-Math.pow(2,10*(a-1))*Math.sin(2*(a-1-b/(2*Math.PI)*Math.asin(1))*Math.PI/b)}var c="Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "),d={In:[[.55,.085,.68,.53],[.55,.055,.675,.19],[.895,.03,.685,.22],[.755,.05,.855,.06],[.47,0,.745,.715],[.95,.05,.795,.035],[.6,.04,.98,.335],[.6,-.28,.735,.045],a],Out:[[.25, .46,.45,.94],[.215,.61,.355,1],[.165,.84,.44,1],[.23,1,.32,1],[.39,.575,.565,1],[.19,1,.22,1],[.075,.82,.165,1],[.175,.885,.32,1.275],function(b,c){return 1-a(1-b,c)}],InOut:[[.455,.03,.515,.955],[.645,.045,.355,1],[.77,0,.175,1],[.86,0,.07,1],[.445,.05,.55,.95],[1,0,0,1],[.785,.135,.15,.86],[.68,-.55,.265,1.55],function(b,c){return.5>b?a(2*b,c)/2:1-a(-2*b+2,c)/2}]},b={linear:A(.25,.25,.75,.75)},f={},e;for(e in d)f.type=e,d[f.type].forEach(function(a){return function(d,f){b["ease"+a.type+c[f]]=h.fnc(d)? d:A.apply($jscomp$this,d)}}(f)),f={type:f.type};return b}(),ha={css:function(a,c,d){return a.style[c]=d},attribute:function(a,c,d){return a.setAttribute(c,d)},object:function(a,c,d){return a[c]=d},transform:function(a,c,d,b,f){b[f]||(b[f]=[]);b[f].push(c+"("+d+")")}},v=[],B=0,ia=function(){function a(){B=requestAnimationFrame(c)}function c(c){var b=v.length;if(b){for(var d=0;db&&(c.duration=d.duration);c.children.push(d)});c.seek(0);c.reset();c.autoplay&&c.restart();return c};return c};q.random=function(a,c){return Math.floor(Math.random()*(c-a+1))+a};return q}); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],3:[function(require,module,exports){ /** * EvEmitter v1.1.0 * Lil' event emitter * MIT License */ /* jshint unused: true, undef: true, strict: true */ ( function( global, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, window */ if ( typeof define == 'function' && define.amd ) { // AMD - RequireJS define( factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS - Browserify, Webpack module.exports = factory(); } else { // Browser globals global.EvEmitter = factory(); } }( typeof window != 'undefined' ? window : this, function() { "use strict"; function EvEmitter() {} var proto = EvEmitter.prototype; proto.on = function( eventName, listener ) { if ( !eventName || !listener ) { return; } // set events hash var events = this._events = this._events || {}; // set listeners array var listeners = events[ eventName ] = events[ eventName ] || []; // only add once if ( listeners.indexOf( listener ) == -1 ) { listeners.push( listener ); } return this; }; proto.once = function( eventName, listener ) { if ( !eventName || !listener ) { return; } // add event this.on( eventName, listener ); // set once flag // set onceEvents hash var onceEvents = this._onceEvents = this._onceEvents || {}; // set onceListeners object var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; // set flag onceListeners[ listener ] = true; return this; }; proto.off = function( eventName, listener ) { var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } var index = listeners.indexOf( listener ); if ( index != -1 ) { listeners.splice( index, 1 ); } return this; }; proto.emitEvent = function( eventName, args ) { var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } // copy over to avoid interference if .off() in listener listeners = listeners.slice(0); args = args || []; // once stuff var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; for ( var i=0; i < listeners.length; i++ ) { var listener = listeners[i] var isOnce = onceListeners && onceListeners[ listener ]; if ( isOnce ) { // remove listener // remove before trigger to prevent recursion this.off( eventName, listener ); // unset once flag delete onceListeners[ listener ]; } // trigger listener listener.apply( this, args ); } return this; }; proto.allOff = function() { delete this._events; delete this._onceEvents; }; return EvEmitter; })); },{}],4:[function(require,module,exports){ /*! * imagesLoaded v4.1.4 * JavaScript is all like "You images are done yet or what?" * MIT License */ ( function( window, factory ) { 'use strict'; // universal module definition /*global define: false, module: false, require: false */ if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'ev-emitter/ev-emitter' ], function( EvEmitter ) { return factory( window, EvEmitter ); }); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, require('ev-emitter') ); } else { // browser global window.imagesLoaded = factory( window, window.EvEmitter ); } })( typeof window !== 'undefined' ? window : this, // -------------------------- factory -------------------------- // function factory( window, EvEmitter ) { 'use strict'; var $ = window.jQuery; var console = window.console; // -------------------------- helpers -------------------------- // // extend objects function extend( a, b ) { for ( var prop in b ) { a[ prop ] = b[ prop ]; } return a; } var arraySlice = Array.prototype.slice; // turn element or nodeList into an array function makeArray( obj ) { if ( Array.isArray( obj ) ) { // use object if already an array return obj; } var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; if ( isArrayLike ) { // convert nodeList to array return arraySlice.call( obj ); } // array of single index return [ obj ]; } // -------------------------- imagesLoaded -------------------------- // /** * @param {Array, Element, NodeList, String} elem * @param {Object or Function} options - if function, use as callback * @param {Function} onAlways - callback function */ function ImagesLoaded( elem, options, onAlways ) { // coerce ImagesLoaded() without new, to be new ImagesLoaded() if ( !( this instanceof ImagesLoaded ) ) { return new ImagesLoaded( elem, options, onAlways ); } // use elem as selector string var queryElem = elem; if ( typeof elem == 'string' ) { queryElem = document.querySelectorAll( elem ); } // bail if bad element if ( !queryElem ) { console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) ); return; } this.elements = makeArray( queryElem ); this.options = extend( {}, this.options ); // shift arguments if no options set if ( typeof options == 'function' ) { onAlways = options; } else { extend( this.options, options ); } if ( onAlways ) { this.on( 'always', onAlways ); } this.getImages(); if ( $ ) { // add jQuery Deferred object this.jqDeferred = new $.Deferred(); } // HACK check async to allow time to bind listeners setTimeout( this.check.bind( this ) ); } ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); ImagesLoaded.prototype.options = {}; ImagesLoaded.prototype.getImages = function() { this.images = []; // filter & find items if we have an item selector this.elements.forEach( this.addElementImages, this ); }; /** * @param {Node} element */ ImagesLoaded.prototype.addElementImages = function( elem ) { // filter siblings if ( elem.nodeName == 'IMG' ) { this.addImage( elem ); } // get background image on element if ( this.options.background === true ) { this.addElementBackgroundImages( elem ); } // find children // no non-element nodes, #143 var nodeType = elem.nodeType; if ( !nodeType || !elementNodeTypes[ nodeType ] ) { return; } var childImgs = elem.querySelectorAll('img'); // concat childElems to filterFound array for ( var i=0; i < childImgs.length; i++ ) { var img = childImgs[i]; this.addImage( img ); } // get child background images if ( typeof this.options.background == 'string' ) { var children = elem.querySelectorAll( this.options.background ); for ( i=0; i < children.length; i++ ) { var child = children[i]; this.addElementBackgroundImages( child ); } } }; var elementNodeTypes = { 1: true, 9: true, 11: true }; ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { var style = getComputedStyle( elem ); if ( !style ) { // Firefox returns null if in a hidden iframe https://bugzil.la/548397 return; } // get url inside url("...") var reURL = /url\((['"])?(.*?)\1\)/gi; var matches = reURL.exec( style.backgroundImage ); while ( matches !== null ) { var url = matches && matches[2]; if ( url ) { this.addBackground( url, elem ); } matches = reURL.exec( style.backgroundImage ); } }; /** * @param {Image} img */ ImagesLoaded.prototype.addImage = function( img ) { var loadingImage = new LoadingImage( img ); this.images.push( loadingImage ); }; ImagesLoaded.prototype.addBackground = function( url, elem ) { var background = new Background( url, elem ); this.images.push( background ); }; ImagesLoaded.prototype.check = function() { var _this = this; this.progressedCount = 0; this.hasAnyBroken = false; // complete if no images if ( !this.images.length ) { this.complete(); return; } function onProgress( image, elem, message ) { // HACK - Chrome triggers event before object properties have changed. #83 setTimeout( function() { _this.progress( image, elem, message ); }); } this.images.forEach( function( loadingImage ) { loadingImage.once( 'progress', onProgress ); loadingImage.check(); }); }; ImagesLoaded.prototype.progress = function( image, elem, message ) { this.progressedCount++; this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; // progress event this.emitEvent( 'progress', [ this, image, elem ] ); if ( this.jqDeferred && this.jqDeferred.notify ) { this.jqDeferred.notify( this, image ); } // check if completed if ( this.progressedCount == this.images.length ) { this.complete(); } if ( this.options.debug && console ) { console.log( 'progress: ' + message, image, elem ); } }; ImagesLoaded.prototype.complete = function() { var eventName = this.hasAnyBroken ? 'fail' : 'done'; this.isComplete = true; this.emitEvent( eventName, [ this ] ); this.emitEvent( 'always', [ this ] ); if ( this.jqDeferred ) { var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; this.jqDeferred[ jqMethod ]( this ); } }; // -------------------------- -------------------------- // function LoadingImage( img ) { this.img = img; } LoadingImage.prototype = Object.create( EvEmitter.prototype ); LoadingImage.prototype.check = function() { // If complete is true and browser supports natural sizes, // try to check for image status manually. var isComplete = this.getIsImageComplete(); if ( isComplete ) { // report based on naturalWidth this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); return; } // If none of the checks above matched, simulate loading on detached element. this.proxyImage = new Image(); this.proxyImage.addEventListener( 'load', this ); this.proxyImage.addEventListener( 'error', this ); // bind to image as well for Firefox. #191 this.img.addEventListener( 'load', this ); this.img.addEventListener( 'error', this ); this.proxyImage.src = this.img.src; }; LoadingImage.prototype.getIsImageComplete = function() { // check for non-zero, non-undefined naturalWidth // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 return this.img.complete && this.img.naturalWidth; }; LoadingImage.prototype.confirm = function( isLoaded, message ) { this.isLoaded = isLoaded; this.emitEvent( 'progress', [ this, this.img, message ] ); }; // ----- events ----- // // trigger specified handler for event type LoadingImage.prototype.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; LoadingImage.prototype.onload = function() { this.confirm( true, 'onload' ); this.unbindEvents(); }; LoadingImage.prototype.onerror = function() { this.confirm( false, 'onerror' ); this.unbindEvents(); }; LoadingImage.prototype.unbindEvents = function() { this.proxyImage.removeEventListener( 'load', this ); this.proxyImage.removeEventListener( 'error', this ); this.img.removeEventListener( 'load', this ); this.img.removeEventListener( 'error', this ); }; // -------------------------- Background -------------------------- // function Background( url, element ) { this.url = url; this.element = element; this.img = new Image(); } // inherit LoadingImage prototype Background.prototype = Object.create( LoadingImage.prototype ); Background.prototype.check = function() { this.img.addEventListener( 'load', this ); this.img.addEventListener( 'error', this ); this.img.src = this.url; // check if image is already complete var isComplete = this.getIsImageComplete(); if ( isComplete ) { this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); this.unbindEvents(); } }; Background.prototype.unbindEvents = function() { this.img.removeEventListener( 'load', this ); this.img.removeEventListener( 'error', this ); }; Background.prototype.confirm = function( isLoaded, message ) { this.isLoaded = isLoaded; this.emitEvent( 'progress', [ this, this.element, message ] ); }; // -------------------------- jQuery -------------------------- // ImagesLoaded.makeJQueryPlugin = function( jQuery ) { jQuery = jQuery || window.jQuery; if ( !jQuery ) { return; } // set local variable $ = jQuery; // $().imagesLoaded() $.fn.imagesLoaded = function( options, callback ) { var instance = new ImagesLoaded( this, options, callback ); return instance.jqDeferred.promise( $(this) ); }; }; // try making plugin ImagesLoaded.makeJQueryPlugin(); // -------------------------- -------------------------- // return ImagesLoaded; }); },{"ev-emitter":3}],5:[function(require,module,exports){ (function (global){ /*! * Tippy.js v2.5.4 * (c) 2017-2018 atomiks * MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.tippy = factory()); }(this, (function () { 'use strict'; var styles = ".tippy-touch{cursor:pointer!important}.tippy-notransition{transition:none!important}.tippy-popper{max-width:350px;-webkit-perspective:700px;perspective:700px;z-index:9999;outline:0;transition-timing-function:cubic-bezier(.165,.84,.44,1);pointer-events:none;line-height:1.4}.tippy-popper[data-html]{max-width:96%;max-width:calc(100% - 20px)}.tippy-popper[x-placement^=top] .tippy-backdrop{border-radius:40% 40% 0 0}.tippy-popper[x-placement^=top] .tippy-roundarrow{bottom:-8px;-webkit-transform-origin:50% 0;transform-origin:50% 0}.tippy-popper[x-placement^=top] .tippy-roundarrow svg{position:absolute;left:0;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.tippy-popper[x-placement^=top] .tippy-arrow{border-top:7px solid #333;border-right:7px solid transparent;border-left:7px solid transparent;bottom:-7px;margin:0 6px;-webkit-transform-origin:50% 0;transform-origin:50% 0}.tippy-popper[x-placement^=top] .tippy-backdrop{-webkit-transform-origin:0 90%;transform-origin:0 90%}.tippy-popper[x-placement^=top] .tippy-backdrop[data-state=visible]{-webkit-transform:scale(6) translate(-50%,25%);transform:scale(6) translate(-50%,25%);opacity:1}.tippy-popper[x-placement^=top] .tippy-backdrop[data-state=hidden]{-webkit-transform:scale(1) translate(-50%,25%);transform:scale(1) translate(-50%,25%);opacity:0}.tippy-popper[x-placement^=top] [data-animation=shift-toward][data-state=visible]{opacity:1;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=shift-toward][data-state=hidden]{opacity:0;-webkit-transform:translateY(-20px);transform:translateY(-20px)}.tippy-popper[x-placement^=top] [data-animation=perspective]{-webkit-transform-origin:bottom;transform-origin:bottom}.tippy-popper[x-placement^=top] [data-animation=perspective][data-state=visible]{opacity:1;-webkit-transform:translateY(-10px) rotateX(0);transform:translateY(-10px) rotateX(0)}.tippy-popper[x-placement^=top] [data-animation=perspective][data-state=hidden]{opacity:0;-webkit-transform:translateY(0) rotateX(90deg);transform:translateY(0) rotateX(90deg)}.tippy-popper[x-placement^=top] [data-animation=fade][data-state=visible]{opacity:1;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=fade][data-state=hidden]{opacity:0;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=shift-away][data-state=visible]{opacity:1;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=shift-away][data-state=hidden]{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}.tippy-popper[x-placement^=top] [data-animation=scale][data-state=visible]{opacity:1;-webkit-transform:translateY(-10px) scale(1);transform:translateY(-10px) scale(1)}.tippy-popper[x-placement^=top] [data-animation=scale][data-state=hidden]{opacity:0;-webkit-transform:translateY(0) scale(0);transform:translateY(0) scale(0)}.tippy-popper[x-placement^=bottom] .tippy-backdrop{border-radius:0 0 30% 30%}.tippy-popper[x-placement^=bottom] .tippy-roundarrow{top:-8px;-webkit-transform-origin:50% 100%;transform-origin:50% 100%}.tippy-popper[x-placement^=bottom] .tippy-roundarrow svg{position:absolute;left:0;-webkit-transform:rotate(0);transform:rotate(0)}.tippy-popper[x-placement^=bottom] .tippy-arrow{border-bottom:7px solid #333;border-right:7px solid transparent;border-left:7px solid transparent;top:-7px;margin:0 6px;-webkit-transform-origin:50% 100%;transform-origin:50% 100%}.tippy-popper[x-placement^=bottom] .tippy-backdrop{-webkit-transform-origin:0 -90%;transform-origin:0 -90%}.tippy-popper[x-placement^=bottom] .tippy-backdrop[data-state=visible]{-webkit-transform:scale(6) translate(-50%,-125%);transform:scale(6) translate(-50%,-125%);opacity:1}.tippy-popper[x-placement^=bottom] .tippy-backdrop[data-state=hidden]{-webkit-transform:scale(1) translate(-50%,-125%);transform:scale(1) translate(-50%,-125%);opacity:0}.tippy-popper[x-placement^=bottom] [data-animation=shift-toward][data-state=visible]{opacity:1;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=shift-toward][data-state=hidden]{opacity:0;-webkit-transform:translateY(20px);transform:translateY(20px)}.tippy-popper[x-placement^=bottom] [data-animation=perspective]{-webkit-transform-origin:top;transform-origin:top}.tippy-popper[x-placement^=bottom] [data-animation=perspective][data-state=visible]{opacity:1;-webkit-transform:translateY(10px) rotateX(0);transform:translateY(10px) rotateX(0)}.tippy-popper[x-placement^=bottom] [data-animation=perspective][data-state=hidden]{opacity:0;-webkit-transform:translateY(0) rotateX(-90deg);transform:translateY(0) rotateX(-90deg)}.tippy-popper[x-placement^=bottom] [data-animation=fade][data-state=visible]{opacity:1;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=fade][data-state=hidden]{opacity:0;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=shift-away][data-state=visible]{opacity:1;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=shift-away][data-state=hidden]{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}.tippy-popper[x-placement^=bottom] [data-animation=scale][data-state=visible]{opacity:1;-webkit-transform:translateY(10px) scale(1);transform:translateY(10px) scale(1)}.tippy-popper[x-placement^=bottom] [data-animation=scale][data-state=hidden]{opacity:0;-webkit-transform:translateY(0) scale(0);transform:translateY(0) scale(0)}.tippy-popper[x-placement^=left] .tippy-backdrop{border-radius:50% 0 0 50%}.tippy-popper[x-placement^=left] .tippy-roundarrow{right:-16px;-webkit-transform-origin:33.33333333% 50%;transform-origin:33.33333333% 50%}.tippy-popper[x-placement^=left] .tippy-roundarrow svg{position:absolute;left:0;-webkit-transform:rotate(90deg);transform:rotate(90deg)}.tippy-popper[x-placement^=left] .tippy-arrow{border-left:7px solid #333;border-top:7px solid transparent;border-bottom:7px solid transparent;right:-7px;margin:3px 0;-webkit-transform-origin:0 50%;transform-origin:0 50%}.tippy-popper[x-placement^=left] .tippy-backdrop{-webkit-transform-origin:100% 0;transform-origin:100% 0}.tippy-popper[x-placement^=left] .tippy-backdrop[data-state=visible]{-webkit-transform:scale(6) translate(40%,-50%);transform:scale(6) translate(40%,-50%);opacity:1}.tippy-popper[x-placement^=left] .tippy-backdrop[data-state=hidden]{-webkit-transform:scale(1.5) translate(40%,-50%);transform:scale(1.5) translate(40%,-50%);opacity:0}.tippy-popper[x-placement^=left] [data-animation=shift-toward][data-state=visible]{opacity:1;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=shift-toward][data-state=hidden]{opacity:0;-webkit-transform:translateX(-20px);transform:translateX(-20px)}.tippy-popper[x-placement^=left] [data-animation=perspective]{-webkit-transform-origin:right;transform-origin:right}.tippy-popper[x-placement^=left] [data-animation=perspective][data-state=visible]{opacity:1;-webkit-transform:translateX(-10px) rotateY(0);transform:translateX(-10px) rotateY(0)}.tippy-popper[x-placement^=left] [data-animation=perspective][data-state=hidden]{opacity:0;-webkit-transform:translateX(0) rotateY(-90deg);transform:translateX(0) rotateY(-90deg)}.tippy-popper[x-placement^=left] [data-animation=fade][data-state=visible]{opacity:1;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=fade][data-state=hidden]{opacity:0;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=shift-away][data-state=visible]{opacity:1;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=shift-away][data-state=hidden]{opacity:0;-webkit-transform:translateX(0);transform:translateX(0)}.tippy-popper[x-placement^=left] [data-animation=scale][data-state=visible]{opacity:1;-webkit-transform:translateX(-10px) scale(1);transform:translateX(-10px) scale(1)}.tippy-popper[x-placement^=left] [data-animation=scale][data-state=hidden]{opacity:0;-webkit-transform:translateX(0) scale(0);transform:translateX(0) scale(0)}.tippy-popper[x-placement^=right] .tippy-backdrop{border-radius:0 50% 50% 0}.tippy-popper[x-placement^=right] .tippy-roundarrow{left:-16px;-webkit-transform-origin:66.66666666% 50%;transform-origin:66.66666666% 50%}.tippy-popper[x-placement^=right] .tippy-roundarrow svg{position:absolute;left:0;-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.tippy-popper[x-placement^=right] .tippy-arrow{border-right:7px solid #333;border-top:7px solid transparent;border-bottom:7px solid transparent;left:-7px;margin:3px 0;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.tippy-popper[x-placement^=right] .tippy-backdrop{-webkit-transform-origin:-100% 0;transform-origin:-100% 0}.tippy-popper[x-placement^=right] .tippy-backdrop[data-state=visible]{-webkit-transform:scale(6) translate(-140%,-50%);transform:scale(6) translate(-140%,-50%);opacity:1}.tippy-popper[x-placement^=right] .tippy-backdrop[data-state=hidden]{-webkit-transform:scale(1.5) translate(-140%,-50%);transform:scale(1.5) translate(-140%,-50%);opacity:0}.tippy-popper[x-placement^=right] [data-animation=shift-toward][data-state=visible]{opacity:1;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=shift-toward][data-state=hidden]{opacity:0;-webkit-transform:translateX(20px);transform:translateX(20px)}.tippy-popper[x-placement^=right] [data-animation=perspective]{-webkit-transform-origin:left;transform-origin:left}.tippy-popper[x-placement^=right] [data-animation=perspective][data-state=visible]{opacity:1;-webkit-transform:translateX(10px) rotateY(0);transform:translateX(10px) rotateY(0)}.tippy-popper[x-placement^=right] [data-animation=perspective][data-state=hidden]{opacity:0;-webkit-transform:translateX(0) rotateY(90deg);transform:translateX(0) rotateY(90deg)}.tippy-popper[x-placement^=right] [data-animation=fade][data-state=visible]{opacity:1;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=fade][data-state=hidden]{opacity:0;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=shift-away][data-state=visible]{opacity:1;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=shift-away][data-state=hidden]{opacity:0;-webkit-transform:translateX(0);transform:translateX(0)}.tippy-popper[x-placement^=right] [data-animation=scale][data-state=visible]{opacity:1;-webkit-transform:translateX(10px) scale(1);transform:translateX(10px) scale(1)}.tippy-popper[x-placement^=right] [data-animation=scale][data-state=hidden]{opacity:0;-webkit-transform:translateX(0) scale(0);transform:translateX(0) scale(0)}.tippy-tooltip{position:relative;color:#fff;border-radius:4px;font-size:.9rem;padding:.3rem .6rem;text-align:center;will-change:transform;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#333}.tippy-tooltip[data-size=small]{padding:.2rem .4rem;font-size:.75rem}.tippy-tooltip[data-size=large]{padding:.4rem .8rem;font-size:1rem}.tippy-tooltip[data-animatefill]{overflow:hidden;background-color:transparent}.tippy-tooltip[data-animatefill] .tippy-content{transition:-webkit-clip-path cubic-bezier(.46,.1,.52,.98);transition:clip-path cubic-bezier(.46,.1,.52,.98);transition:clip-path cubic-bezier(.46,.1,.52,.98),-webkit-clip-path cubic-bezier(.46,.1,.52,.98)}.tippy-tooltip[data-interactive],.tippy-tooltip[data-interactive] path{pointer-events:auto}.tippy-tooltip[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.53,2,.36,.85)}.tippy-tooltip[data-inertia][data-state=hidden]{transition-timing-function:ease}.tippy-arrow,.tippy-roundarrow{position:absolute;width:0;height:0}.tippy-roundarrow{width:24px;height:8px;fill:#333;pointer-events:none}.tippy-backdrop{position:absolute;will-change:transform;background-color:#333;border-radius:50%;width:26%;left:50%;top:50%;z-index:-1;transition:all cubic-bezier(.46,.1,.52,.98);-webkit-backface-visibility:hidden;backface-visibility:hidden}.tippy-backdrop:after{content:\"\";float:left;padding-top:100%}body:not(.tippy-touch) .tippy-tooltip[data-animatefill][data-state=visible] .tippy-content{-webkit-clip-path:ellipse(100% 100% at 50% 50%);clip-path:ellipse(100% 100% at 50% 50%)}body:not(.tippy-touch) .tippy-tooltip[data-animatefill][data-state=hidden] .tippy-content{-webkit-clip-path:ellipse(5% 50% at 50% 50%);clip-path:ellipse(5% 50% at 50% 50%)}body:not(.tippy-touch) .tippy-popper[x-placement=right] .tippy-tooltip[data-animatefill][data-state=visible] .tippy-content{-webkit-clip-path:ellipse(135% 100% at 0 50%);clip-path:ellipse(135% 100% at 0 50%)}body:not(.tippy-touch) .tippy-popper[x-placement=right] .tippy-tooltip[data-animatefill][data-state=hidden] .tippy-content{-webkit-clip-path:ellipse(40% 100% at 0 50%);clip-path:ellipse(40% 100% at 0 50%)}body:not(.tippy-touch) .tippy-popper[x-placement=left] .tippy-tooltip[data-animatefill][data-state=visible] .tippy-content{-webkit-clip-path:ellipse(135% 100% at 100% 50%);clip-path:ellipse(135% 100% at 100% 50%)}body:not(.tippy-touch) .tippy-popper[x-placement=left] .tippy-tooltip[data-animatefill][data-state=hidden] .tippy-content{-webkit-clip-path:ellipse(40% 100% at 100% 50%);clip-path:ellipse(40% 100% at 100% 50%)}@media (max-width:360px){.tippy-popper{max-width:96%;max-width:calc(100% - 20px)}}"; var version = "2.5.4"; var isBrowser = typeof window !== 'undefined'; var isIE = isBrowser && /MSIE |Trident\//.test(navigator.userAgent); var browser = {}; if (isBrowser) { browser.supported = 'requestAnimationFrame' in window; browser.supportsTouch = 'ontouchstart' in window; browser.usingTouch = false; browser.dynamicInputDetection = true; browser.iOS = /iPhone|iPad|iPod/.test(navigator.platform) && !window.MSStream; browser.onUserInputChange = function () {}; } /** * Selector constants used for grabbing elements */ var selectors = { POPPER: '.tippy-popper', TOOLTIP: '.tippy-tooltip', CONTENT: '.tippy-content', BACKDROP: '.tippy-backdrop', ARROW: '.tippy-arrow', ROUND_ARROW: '.tippy-roundarrow', REFERENCE: '[data-tippy]' }; var defaults = { placement: 'top', livePlacement: true, trigger: 'mouseenter focus', animation: 'shift-away', html: false, animateFill: true, arrow: false, delay: 0, duration: [350, 300], interactive: false, interactiveBorder: 2, theme: 'dark', size: 'regular', distance: 10, offset: 0, hideOnClick: true, multiple: false, followCursor: false, inertia: false, updateDuration: 350, sticky: false, appendTo: function appendTo() { return document.body; }, zIndex: 9999, touchHold: false, performance: false, dynamicTitle: false, flip: true, flipBehavior: 'flip', arrowType: 'sharp', arrowTransform: '', maxWidth: '', target: null, allowTitleHTML: true, popperOptions: {}, createPopperInstanceOnInit: false, onShow: function onShow() {}, onShown: function onShown() {}, onHide: function onHide() {}, onHidden: function onHidden() {} }; /** * The keys of the defaults object for reducing down into a new object * Used in `getIndividualOptions()` */ var defaultsKeys = browser.supported && Object.keys(defaults); /** * Determines if a value is an object literal * @param {*} value * @return {Boolean} */ function isObjectLiteral(value) { return {}.toString.call(value) === '[object Object]'; } /** * Ponyfill for Array.from * @param {*} value * @return {Array} */ function toArray(value) { return [].slice.call(value); } /** * Returns an array of elements based on the selector input * @param {String|Element|Element[]|NodeList|Object} selector * @return {Element[]} */ function getArrayOfElements(selector) { if (selector instanceof Element || isObjectLiteral(selector)) { return [selector]; } if (selector instanceof NodeList) { return toArray(selector); } if (Array.isArray(selector)) { return selector; } try { return toArray(document.querySelectorAll(selector)); } catch (_) { return []; } } /** * Polyfills needed props/methods for a virtual reference object * NOTE: in v3.0 this will be pure * @param {Object} reference */ function polyfillVirtualReferenceProps(reference) { reference.refObj = true; reference.attributes = reference.attributes || {}; reference.setAttribute = function (key, val) { reference.attributes[key] = val; }; reference.getAttribute = function (key) { return reference.attributes[key]; }; reference.removeAttribute = function (key) { delete reference.attributes[key]; }; reference.hasAttribute = function (key) { return key in reference.attributes; }; reference.addEventListener = function () {}; reference.removeEventListener = function () {}; reference.classList = { classNames: {}, add: function add(key) { return reference.classList.classNames[key] = true; }, remove: function remove(key) { delete reference.classList.classNames[key]; return true; }, contains: function contains(key) { return key in reference.classList.classNames; } }; } /** * Returns the supported prefixed property - only `webkit` is needed, `moz`, `ms` and `o` are obsolete * @param {String} property * @return {String} - browser supported prefixed property */ function prefix(property) { var prefixes = ['', 'webkit']; var upperProp = property.charAt(0).toUpperCase() + property.slice(1); for (var i = 0; i < prefixes.length; i++) { var _prefix = prefixes[i]; var prefixedProp = _prefix ? _prefix + upperProp : property; if (typeof document.body.style[prefixedProp] !== 'undefined') { return prefixedProp; } } return null; } /** * Creates a div element * @return {Element} */ function div() { return document.createElement('div'); } /** * Creates a popper element then returns it * @param {Number} id - the popper id * @param {String} title - the tooltip's `title` attribute * @param {Object} options - individual options * @return {Element} - the popper element */ function createPopperElement(id, title, options) { var popper = div(); popper.setAttribute('class', 'tippy-popper'); popper.setAttribute('role', 'tooltip'); popper.setAttribute('id', 'tippy-' + id); popper.style.zIndex = options.zIndex; popper.style.maxWidth = options.maxWidth; var tooltip = div(); tooltip.setAttribute('class', 'tippy-tooltip'); tooltip.setAttribute('data-size', options.size); tooltip.setAttribute('data-animation', options.animation); tooltip.setAttribute('data-state', 'hidden'); options.theme.split(' ').forEach(function (t) { tooltip.classList.add(t + '-theme'); }); var content = div(); content.setAttribute('class', 'tippy-content'); if (options.arrow) { var arrow = div(); arrow.style[prefix('transform')] = options.arrowTransform; if (options.arrowType === 'round') { arrow.classList.add('tippy-roundarrow'); arrow.innerHTML = ''; } else { arrow.classList.add('tippy-arrow'); } tooltip.appendChild(arrow); } if (options.animateFill) { // Create animateFill circle element for animation tooltip.setAttribute('data-animatefill', ''); var backdrop = div(); backdrop.classList.add('tippy-backdrop'); backdrop.setAttribute('data-state', 'hidden'); tooltip.appendChild(backdrop); } if (options.inertia) { // Change transition timing function cubic bezier tooltip.setAttribute('data-inertia', ''); } if (options.interactive) { tooltip.setAttribute('data-interactive', ''); } var html = options.html; if (html) { var templateId = void 0; if (html instanceof Element) { content.appendChild(html); templateId = '#' + (html.id || 'tippy-html-template'); } else { // trick linters: https://github.com/atomiks/tippyjs/issues/197 //content[true && 'innerHTML'] = document.querySelector(html)[true && 'innerHTML']; templateId = html; } popper.setAttribute('data-html', ''); tooltip.setAttribute('data-template-id', templateId); if (options.interactive) { popper.setAttribute('tabindex', '-1'); } } else { content[options.allowTitleHTML ? 'innerHTML' : 'textContent'] = title; } tooltip.appendChild(content); popper.appendChild(tooltip); return popper; } /** * Creates a trigger by adding the necessary event listeners to the reference element * @param {String} eventType - the custom event specified in the `trigger` setting * @param {Element} reference * @param {Object} handlers - the handlers for each event * @param {Object} options * @return {Array} - array of listener objects */ function createTrigger(eventType, reference, handlers, options) { var onTrigger = handlers.onTrigger, onMouseLeave = handlers.onMouseLeave, onBlur = handlers.onBlur, onDelegateShow = handlers.onDelegateShow, onDelegateHide = handlers.onDelegateHide; var listeners = []; if (eventType === 'manual') return listeners; var on = function on(eventType, handler) { reference.addEventListener(eventType, handler); listeners.push({ event: eventType, handler: handler }); }; if (!options.target) { on(eventType, onTrigger); if (browser.supportsTouch && options.touchHold) { on('touchstart', onTrigger); on('touchend', onMouseLeave); } if (eventType === 'mouseenter') { on('mouseleave', onMouseLeave); } if (eventType === 'focus') { on(isIE ? 'focusout' : 'blur', onBlur); } } else { if (browser.supportsTouch && options.touchHold) { on('touchstart', onDelegateShow); on('touchend', onDelegateHide); } if (eventType === 'mouseenter') { on('mouseover', onDelegateShow); on('mouseout', onDelegateHide); } if (eventType === 'focus') { on('focusin', onDelegateShow); on('focusout', onDelegateHide); } if (eventType === 'click') { on('click', onDelegateShow); } } return listeners; } var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * Returns an object of settings to override global settings * @param {Element} reference * @param {Object} instanceOptions * @return {Object} - individual options */ function getIndividualOptions(reference, instanceOptions) { var options = defaultsKeys.reduce(function (acc, key) { var val = reference.getAttribute('data-tippy-' + key.toLowerCase()) || instanceOptions[key]; // Convert strings to booleans if (val === 'false') val = false; if (val === 'true') val = true; // Convert number strings to true numbers if (isFinite(val) && !isNaN(parseFloat(val))) { val = parseFloat(val); } // Convert array strings to actual arrays if (key !== 'target' && typeof val === 'string' && val.trim().charAt(0) === '[') { val = JSON.parse(val); } acc[key] = val; return acc; }, {}); return _extends({}, instanceOptions, options); } /** * Evaluates/modifies the options object for appropriate behavior * @param {Element|Object} reference * @param {Object} options * @return {Object} modified/evaluated options */ function evaluateOptions(reference, options) { // animateFill is disabled if an arrow is true if (options.arrow) { options.animateFill = false; } if (options.appendTo && typeof options.appendTo === 'function') { options.appendTo = options.appendTo(); } if (typeof options.html === 'function') { options.html = options.html(reference); } return options; } /** * Returns inner elements of the popper element * @param {Element} popper * @return {Object} */ function getInnerElements(popper) { var select = function select(s) { return popper.querySelector(s); }; return { tooltip: select(selectors.TOOLTIP), backdrop: select(selectors.BACKDROP), content: select(selectors.CONTENT), arrow: select(selectors.ARROW) || select(selectors.ROUND_ARROW) }; } /** * Removes the title from an element, setting `data-original-title` * appropriately * @param {Element} el */ function removeTitle(el) { var title = el.getAttribute('title'); // Only set `data-original-title` attr if there is a title if (title) { el.setAttribute('data-original-title', title); } el.removeAttribute('title'); } /**! * @fileOverview Kickass library to create and place poppers near their reference elements. * @version 1.14.3 * @license * Copyright (c) 2016 Federico Zivolo and contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ var isBrowser$1 = typeof window !== 'undefined' && typeof document !== 'undefined'; var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox']; var timeoutDuration = 0; for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) { if (isBrowser$1 && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) { timeoutDuration = 1; break; } } function microtaskDebounce(fn) { var called = false; return function () { if (called) { return; } called = true; window.Promise.resolve().then(function () { called = false; fn(); }); }; } function taskDebounce(fn) { var scheduled = false; return function () { if (!scheduled) { scheduled = true; setTimeout(function () { scheduled = false; fn(); }, timeoutDuration); } }; } var supportsMicroTasks = isBrowser$1 && window.Promise; /** * Create a debounced version of a method, that's asynchronously deferred * but called in the minimum time possible. * * @method * @memberof Popper.Utils * @argument {Function} fn * @returns {Function} */ var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce; /** * Check if the given variable is a function * @method * @memberof Popper.Utils * @argument {Any} functionToCheck - variable to check * @returns {Boolean} answer to: is a function? */ function isFunction(functionToCheck) { var getType = {}; return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; } /** * Get CSS computed property of the given element * @method * @memberof Popper.Utils * @argument {Eement} element * @argument {String} property */ function getStyleComputedProperty(element, property) { if (element.nodeType !== 1) { return []; } // NOTE: 1 DOM access here var css = getComputedStyle(element, null); return property ? css[property] : css; } /** * Returns the parentNode or the host of the element * @method * @memberof Popper.Utils * @argument {Element} element * @returns {Element} parent */ function getParentNode(element) { if (element.nodeName === 'HTML') { return element; } return element.parentNode || element.host; } /** * Returns the scrolling parent of the given element * @method * @memberof Popper.Utils * @argument {Element} element * @returns {Element} scroll parent */ function getScrollParent(element) { // Return body, `getScroll` will take care to get the correct `scrollTop` from it if (!element) { return document.body; } switch (element.nodeName) { case 'HTML': case 'BODY': return element.ownerDocument.body; case '#document': return element.body; } // Firefox want us to check `-x` and `-y` variations as well var _getStyleComputedProp = getStyleComputedProperty(element), overflow = _getStyleComputedProp.overflow, overflowX = _getStyleComputedProp.overflowX, overflowY = _getStyleComputedProp.overflowY; if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) { return element; } return getScrollParent(getParentNode(element)); } var isIE11 = isBrowser$1 && !!(window.MSInputMethodContext && document.documentMode); var isIE10 = isBrowser$1 && /MSIE 10/.test(navigator.userAgent); /** * Determines if the browser is Internet Explorer * @method * @memberof Popper.Utils * @param {Number} version to check * @returns {Boolean} isIE */ function isIE$1(version) { if (version === 11) { return isIE11; } if (version === 10) { return isIE10; } return isIE11 || isIE10; } /** * Returns the offset parent of the given element * @method * @memberof Popper.Utils * @argument {Element} element * @returns {Element} offset parent */ function getOffsetParent(element) { if (!element) { return document.documentElement; } var noOffsetParent = isIE$1(10) ? document.body : null; // NOTE: 1 DOM access here var offsetParent = element.offsetParent; // Skip hidden elements which don't have an offsetParent while (offsetParent === noOffsetParent && element.nextElementSibling) { offsetParent = (element = element.nextElementSibling).offsetParent; } var nodeName = offsetParent && offsetParent.nodeName; if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') { return element ? element.ownerDocument.documentElement : document.documentElement; } // .offsetParent will return the closest TD or TABLE in case // no offsetParent is present, I hate this job... if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') { return getOffsetParent(offsetParent); } return offsetParent; } function isOffsetContainer(element) { var nodeName = element.nodeName; if (nodeName === 'BODY') { return false; } return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element; } /** * Finds the root node (document, shadowDOM root) of the given element * @method * @memberof Popper.Utils * @argument {Element} node * @returns {Element} root node */ function getRoot(node) { if (node.parentNode !== null) { return getRoot(node.parentNode); } return node; } /** * Finds the offset parent common to the two provided nodes * @method * @memberof Popper.Utils * @argument {Element} element1 * @argument {Element} element2 * @returns {Element} common offset parent */ function findCommonOffsetParent(element1, element2) { // This check is needed to avoid errors in case one of the elements isn't defined for any reason if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) { return document.documentElement; } // Here we make sure to give as "start" the element that comes first in the DOM var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING; var start = order ? element1 : element2; var end = order ? element2 : element1; // Get common ancestor container var range = document.createRange(); range.setStart(start, 0); range.setEnd(end, 0); var commonAncestorContainer = range.commonAncestorContainer; // Both nodes are inside #document if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) { if (isOffsetContainer(commonAncestorContainer)) { return commonAncestorContainer; } return getOffsetParent(commonAncestorContainer); } // one of the nodes is inside shadowDOM, find which one var element1root = getRoot(element1); if (element1root.host) { return findCommonOffsetParent(element1root.host, element2); } else { return findCommonOffsetParent(element1, getRoot(element2).host); } } /** * Gets the scroll value of the given element in the given side (top and left) * @method * @memberof Popper.Utils * @argument {Element} element * @argument {String} side `top` or `left` * @returns {number} amount of scrolled pixels */ function getScroll(element) { var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top'; var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft'; var nodeName = element.nodeName; if (nodeName === 'BODY' || nodeName === 'HTML') { var html = element.ownerDocument.documentElement; var scrollingElement = element.ownerDocument.scrollingElement || html; return scrollingElement[upperSide]; } return element[upperSide]; } /* * Sum or subtract the element scroll values (left and top) from a given rect object * @method * @memberof Popper.Utils * @param {Object} rect - Rect object you want to change * @param {HTMLElement} element - The element from the function reads the scroll values * @param {Boolean} subtract - set to true if you want to subtract the scroll values * @return {Object} rect - The modifier rect object */ function includeScroll(rect, element) { var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var scrollTop = getScroll(element, 'top'); var scrollLeft = getScroll(element, 'left'); var modifier = subtract ? -1 : 1; rect.top += scrollTop * modifier; rect.bottom += scrollTop * modifier; rect.left += scrollLeft * modifier; rect.right += scrollLeft * modifier; return rect; } /* * Helper to detect borders of a given element * @method * @memberof Popper.Utils * @param {CSSStyleDeclaration} styles * Result of `getStyleComputedProperty` on the given element * @param {String} axis - `x` or `y` * @return {number} borders - The borders size of the given axis */ function getBordersSize(styles, axis) { var sideA = axis === 'x' ? 'Left' : 'Top'; var sideB = sideA === 'Left' ? 'Right' : 'Bottom'; return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10); } function getSize(axis, body, html, computedStyle) { return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE$1(10) ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0); } function getWindowSizes() { var body = document.body; var html = document.documentElement; var computedStyle = isIE$1(10) && getComputedStyle(html); return { height: getSize('Height', body, html, computedStyle), width: getSize('Width', body, html, computedStyle) }; } var classCallCheck$1 = function classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass$1 = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var defineProperty$1 = function defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }; var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * Given element offsets, generate an output similar to getBoundingClientRect * @method * @memberof Popper.Utils * @argument {Object} offsets * @returns {Object} ClientRect like output */ function getClientRect(offsets) { return _extends$1({}, offsets, { right: offsets.left + offsets.width, bottom: offsets.top + offsets.height }); } /** * Get bounding client rect of given element * @method * @memberof Popper.Utils * @param {HTMLElement} element * @return {Object} client rect */ function getBoundingClientRect(element) { var rect = {}; // IE10 10 FIX: Please, don't ask, the element isn't // considered in DOM in some circumstances... // This isn't reproducible in IE10 compatibility mode of IE11 try { if (isIE$1(10)) { rect = element.getBoundingClientRect(); var scrollTop = getScroll(element, 'top'); var scrollLeft = getScroll(element, 'left'); rect.top += scrollTop; rect.left += scrollLeft; rect.bottom += scrollTop; rect.right += scrollLeft; } else { rect = element.getBoundingClientRect(); } } catch (e) {} var result = { left: rect.left, top: rect.top, width: rect.right - rect.left, height: rect.bottom - rect.top }; // subtract scrollbar size from sizes var sizes = element.nodeName === 'HTML' ? getWindowSizes() : {}; var width = sizes.width || element.clientWidth || result.right - result.left; var height = sizes.height || element.clientHeight || result.bottom - result.top; var horizScrollbar = element.offsetWidth - width; var vertScrollbar = element.offsetHeight - height; // if an hypothetical scrollbar is detected, we must be sure it's not a `border` // we make this check conditional for performance reasons if (horizScrollbar || vertScrollbar) { var styles = getStyleComputedProperty(element); horizScrollbar -= getBordersSize(styles, 'x'); vertScrollbar -= getBordersSize(styles, 'y'); result.width -= horizScrollbar; result.height -= vertScrollbar; } return getClientRect(result); } function getOffsetRectRelativeToArbitraryNode(children, parent) { var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var isIE10 = isIE$1(10); var isHTML = parent.nodeName === 'HTML'; var childrenRect = getBoundingClientRect(children); var parentRect = getBoundingClientRect(parent); var scrollParent = getScrollParent(children); var styles = getStyleComputedProperty(parent); var borderTopWidth = parseFloat(styles.borderTopWidth, 10); var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10); // In cases where the parent is fixed, we must ignore negative scroll in offset calc if (fixedPosition && parent.nodeName === 'HTML') { parentRect.top = Math.max(parentRect.top, 0); parentRect.left = Math.max(parentRect.left, 0); } var offsets = getClientRect({ top: childrenRect.top - parentRect.top - borderTopWidth, left: childrenRect.left - parentRect.left - borderLeftWidth, width: childrenRect.width, height: childrenRect.height }); offsets.marginTop = 0; offsets.marginLeft = 0; // Subtract margins of documentElement in case it's being used as parent // we do this only on HTML because it's the only element that behaves // differently when margins are applied to it. The margins are included in // the box of the documentElement, in the other cases not. if (!isIE10 && isHTML) { var marginTop = parseFloat(styles.marginTop, 10); var marginLeft = parseFloat(styles.marginLeft, 10); offsets.top -= borderTopWidth - marginTop; offsets.bottom -= borderTopWidth - marginTop; offsets.left -= borderLeftWidth - marginLeft; offsets.right -= borderLeftWidth - marginLeft; // Attach marginTop and marginLeft because in some circumstances we may need them offsets.marginTop = marginTop; offsets.marginLeft = marginLeft; } if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') { offsets = includeScroll(offsets, parent); } return offsets; } function getViewportOffsetRectRelativeToArtbitraryNode(element) { var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var html = element.ownerDocument.documentElement; var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html); var width = Math.max(html.clientWidth, window.innerWidth || 0); var height = Math.max(html.clientHeight, window.innerHeight || 0); var scrollTop = !excludeScroll ? getScroll(html) : 0; var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0; var offset = { top: scrollTop - relativeOffset.top + relativeOffset.marginTop, left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft, width: width, height: height }; return getClientRect(offset); } /** * Check if the given element is fixed or is inside a fixed parent * @method * @memberof Popper.Utils * @argument {Element} element * @argument {Element} customContainer * @returns {Boolean} answer to "isFixed?" */ function isFixed(element) { var nodeName = element.nodeName; if (nodeName === 'BODY' || nodeName === 'HTML') { return false; } if (getStyleComputedProperty(element, 'position') === 'fixed') { return true; } return isFixed(getParentNode(element)); } /** * Finds the first parent of an element that has a transformed property defined * @method * @memberof Popper.Utils * @argument {Element} element * @returns {Element} first transformed parent or documentElement */ function getFixedPositionOffsetParent(element) { // This check is needed to avoid errors in case one of the elements isn't defined for any reason if (!element || !element.parentElement || isIE$1()) { return document.documentElement; } var el = element.parentElement; while (el && getStyleComputedProperty(el, 'transform') === 'none') { el = el.parentElement; } return el || document.documentElement; } /** * Computed the boundaries limits and return them * @method * @memberof Popper.Utils * @param {HTMLElement} popper * @param {HTMLElement} reference * @param {number} padding * @param {HTMLElement} boundariesElement - Element used to define the boundaries * @param {Boolean} fixedPosition - Is in fixed position mode * @returns {Object} Coordinates of the boundaries */ function getBoundaries(popper, reference, padding, boundariesElement) { var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; // NOTE: 1 DOM access here var boundaries = { top: 0, left: 0 }; var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference); // Handle viewport case if (boundariesElement === 'viewport') { boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition); } else { // Handle other cases based on DOM element used as boundaries var boundariesNode = void 0; if (boundariesElement === 'scrollParent') { boundariesNode = getScrollParent(getParentNode(reference)); if (boundariesNode.nodeName === 'BODY') { boundariesNode = popper.ownerDocument.documentElement; } } else if (boundariesElement === 'window') { boundariesNode = popper.ownerDocument.documentElement; } else { boundariesNode = boundariesElement; } var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition); // In case of HTML, we need a different computation if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) { var _getWindowSizes = getWindowSizes(), height = _getWindowSizes.height, width = _getWindowSizes.width; boundaries.top += offsets.top - offsets.marginTop; boundaries.bottom = height + offsets.top; boundaries.left += offsets.left - offsets.marginLeft; boundaries.right = width + offsets.left; } else { // for all the other DOM elements, this one is good boundaries = offsets; } } // Add paddings boundaries.left += padding; boundaries.top += padding; boundaries.right -= padding; boundaries.bottom -= padding; return boundaries; } function getArea(_ref) { var width = _ref.width, height = _ref.height; return width * height; } /** * Utility used to transform the `auto` placement to the placement with more * available space. * @method * @memberof Popper.Utils * @argument {Object} data - The data object generated by update method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) { var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0; if (placement.indexOf('auto') === -1) { return placement; } var boundaries = getBoundaries(popper, reference, padding, boundariesElement); var rects = { top: { width: boundaries.width, height: refRect.top - boundaries.top }, right: { width: boundaries.right - refRect.right, height: boundaries.height }, bottom: { width: boundaries.width, height: boundaries.bottom - refRect.bottom }, left: { width: refRect.left - boundaries.left, height: boundaries.height } }; var sortedAreas = Object.keys(rects).map(function (key) { return _extends$1({ key: key }, rects[key], { area: getArea(rects[key]) }); }).sort(function (a, b) { return b.area - a.area; }); var filteredAreas = sortedAreas.filter(function (_ref2) { var width = _ref2.width, height = _ref2.height; return width >= popper.clientWidth && height >= popper.clientHeight; }); var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key; var variation = placement.split('-')[1]; return computedPlacement + (variation ? '-' + variation : ''); } /** * Get offsets to the reference element * @method * @memberof Popper.Utils * @param {Object} state * @param {Element} popper - the popper element * @param {Element} reference - the reference element (the popper will be relative to this) * @param {Element} fixedPosition - is in fixed position mode * @returns {Object} An object containing the offsets which will be applied to the popper */ function getReferenceOffsets(state, popper, reference) { var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference); return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition); } /** * Get the outer sizes of the given element (offset size + margins) * @method * @memberof Popper.Utils * @argument {Element} element * @returns {Object} object containing width and height properties */ function getOuterSizes(element) { var styles = getComputedStyle(element); var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom); var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight); var result = { width: element.offsetWidth + y, height: element.offsetHeight + x }; return result; } /** * Get the opposite placement of the given one * @method * @memberof Popper.Utils * @argument {String} placement * @returns {String} flipped placement */ function getOppositePlacement(placement) { var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; return placement.replace(/left|right|bottom|top/g, function (matched) { return hash[matched]; }); } /** * Get offsets to the popper * @method * @memberof Popper.Utils * @param {Object} position - CSS position the Popper will get applied * @param {HTMLElement} popper - the popper element * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this) * @param {String} placement - one of the valid placement options * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper */ function getPopperOffsets(popper, referenceOffsets, placement) { placement = placement.split('-')[0]; // Get popper node sizes var popperRect = getOuterSizes(popper); // Add position, width and height to our offsets object var popperOffsets = { width: popperRect.width, height: popperRect.height }; // depending by the popper placement we have to compute its offsets slightly differently var isHoriz = ['right', 'left'].indexOf(placement) !== -1; var mainSide = isHoriz ? 'top' : 'left'; var secondarySide = isHoriz ? 'left' : 'top'; var measurement = isHoriz ? 'height' : 'width'; var secondaryMeasurement = !isHoriz ? 'height' : 'width'; popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2; if (placement === secondarySide) { popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement]; } else { popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)]; } return popperOffsets; } /** * Mimics the `find` method of Array * @method * @memberof Popper.Utils * @argument {Array} arr * @argument prop * @argument value * @returns index or -1 */ function find(arr, check) { // use native find if supported if (Array.prototype.find) { return arr.find(check); } // use `filter` to obtain the same behavior of `find` return arr.filter(check)[0]; } /** * Return the index of the matching object * @method * @memberof Popper.Utils * @argument {Array} arr * @argument prop * @argument value * @returns index or -1 */ function findIndex(arr, prop, value) { // use native findIndex if supported if (Array.prototype.findIndex) { return arr.findIndex(function (cur) { return cur[prop] === value; }); } // use `find` + `indexOf` if `findIndex` isn't supported var match = find(arr, function (obj) { return obj[prop] === value; }); return arr.indexOf(match); } /** * Loop trough the list of modifiers and run them in order, * each of them will then edit the data object. * @method * @memberof Popper.Utils * @param {dataObject} data * @param {Array} modifiers * @param {String} ends - Optional modifier name used as stopper * @returns {dataObject} */ function runModifiers(modifiers, data, ends) { var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends)); modifiersToRun.forEach(function (modifier) { if (modifier['function']) { // eslint-disable-line dot-notation console.warn('`modifier.function` is deprecated, use `modifier.fn`!'); } var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation if (modifier.enabled && isFunction(fn)) { // Add properties to offsets to make them a complete clientRect object // we do this before each modifier to make sure the previous one doesn't // mess with these values data.offsets.popper = getClientRect(data.offsets.popper); data.offsets.reference = getClientRect(data.offsets.reference); data = fn(data, modifier); } }); return data; } /** * Updates the position of the popper, computing the new offsets and applying * the new style.
* Prefer `scheduleUpdate` over `update` because of performance reasons. * @method * @memberof Popper */ function update() { // if popper is destroyed, don't perform any further update if (this.state.isDestroyed) { return; } var data = { instance: this, styles: {}, arrowStyles: {}, attributes: {}, flipped: false, offsets: {} }; // compute reference element offsets data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed); // compute auto placement, store placement inside the data object, // modifiers will be able to edit `placement` if needed // and refer to originalPlacement to know the original value data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding); // store the computed placement inside `originalPlacement` data.originalPlacement = data.placement; data.positionFixed = this.options.positionFixed; // compute the popper offsets data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement); data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute'; // run the modifiers data = runModifiers(this.modifiers, data); // the first `update` will call `onCreate` callback // the other ones will call `onUpdate` callback if (!this.state.isCreated) { this.state.isCreated = true; this.options.onCreate(data); } else { this.options.onUpdate(data); } } /** * Helper used to know if the given modifier is enabled. * @method * @memberof Popper.Utils * @returns {Boolean} */ function isModifierEnabled(modifiers, modifierName) { return modifiers.some(function (_ref) { var name = _ref.name, enabled = _ref.enabled; return enabled && name === modifierName; }); } /** * Get the prefixed supported property name * @method * @memberof Popper.Utils * @argument {String} property (camelCase) * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix) */ function getSupportedPropertyName(property) { var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O']; var upperProp = property.charAt(0).toUpperCase() + property.slice(1); for (var i = 0; i < prefixes.length; i++) { var prefix = prefixes[i]; var toCheck = prefix ? '' + prefix + upperProp : property; if (typeof document.body.style[toCheck] !== 'undefined') { return toCheck; } } return null; } /** * Destroy the popper * @method * @memberof Popper */ function destroy() { this.state.isDestroyed = true; // touch DOM only if `applyStyle` modifier is enabled if (isModifierEnabled(this.modifiers, 'applyStyle')) { this.popper.removeAttribute('x-placement'); this.popper.style.position = ''; this.popper.style.top = ''; this.popper.style.left = ''; this.popper.style.right = ''; this.popper.style.bottom = ''; this.popper.style.willChange = ''; this.popper.style[getSupportedPropertyName('transform')] = ''; } this.disableEventListeners(); // remove the popper if user explicity asked for the deletion on destroy // do not use `remove` because IE11 doesn't support it if (this.options.removeOnDestroy) { this.popper.parentNode.removeChild(this.popper); } return this; } /** * Get the window associated with the element * @argument {Element} element * @returns {Window} */ function getWindow(element) { var ownerDocument = element.ownerDocument; return ownerDocument ? ownerDocument.defaultView : window; } function attachToScrollParents(scrollParent, event, callback, scrollParents) { var isBody = scrollParent.nodeName === 'BODY'; var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent; target.addEventListener(event, callback, { passive: true }); if (!isBody) { attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents); } scrollParents.push(target); } /** * Setup needed event listeners used to update the popper position * @method * @memberof Popper.Utils * @private */ function setupEventListeners(reference, options, state, updateBound) { // Resize event listener on window state.updateBound = updateBound; getWindow(reference).addEventListener('resize', state.updateBound, { passive: true }); // Scroll event listener on scroll parents var scrollElement = getScrollParent(reference); attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents); state.scrollElement = scrollElement; state.eventsEnabled = true; return state; } /** * It will add resize/scroll events and start recalculating * position of the popper element when they are triggered. * @method * @memberof Popper */ function enableEventListeners() { if (!this.state.eventsEnabled) { this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate); } } /** * Remove event listeners used to update the popper position * @method * @memberof Popper.Utils * @private */ function removeEventListeners(reference, state) { // Remove resize event listener on window getWindow(reference).removeEventListener('resize', state.updateBound); // Remove scroll event listener on scroll parents state.scrollParents.forEach(function (target) { target.removeEventListener('scroll', state.updateBound); }); // Reset state state.updateBound = null; state.scrollParents = []; state.scrollElement = null; state.eventsEnabled = false; return state; } /** * It will remove resize/scroll events and won't recalculate popper position * when they are triggered. It also won't trigger onUpdate callback anymore, * unless you call `update` method manually. * @method * @memberof Popper */ function disableEventListeners() { if (this.state.eventsEnabled) { cancelAnimationFrame(this.scheduleUpdate); this.state = removeEventListeners(this.reference, this.state); } } /** * Tells if a given input is a number * @method * @memberof Popper.Utils * @param {*} input to check * @return {Boolean} */ function isNumeric(n) { return n !== '' && !isNaN(parseFloat(n)) && isFinite(n); } /** * Set the style to the given popper * @method * @memberof Popper.Utils * @argument {Element} element - Element to apply the style to * @argument {Object} styles * Object with a list of properties and values which will be applied to the element */ function setStyles(element, styles) { Object.keys(styles).forEach(function (prop) { var unit = ''; // add unit if the value is numeric and is one of the following if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) { unit = 'px'; } element.style[prop] = styles[prop] + unit; }); } /** * Set the attributes to the given popper * @method * @memberof Popper.Utils * @argument {Element} element - Element to apply the attributes to * @argument {Object} styles * Object with a list of properties and values which will be applied to the element */ function setAttributes(element, attributes) { Object.keys(attributes).forEach(function (prop) { var value = attributes[prop]; if (value !== false) { element.setAttribute(prop, attributes[prop]); } else { element.removeAttribute(prop); } }); } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by `update` method * @argument {Object} data.styles - List of style properties - values to apply to popper element * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element * @argument {Object} options - Modifiers configuration and options * @returns {Object} The same data object */ function applyStyle(data) { // any property present in `data.styles` will be applied to the popper, // in this way we can make the 3rd party modifiers add custom styles to it // Be aware, modifiers could override the properties defined in the previous // lines of this modifier! setStyles(data.instance.popper, data.styles); // any property present in `data.attributes` will be applied to the popper, // they will be set as HTML attributes of the element setAttributes(data.instance.popper, data.attributes); // if arrowElement is defined and arrowStyles has some properties if (data.arrowElement && Object.keys(data.arrowStyles).length) { setStyles(data.arrowElement, data.arrowStyles); } return data; } /** * Set the x-placement attribute before everything else because it could be used * to add margins to the popper margins needs to be calculated to get the * correct popper offsets. * @method * @memberof Popper.modifiers * @param {HTMLElement} reference - The reference element used to position the popper * @param {HTMLElement} popper - The HTML element used as popper * @param {Object} options - Popper.js options */ function applyStyleOnLoad(reference, popper, options, modifierOptions, state) { // compute reference element offsets var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed); // compute auto placement, store placement inside the data object, // modifiers will be able to edit `placement` if needed // and refer to originalPlacement to know the original value var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding); popper.setAttribute('x-placement', placement); // Apply `position` to popper before anything else because // without the position applied we can't guarantee correct computations setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' }); return options; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by `update` method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function computeStyle(data, options) { var x = options.x, y = options.y; var popper = data.offsets.popper; // Remove this legacy support in Popper.js v2 var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) { return modifier.name === 'applyStyle'; }).gpuAcceleration; if (legacyGpuAccelerationOption !== undefined) { console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!'); } var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration; var offsetParent = getOffsetParent(data.instance.popper); var offsetParentRect = getBoundingClientRect(offsetParent); // Styles var styles = { position: popper.position }; // Avoid blurry text by using full pixel integers. // For pixel-perfect positioning, top/bottom prefers rounded // values, while left/right prefers floored values. var offsets = { left: Math.floor(popper.left), top: Math.round(popper.top), bottom: Math.round(popper.bottom), right: Math.floor(popper.right) }; var sideA = x === 'bottom' ? 'top' : 'bottom'; var sideB = y === 'right' ? 'left' : 'right'; // if gpuAcceleration is set to `true` and transform is supported, // we use `translate3d` to apply the position to the popper we // automatically use the supported prefixed version if needed var prefixedProperty = getSupportedPropertyName('transform'); // now, let's make a step back and look at this code closely (wtf?) // If the content of the popper grows once it's been positioned, it // may happen that the popper gets misplaced because of the new content // overflowing its reference element // To avoid this problem, we provide two options (x and y), which allow // the consumer to define the offset origin. // If we position a popper on top of a reference element, we can set // `x` to `top` to make the popper grow towards its top instead of // its bottom. var left = void 0, top = void 0; if (sideA === 'bottom') { top = -offsetParentRect.height + offsets.bottom; } else { top = offsets.top; } if (sideB === 'right') { left = -offsetParentRect.width + offsets.right; } else { left = offsets.left; } if (gpuAcceleration && prefixedProperty) { styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)'; styles[sideA] = 0; styles[sideB] = 0; styles.willChange = 'transform'; } else { // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties var invertTop = sideA === 'bottom' ? -1 : 1; var invertLeft = sideB === 'right' ? -1 : 1; styles[sideA] = top * invertTop; styles[sideB] = left * invertLeft; styles.willChange = sideA + ', ' + sideB; } // Attributes var attributes = { 'x-placement': data.placement }; // Update `data` attributes, styles and arrowStyles data.attributes = _extends$1({}, attributes, data.attributes); data.styles = _extends$1({}, styles, data.styles); data.arrowStyles = _extends$1({}, data.offsets.arrow, data.arrowStyles); return data; } /** * Helper used to know if the given modifier depends from another one.
* It checks if the needed modifier is listed and enabled. * @method * @memberof Popper.Utils * @param {Array} modifiers - list of modifiers * @param {String} requestingName - name of requesting modifier * @param {String} requestedName - name of requested modifier * @returns {Boolean} */ function isModifierRequired(modifiers, requestingName, requestedName) { var requesting = find(modifiers, function (_ref) { var name = _ref.name; return name === requestingName; }); var isRequired = !!requesting && modifiers.some(function (modifier) { return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order; }); if (!isRequired) { var _requesting = '`' + requestingName + '`'; var requested = '`' + requestedName + '`'; console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!'); } return isRequired; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by update method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function arrow(data, options) { var _data$offsets$arrow; // arrow depends on keepTogether in order to work if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) { return data; } var arrowElement = options.element; // if arrowElement is a string, suppose it's a CSS selector if (typeof arrowElement === 'string') { arrowElement = data.instance.popper.querySelector(arrowElement); // if arrowElement is not found, don't run the modifier if (!arrowElement) { return data; } } else { // if the arrowElement isn't a query selector we must check that the // provided DOM node is child of its popper node if (!data.instance.popper.contains(arrowElement)) { console.warn('WARNING: `arrow.element` must be child of its popper element!'); return data; } } var placement = data.placement.split('-')[0]; var _data$offsets = data.offsets, popper = _data$offsets.popper, reference = _data$offsets.reference; var isVertical = ['left', 'right'].indexOf(placement) !== -1; var len = isVertical ? 'height' : 'width'; var sideCapitalized = isVertical ? 'Top' : 'Left'; var side = sideCapitalized.toLowerCase(); var altSide = isVertical ? 'left' : 'top'; var opSide = isVertical ? 'bottom' : 'right'; var arrowElementSize = getOuterSizes(arrowElement)[len]; // // extends keepTogether behavior making sure the popper and its // reference have enough pixels in conjuction // // top/left side if (reference[opSide] - arrowElementSize < popper[side]) { data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize); } // bottom/right side if (reference[side] + arrowElementSize > popper[opSide]) { data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide]; } data.offsets.popper = getClientRect(data.offsets.popper); // compute center of the popper var center = reference[side] + reference[len] / 2 - arrowElementSize / 2; // Compute the sideValue using the updated popper offsets // take popper margin in account because we don't have this info available var css = getStyleComputedProperty(data.instance.popper); var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10); var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10); var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide; // prevent arrowElement from being placed not contiguously to its popper sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0); data.arrowElement = arrowElement; data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty$1(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty$1(_data$offsets$arrow, altSide, ''), _data$offsets$arrow); return data; } /** * Get the opposite placement variation of the given one * @method * @memberof Popper.Utils * @argument {String} placement variation * @returns {String} flipped placement variation */ function getOppositeVariation(variation) { if (variation === 'end') { return 'start'; } else if (variation === 'start') { return 'end'; } return variation; } /** * List of accepted placements to use as values of the `placement` option.
* Valid placements are: * - `auto` * - `top` * - `right` * - `bottom` * - `left` * * Each placement can have a variation from this list: * - `-start` * - `-end` * * Variations are interpreted easily if you think of them as the left to right * written languages. Horizontally (`top` and `bottom`), `start` is left and `end` * is right.
* Vertically (`left` and `right`), `start` is top and `end` is bottom. * * Some valid examples are: * - `top-end` (on top of reference, right aligned) * - `right-start` (on right of reference, top aligned) * - `bottom` (on bottom, centered) * - `auto-right` (on the side with more space available, alignment depends by placement) * * @static * @type {Array} * @enum {String} * @readonly * @method placements * @memberof Popper */ var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start']; // Get rid of `auto` `auto-start` and `auto-end` var validPlacements = placements.slice(3); /** * Given an initial placement, returns all the subsequent placements * clockwise (or counter-clockwise). * * @method * @memberof Popper.Utils * @argument {String} placement - A valid placement (it accepts variations) * @argument {Boolean} counter - Set to true to walk the placements counterclockwise * @returns {Array} placements including their variations */ function clockwise(placement) { var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var index = validPlacements.indexOf(placement); var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index)); return counter ? arr.reverse() : arr; } var BEHAVIORS = { FLIP: 'flip', CLOCKWISE: 'clockwise', COUNTERCLOCKWISE: 'counterclockwise' }; /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by update method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function flip(data, options) { // if `inner` modifier is enabled, we can't use the `flip` modifier if (isModifierEnabled(data.instance.modifiers, 'inner')) { return data; } if (data.flipped && data.placement === data.originalPlacement) { // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides return data; } var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed); var placement = data.placement.split('-')[0]; var placementOpposite = getOppositePlacement(placement); var variation = data.placement.split('-')[1] || ''; var flipOrder = []; switch (options.behavior) { case BEHAVIORS.FLIP: flipOrder = [placement, placementOpposite]; break; case BEHAVIORS.CLOCKWISE: flipOrder = clockwise(placement); break; case BEHAVIORS.COUNTERCLOCKWISE: flipOrder = clockwise(placement, true); break; default: flipOrder = options.behavior; } flipOrder.forEach(function (step, index) { if (placement !== step || flipOrder.length === index + 1) { return data; } placement = data.placement.split('-')[0]; placementOpposite = getOppositePlacement(placement); var popperOffsets = data.offsets.popper; var refOffsets = data.offsets.reference; // using floor because the reference offsets may contain decimals we are not going to consider here var floor = Math.floor; var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom); var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left); var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right); var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top); var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom); var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom; // flip the variation if required var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom); if (overlapsRef || overflowsBoundaries || flippedVariation) { // this boolean to detect any flip loop data.flipped = true; if (overlapsRef || overflowsBoundaries) { placement = flipOrder[index + 1]; } if (flippedVariation) { variation = getOppositeVariation(variation); } data.placement = placement + (variation ? '-' + variation : ''); // this object contains `position`, we want to preserve it along with // any additional property we may add in the future data.offsets.popper = _extends$1({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement)); data = runModifiers(data.instance.modifiers, data, 'flip'); } }); return data; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by update method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function keepTogether(data) { var _data$offsets = data.offsets, popper = _data$offsets.popper, reference = _data$offsets.reference; var placement = data.placement.split('-')[0]; var floor = Math.floor; var isVertical = ['top', 'bottom'].indexOf(placement) !== -1; var side = isVertical ? 'right' : 'bottom'; var opSide = isVertical ? 'left' : 'top'; var measurement = isVertical ? 'width' : 'height'; if (popper[side] < floor(reference[opSide])) { data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement]; } if (popper[opSide] > floor(reference[side])) { data.offsets.popper[opSide] = floor(reference[side]); } return data; } /** * Converts a string containing value + unit into a px value number * @function * @memberof {modifiers~offset} * @private * @argument {String} str - Value + unit string * @argument {String} measurement - `height` or `width` * @argument {Object} popperOffsets * @argument {Object} referenceOffsets * @returns {Number|String} * Value in pixels, or original string if no values were extracted */ function toValue(str, measurement, popperOffsets, referenceOffsets) { // separate value from unit var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/); var value = +split[1]; var unit = split[2]; // If it's not a number it's an operator, I guess if (!value) { return str; } if (unit.indexOf('%') === 0) { var element = void 0; switch (unit) { case '%p': element = popperOffsets; break; case '%': case '%r': default: element = referenceOffsets; } var rect = getClientRect(element); return rect[measurement] / 100 * value; } else if (unit === 'vh' || unit === 'vw') { // if is a vh or vw, we calculate the size based on the viewport var size = void 0; if (unit === 'vh') { size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); } else { size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); } return size / 100 * value; } else { // if is an explicit pixel unit, we get rid of the unit and keep the value // if is an implicit unit, it's px, and we return just the value return value; } } /** * Parse an `offset` string to extrapolate `x` and `y` numeric offsets. * @function * @memberof {modifiers~offset} * @private * @argument {String} offset * @argument {Object} popperOffsets * @argument {Object} referenceOffsets * @argument {String} basePlacement * @returns {Array} a two cells array with x and y offsets in numbers */ function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) { var offsets = [0, 0]; // Use height if placement is left or right and index is 0 otherwise use width // in this way the first offset will use an axis and the second one // will use the other one var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1; // Split the offset string to obtain a list of values and operands // The regex addresses values with the plus or minus sign in front (+10, -20, etc) var fragments = offset.split(/(\+|\-)/).map(function (frag) { return frag.trim(); }); // Detect if the offset string contains a pair of values or a single one // they could be separated by comma or space var divider = fragments.indexOf(find(fragments, function (frag) { return frag.search(/,|\s/) !== -1; })); if (fragments[divider] && fragments[divider].indexOf(',') === -1) { console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.'); } // If divider is found, we divide the list of values and operands to divide // them by ofset X and Y. var splitRegex = /\s*,\s*|\s+/; var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments]; // Convert the values with units to absolute pixels to allow our computations ops = ops.map(function (op, index) { // Most of the units rely on the orientation of the popper var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width'; var mergeWithPrevious = false; return op // This aggregates any `+` or `-` sign that aren't considered operators // e.g.: 10 + +5 => [10, +, +5] .reduce(function (a, b) { if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) { a[a.length - 1] = b; mergeWithPrevious = true; return a; } else if (mergeWithPrevious) { a[a.length - 1] += b; mergeWithPrevious = false; return a; } else { return a.concat(b); } }, []) // Here we convert the string values into number values (in px) .map(function (str) { return toValue(str, measurement, popperOffsets, referenceOffsets); }); }); // Loop trough the offsets arrays and execute the operations ops.forEach(function (op, index) { op.forEach(function (frag, index2) { if (isNumeric(frag)) { offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1); } }); }); return offsets; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by update method * @argument {Object} options - Modifiers configuration and options * @argument {Number|String} options.offset=0 * The offset value as described in the modifier description * @returns {Object} The data object, properly modified */ function offset(data, _ref) { var offset = _ref.offset; var placement = data.placement, _data$offsets = data.offsets, popper = _data$offsets.popper, reference = _data$offsets.reference; var basePlacement = placement.split('-')[0]; var offsets = void 0; if (isNumeric(+offset)) { offsets = [+offset, 0]; } else { offsets = parseOffset(offset, popper, reference, basePlacement); } if (basePlacement === 'left') { popper.top += offsets[0]; popper.left -= offsets[1]; } else if (basePlacement === 'right') { popper.top += offsets[0]; popper.left += offsets[1]; } else if (basePlacement === 'top') { popper.left += offsets[0]; popper.top -= offsets[1]; } else if (basePlacement === 'bottom') { popper.left += offsets[0]; popper.top += offsets[1]; } data.popper = popper; return data; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by `update` method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function preventOverflow(data, options) { var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper); // If offsetParent is the reference element, we really want to // go one step up and use the next offsetParent as reference to // avoid to make this modifier completely useless and look like broken if (data.instance.reference === boundariesElement) { boundariesElement = getOffsetParent(boundariesElement); } // NOTE: DOM access here // resets the popper's position so that the document size can be calculated excluding // the size of the popper element itself var transformProp = getSupportedPropertyName('transform'); var popperStyles = data.instance.popper.style; // assignment to help minification var top = popperStyles.top, left = popperStyles.left, transform = popperStyles[transformProp]; popperStyles.top = ''; popperStyles.left = ''; popperStyles[transformProp] = ''; var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed); // NOTE: DOM access here // restores the original style properties after the offsets have been computed popperStyles.top = top; popperStyles.left = left; popperStyles[transformProp] = transform; options.boundaries = boundaries; var order = options.priority; var popper = data.offsets.popper; var check = { primary: function primary(placement) { var value = popper[placement]; if (popper[placement] < boundaries[placement] && !options.escapeWithReference) { value = Math.max(popper[placement], boundaries[placement]); } return defineProperty$1({}, placement, value); }, secondary: function secondary(placement) { var mainSide = placement === 'right' ? 'left' : 'top'; var value = popper[mainSide]; if (popper[placement] > boundaries[placement] && !options.escapeWithReference) { value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height)); } return defineProperty$1({}, mainSide, value); } }; order.forEach(function (placement) { var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary'; popper = _extends$1({}, popper, check[side](placement)); }); data.offsets.popper = popper; return data; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by `update` method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function shift(data) { var placement = data.placement; var basePlacement = placement.split('-')[0]; var shiftvariation = placement.split('-')[1]; // if shift shiftvariation is specified, run the modifier if (shiftvariation) { var _data$offsets = data.offsets, reference = _data$offsets.reference, popper = _data$offsets.popper; var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1; var side = isVertical ? 'left' : 'top'; var measurement = isVertical ? 'width' : 'height'; var shiftOffsets = { start: defineProperty$1({}, side, reference[side]), end: defineProperty$1({}, side, reference[side] + reference[measurement] - popper[measurement]) }; data.offsets.popper = _extends$1({}, popper, shiftOffsets[shiftvariation]); } return data; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by update method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function hide(data) { if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) { return data; } var refRect = data.offsets.reference; var bound = find(data.instance.modifiers, function (modifier) { return modifier.name === 'preventOverflow'; }).boundaries; if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) { // Avoid unnecessary DOM access if visibility hasn't changed if (data.hide === true) { return data; } data.hide = true; data.attributes['x-out-of-boundaries'] = ''; } else { // Avoid unnecessary DOM access if visibility hasn't changed if (data.hide === false) { return data; } data.hide = false; data.attributes['x-out-of-boundaries'] = false; } return data; } /** * @function * @memberof Modifiers * @argument {Object} data - The data object generated by `update` method * @argument {Object} options - Modifiers configuration and options * @returns {Object} The data object, properly modified */ function inner(data) { var placement = data.placement; var basePlacement = placement.split('-')[0]; var _data$offsets = data.offsets, popper = _data$offsets.popper, reference = _data$offsets.reference; var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1; var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1; popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0); data.placement = getOppositePlacement(placement); data.offsets.popper = getClientRect(popper); return data; } /** * Modifier function, each modifier can have a function of this type assigned * to its `fn` property.
* These functions will be called on each update, this means that you must * make sure they are performant enough to avoid performance bottlenecks. * * @function ModifierFn * @argument {dataObject} data - The data object generated by `update` method * @argument {Object} options - Modifiers configuration and options * @returns {dataObject} The data object, properly modified */ /** * Modifiers are plugins used to alter the behavior of your poppers.
* Popper.js uses a set of 9 modifiers to provide all the basic functionalities * needed by the library. * * Usually you don't want to override the `order`, `fn` and `onLoad` props. * All the other properties are configurations that could be tweaked. * @namespace modifiers */ var modifiers = { /** * Modifier used to shift the popper on the start or end of its reference * element.
* It will read the variation of the `placement` property.
* It can be one either `-end` or `-start`. * @memberof modifiers * @inner */ shift: { /** @prop {number} order=100 - Index used to define the order of execution */ order: 100, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: shift }, /** * The `offset` modifier can shift your popper on both its axis. * * It accepts the following units: * - `px` or unitless, interpreted as pixels * - `%` or `%r`, percentage relative to the length of the reference element * - `%p`, percentage relative to the length of the popper element * - `vw`, CSS viewport width unit * - `vh`, CSS viewport height unit * * For length is intended the main axis relative to the placement of the popper.
* This means that if the placement is `top` or `bottom`, the length will be the * `width`. In case of `left` or `right`, it will be the height. * * You can provide a single value (as `Number` or `String`), or a pair of values * as `String` divided by a comma or one (or more) white spaces.
* The latter is a deprecated method because it leads to confusion and will be * removed in v2.
* Additionally, it accepts additions and subtractions between different units. * Note that multiplications and divisions aren't supported. * * Valid examples are: * ``` * 10 * '10%' * '10, 10' * '10%, 10' * '10 + 10%' * '10 - 5vh + 3%' * '-10px + 5vh, 5px - 6%' * ``` * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap * > with their reference element, unfortunately, you will have to disable the `flip` modifier. * > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373) * * @memberof modifiers * @inner */ offset: { /** @prop {number} order=200 - Index used to define the order of execution */ order: 200, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: offset, /** @prop {Number|String} offset=0 * The offset value as described in the modifier description */ offset: 0 }, /** * Modifier used to prevent the popper from being positioned outside the boundary. * * An scenario exists where the reference itself is not within the boundaries.
* We can say it has "escaped the boundaries" — or just "escaped".
* In this case we need to decide whether the popper should either: * * - detach from the reference and remain "trapped" in the boundaries, or * - if it should ignore the boundary and "escape with its reference" * * When `escapeWithReference` is set to`true` and reference is completely * outside its boundaries, the popper will overflow (or completely leave) * the boundaries in order to remain attached to the edge of the reference. * * @memberof modifiers * @inner */ preventOverflow: { /** @prop {number} order=300 - Index used to define the order of execution */ order: 300, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: preventOverflow, /** * @prop {Array} [priority=['left','right','top','bottom']] * Popper will try to prevent overflow following these priorities by default, * then, it could overflow on the left and on top of the `boundariesElement` */ priority: ['left', 'right', 'top', 'bottom'], /** * @prop {number} padding=5 * Amount of pixel used to define a minimum distance between the boundaries * and the popper this makes sure the popper has always a little padding * between the edges of its container */ padding: 5, /** * @prop {String|HTMLElement} boundariesElement='scrollParent' * Boundaries used by the modifier, can be `scrollParent`, `window`, * `viewport` or any DOM element. */ boundariesElement: 'scrollParent' }, /** * Modifier used to make sure the reference and its popper stay near eachothers * without leaving any gap between the two. Expecially useful when the arrow is * enabled and you want to assure it to point to its reference element. * It cares only about the first axis, you can still have poppers with margin * between the popper and its reference element. * @memberof modifiers * @inner */ keepTogether: { /** @prop {number} order=400 - Index used to define the order of execution */ order: 400, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: keepTogether }, /** * This modifier is used to move the `arrowElement` of the popper to make * sure it is positioned between the reference element and its popper element. * It will read the outer size of the `arrowElement` node to detect how many * pixels of conjuction are needed. * * It has no effect if no `arrowElement` is provided. * @memberof modifiers * @inner */ arrow: { /** @prop {number} order=500 - Index used to define the order of execution */ order: 500, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: arrow, /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */ element: '[x-arrow]' }, /** * Modifier used to flip the popper's placement when it starts to overlap its * reference element. * * Requires the `preventOverflow` modifier before it in order to work. * * **NOTE:** this modifier will interrupt the current update cycle and will * restart it if it detects the need to flip the placement. * @memberof modifiers * @inner */ flip: { /** @prop {number} order=600 - Index used to define the order of execution */ order: 600, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: flip, /** * @prop {String|Array} behavior='flip' * The behavior used to change the popper's placement. It can be one of * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid * placements (with optional variations). */ behavior: 'flip', /** * @prop {number} padding=5 * The popper will flip if it hits the edges of the `boundariesElement` */ padding: 5, /** * @prop {String|HTMLElement} boundariesElement='viewport' * The element which will define the boundaries of the popper position, * the popper will never be placed outside of the defined boundaries * (except if keepTogether is enabled) */ boundariesElement: 'viewport' }, /** * Modifier used to make the popper flow toward the inner of the reference element. * By default, when this modifier is disabled, the popper will be placed outside * the reference element. * @memberof modifiers * @inner */ inner: { /** @prop {number} order=700 - Index used to define the order of execution */ order: 700, /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */ enabled: false, /** @prop {ModifierFn} */ fn: inner }, /** * Modifier used to hide the popper when its reference element is outside of the * popper boundaries. It will set a `x-out-of-boundaries` attribute which can * be used to hide with a CSS selector the popper when its reference is * out of boundaries. * * Requires the `preventOverflow` modifier before it in order to work. * @memberof modifiers * @inner */ hide: { /** @prop {number} order=800 - Index used to define the order of execution */ order: 800, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: hide }, /** * Computes the style that will be applied to the popper element to gets * properly positioned. * * Note that this modifier will not touch the DOM, it just prepares the styles * so that `applyStyle` modifier can apply it. This separation is useful * in case you need to replace `applyStyle` with a custom implementation. * * This modifier has `850` as `order` value to maintain backward compatibility * with previous versions of Popper.js. Expect the modifiers ordering method * to change in future major versions of the library. * * @memberof modifiers * @inner */ computeStyle: { /** @prop {number} order=850 - Index used to define the order of execution */ order: 850, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: computeStyle, /** * @prop {Boolean} gpuAcceleration=true * If true, it uses the CSS 3d transformation to position the popper. * Otherwise, it will use the `top` and `left` properties. */ gpuAcceleration: true, /** * @prop {string} [x='bottom'] * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin. * Change this if your popper should grow in a direction different from `bottom` */ x: 'bottom', /** * @prop {string} [x='left'] * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin. * Change this if your popper should grow in a direction different from `right` */ y: 'right' }, /** * Applies the computed styles to the popper element. * * All the DOM manipulations are limited to this modifier. This is useful in case * you want to integrate Popper.js inside a framework or view library and you * want to delegate all the DOM manipulations to it. * * Note that if you disable this modifier, you must make sure the popper element * has its position set to `absolute` before Popper.js can do its work! * * Just disable this modifier and define you own to achieve the desired effect. * * @memberof modifiers * @inner */ applyStyle: { /** @prop {number} order=900 - Index used to define the order of execution */ order: 900, /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */ enabled: true, /** @prop {ModifierFn} */ fn: applyStyle, /** @prop {Function} */ onLoad: applyStyleOnLoad, /** * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier * @prop {Boolean} gpuAcceleration=true * If true, it uses the CSS 3d transformation to position the popper. * Otherwise, it will use the `top` and `left` properties. */ gpuAcceleration: undefined } }; /** * The `dataObject` is an object containing all the informations used by Popper.js * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks. * @name dataObject * @property {Object} data.instance The Popper.js instance * @property {String} data.placement Placement applied to popper * @property {String} data.originalPlacement Placement originally defined on init * @property {Boolean} data.flipped True if popper has been flipped by flip modifier * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper. * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`) * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`) * @property {Object} data.boundaries Offsets of the popper boundaries * @property {Object} data.offsets The measurements of popper, reference and arrow elements. * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0 */ /** * Default options provided to Popper.js constructor.
* These can be overriden using the `options` argument of Popper.js.
* To override an option, simply pass as 3rd argument an object with the same * structure of this object, example: * ``` * new Popper(ref, pop, { * modifiers: { * preventOverflow: { enabled: false } * } * }) * ``` * @type {Object} * @static * @memberof Popper */ var Defaults = { /** * Popper's placement * @prop {Popper.placements} placement='bottom' */ placement: 'bottom', /** * Set this to true if you want popper to position it self in 'fixed' mode * @prop {Boolean} positionFixed=false */ positionFixed: false, /** * Whether events (resize, scroll) are initially enabled * @prop {Boolean} eventsEnabled=true */ eventsEnabled: true, /** * Set to true if you want to automatically remove the popper when * you call the `destroy` method. * @prop {Boolean} removeOnDestroy=false */ removeOnDestroy: false, /** * Callback called when the popper is created.
* By default, is set to no-op.
* Access Popper.js instance with `data.instance`. * @prop {onCreate} */ onCreate: function onCreate() {}, /** * Callback called when the popper is updated, this callback is not called * on the initialization/creation of the popper, but only on subsequent * updates.
* By default, is set to no-op.
* Access Popper.js instance with `data.instance`. * @prop {onUpdate} */ onUpdate: function onUpdate() {}, /** * List of modifiers used to modify the offsets before they are applied to the popper. * They provide most of the functionalities of Popper.js * @prop {modifiers} */ modifiers: modifiers }; /** * @callback onCreate * @param {dataObject} data */ /** * @callback onUpdate * @param {dataObject} data */ // Utils // Methods var Popper = function () { /** * Create a new Popper.js instance * @class Popper * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper * @param {HTMLElement} popper - The HTML element used as popper. * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults) * @return {Object} instance - The generated Popper.js instance */ function Popper(reference, popper) { var _this = this; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; classCallCheck$1(this, Popper); this.scheduleUpdate = function () { return requestAnimationFrame(_this.update); }; // make update() debounced, so that it only runs at most once-per-tick this.update = debounce(this.update.bind(this)); // with {} we create a new object with the options inside it this.options = _extends$1({}, Popper.Defaults, options); // init state this.state = { isDestroyed: false, isCreated: false, scrollParents: [] }; // get reference and popper elements (allow jQuery wrappers) this.reference = reference && reference.jquery ? reference[0] : reference; this.popper = popper && popper.jquery ? popper[0] : popper; // Deep merge modifiers options this.options.modifiers = {}; Object.keys(_extends$1({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) { _this.options.modifiers[name] = _extends$1({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {}); }); // Refactoring modifiers' list (Object => Array) this.modifiers = Object.keys(this.options.modifiers).map(function (name) { return _extends$1({ name: name }, _this.options.modifiers[name]); }) // sort the modifiers by order .sort(function (a, b) { return a.order - b.order; }); // modifiers have the ability to execute arbitrary code when Popper.js get inited // such code is executed in the same order of its modifier // they could add new properties to their options configuration // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`! this.modifiers.forEach(function (modifierOptions) { if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) { modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state); } }); // fire the first update to position the popper in the right place this.update(); var eventsEnabled = this.options.eventsEnabled; if (eventsEnabled) { // setup event listeners, they will take care of update the position in specific situations this.enableEventListeners(); } this.state.eventsEnabled = eventsEnabled; } // We can't use class properties because they don't get listed in the // class prototype and break stuff like Sinon stubs createClass$1(Popper, [{ key: 'update', value: function update$$1() { return update.call(this); } }, { key: 'destroy', value: function destroy$$1() { return destroy.call(this); } }, { key: 'enableEventListeners', value: function enableEventListeners$$1() { return enableEventListeners.call(this); } }, { key: 'disableEventListeners', value: function disableEventListeners$$1() { return disableEventListeners.call(this); } /** * Schedule an update, it will run on the next UI update available * @method scheduleUpdate * @memberof Popper */ /** * Collection of utilities useful when writing custom modifiers. * Starting from version 1.7, this method is available only if you * include `popper-utils.js` before `popper.js`. * * **DEPRECATION**: This way to access PopperUtils is deprecated * and will be removed in v2! Use the PopperUtils module directly instead. * Due to the high instability of the methods contained in Utils, we can't * guarantee them to follow semver. Use them at your own risk! * @static * @private * @type {Object} * @deprecated since version 1.8 * @member Utils * @memberof Popper */ }]); return Popper; }(); /** * The `referenceObject` is an object that provides an interface compatible with Popper.js * and lets you use it as replacement of a real DOM node.
* You can use this method to position a popper relatively to a set of coordinates * in case you don't have a DOM node to use as reference. * * ``` * new Popper(referenceObject, popperNode); * ``` * * NB: This feature isn't supported in Internet Explorer 10 * @name referenceObject * @property {Function} data.getBoundingClientRect * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method. * @property {number} data.clientWidth * An ES6 getter that will return the width of the virtual reference element. * @property {number} data.clientHeight * An ES6 getter that will return the height of the virtual reference element. */ Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils; Popper.placements = placements; Popper.Defaults = Defaults; /** * Triggers document reflow. * Use void because some minifiers or engines think simply accessing the property * is unnecessary. * @param {Element} popper */ function reflow(popper) { void popper.offsetHeight; } /** * Wrapper util for popper position updating. * Updates the popper's position and invokes the callback on update. * Hackish workaround until Popper 2.0's update() becomes sync. * @param {Popper} popperInstance * @param {Function} callback: to run once popper's position was updated * @param {Boolean} updateAlreadyCalled: was scheduleUpdate() already called? */ function updatePopperPosition(popperInstance, callback, updateAlreadyCalled) { var popper = popperInstance.popper, options = popperInstance.options; var onCreate = options.onCreate; var onUpdate = options.onUpdate; options.onCreate = options.onUpdate = function () { reflow(popper), callback && callback(), onUpdate(); options.onCreate = onCreate; options.onUpdate = onUpdate; }; if (!updateAlreadyCalled) { popperInstance.scheduleUpdate(); } } /** * Returns the core placement ('top', 'bottom', 'left', 'right') of a popper * @param {Element} popper * @return {String} */ function getPopperPlacement(popper) { return popper.getAttribute('x-placement').replace(/-.+/, ''); } /** * Determines if the mouse's cursor is outside the interactive border * @param {MouseEvent} event * @param {Element} popper * @param {Object} options * @return {Boolean} */ function cursorIsOutsideInteractiveBorder(event, popper, options) { if (!popper.getAttribute('x-placement')) return true; var x = event.clientX, y = event.clientY; var interactiveBorder = options.interactiveBorder, distance = options.distance; var rect = popper.getBoundingClientRect(); var placement = getPopperPlacement(popper); var borderWithDistance = interactiveBorder + distance; var exceeds = { top: rect.top - y > interactiveBorder, bottom: y - rect.bottom > interactiveBorder, left: rect.left - x > interactiveBorder, right: x - rect.right > interactiveBorder }; switch (placement) { case 'top': exceeds.top = rect.top - y > borderWithDistance; break; case 'bottom': exceeds.bottom = y - rect.bottom > borderWithDistance; break; case 'left': exceeds.left = rect.left - x > borderWithDistance; break; case 'right': exceeds.right = x - rect.right > borderWithDistance; break; } return exceeds.top || exceeds.bottom || exceeds.left || exceeds.right; } /** * Transforms the `arrowTransform` numbers based on the placement axis * @param {String} type 'scale' or 'translate' * @param {Number[]} numbers * @param {Boolean} isVertical * @param {Boolean} isReverse * @return {String} */ function transformNumbersBasedOnPlacementAxis(type, numbers, isVertical, isReverse) { if (!numbers.length) return ''; var transforms = { scale: function () { if (numbers.length === 1) { return '' + numbers[0]; } else { return isVertical ? numbers[0] + ', ' + numbers[1] : numbers[1] + ', ' + numbers[0]; } }(), translate: function () { if (numbers.length === 1) { return isReverse ? -numbers[0] + 'px' : numbers[0] + 'px'; } else { if (isVertical) { return isReverse ? numbers[0] + 'px, ' + -numbers[1] + 'px' : numbers[0] + 'px, ' + numbers[1] + 'px'; } else { return isReverse ? -numbers[1] + 'px, ' + numbers[0] + 'px' : numbers[1] + 'px, ' + numbers[0] + 'px'; } } }() }; return transforms[type]; } /** * Transforms the `arrowTransform` x or y axis based on the placement axis * @param {String} axis 'X', 'Y', '' * @param {Boolean} isVertical * @return {String} */ function transformAxis(axis, isVertical) { if (!axis) return ''; var map = { X: 'Y', Y: 'X' }; return isVertical ? axis : map[axis]; } /** * Computes and applies the necessary arrow transform * @param {Element} popper * @param {Element} arrow * @param {String} arrowTransform */ function computeArrowTransform(popper, arrow, arrowTransform) { var placement = getPopperPlacement(popper); var isVertical = placement === 'top' || placement === 'bottom'; var isReverse = placement === 'right' || placement === 'bottom'; var getAxis = function getAxis(re) { var match = arrowTransform.match(re); return match ? match[1] : ''; }; var getNumbers = function getNumbers(re) { var match = arrowTransform.match(re); return match ? match[1].split(',').map(parseFloat) : []; }; var re = { translate: /translateX?Y?\(([^)]+)\)/, scale: /scaleX?Y?\(([^)]+)\)/ }; var matches = { translate: { axis: getAxis(/translate([XY])/), numbers: getNumbers(re.translate) }, scale: { axis: getAxis(/scale([XY])/), numbers: getNumbers(re.scale) } }; var computedTransform = arrowTransform.replace(re.translate, 'translate' + transformAxis(matches.translate.axis, isVertical) + '(' + transformNumbersBasedOnPlacementAxis('translate', matches.translate.numbers, isVertical, isReverse) + ')').replace(re.scale, 'scale' + transformAxis(matches.scale.axis, isVertical) + '(' + transformNumbersBasedOnPlacementAxis('scale', matches.scale.numbers, isVertical, isReverse) + ')'); arrow.style[prefix('transform')] = computedTransform; } /** * Returns the distance taking into account the default distance due to * the transform: translate setting in CSS * @param {Number} distance * @return {String} */ function getOffsetDistanceInPx(distance) { return -(distance - defaults.distance) + 'px'; } /** * Waits until next repaint to execute a fn * @param {Function} fn */ function defer(fn) { requestAnimationFrame(function () { setTimeout(fn, 1); }); } var matches = {}; if (isBrowser) { var e = Element.prototype; matches = e.matches || e.matchesSelector || e.webkitMatchesSelector || e.mozMatchesSelector || e.msMatchesSelector || function (s) { var matches = (this.document || this.ownerDocument).querySelectorAll(s); var i = matches.length; while (--i >= 0 && matches.item(i) !== this) {} // eslint-disable-line no-empty return i > -1; }; } var matches$1 = matches; /** * Ponyfill to get the closest parent element * @param {Element} element - child of parent to be returned * @param {String} parentSelector - selector to match the parent if found * @return {Element} */ function closest(element, parentSelector) { var fn = Element.prototype.closest || function (selector) { var el = this; while (el) { if (matches$1.call(el, selector)) { return el; } el = el.parentElement; } }; return fn.call(element, parentSelector); } /** * Returns the value taking into account the value being either a number or array * @param {Number|Array} value * @param {Number} index * @return {Number} */ function getValue(value, index) { return Array.isArray(value) ? value[index] : value; } /** * Sets the visibility state of an element for transition to begin * @param {Element[]} els - array of elements * @param {String} type - 'visible' or 'hidden' */ function setVisibilityState(els, type) { els.forEach(function (el) { if (!el) return; el.setAttribute('data-state', type); }); } /** * Sets the transition property to each element * @param {Element[]} els - Array of elements * @param {String} value */ function applyTransitionDuration(els, value) { els.filter(Boolean).forEach(function (el) { el.style[prefix('transitionDuration')] = value + 'ms'; }); } /** * Focuses an element while preventing a scroll jump if it's not entirely within the viewport * @param {Element} el */ function focus(el) { var x = window.scrollX || window.pageXOffset; var y = window.scrollY || window.pageYOffset; el.focus(); scroll(x, y); } var key = {}; var store = function store(data) { return function (k) { return k === key && data; }; }; var Tippy = function () { function Tippy(config) { classCallCheck(this, Tippy); for (var _key in config) { this[_key] = config[_key]; } this.state = { destroyed: false, visible: false, enabled: true }; this._ = store({ mutationObservers: [] }); } /** * Enables the tooltip to allow it to show or hide * @memberof Tippy * @public */ createClass(Tippy, [{ key: 'enable', value: function enable() { this.state.enabled = true; } /** * Disables the tooltip from showing or hiding, but does not destroy it * @memberof Tippy * @public */ }, { key: 'disable', value: function disable() { this.state.enabled = false; } /** * Shows the tooltip * @param {Number} duration in milliseconds * @memberof Tippy * @public */ }, { key: 'show', value: function show(duration) { var _this = this; if (this.state.destroyed || !this.state.enabled) return; var popper = this.popper, reference = this.reference, options = this.options; var _getInnerElements = getInnerElements(popper), tooltip = _getInnerElements.tooltip, backdrop = _getInnerElements.backdrop, content = _getInnerElements.content; // If the `dynamicTitle` option is true, the instance is allowed // to be created with an empty title. Make sure that the tooltip // content is not empty before showing it if (options.dynamicTitle && !reference.getAttribute('data-original-title')) { return; } // Do not show tooltip if reference contains 'disabled' attribute. FF fix for #221 if (reference.hasAttribute('disabled')) return; // Destroy tooltip if the reference element is no longer on the DOM if (!reference.refObj && !document.documentElement.contains(reference)) { this.destroy(); return; } options.onShow.call(popper, this); duration = getValue(duration !== undefined ? duration : options.duration, 0); // Prevent a transition when popper changes position applyTransitionDuration([popper, tooltip, backdrop], 0); popper.style.visibility = 'visible'; this.state.visible = true; _mount.call(this, function () { if (!_this.state.visible) return; if (!_hasFollowCursorBehavior.call(_this)) { // FIX: Arrow will sometimes not be positioned correctly. Force another update. _this.popperInstance.scheduleUpdate(); } // Set initial position near the cursor if (_hasFollowCursorBehavior.call(_this)) { _this.popperInstance.disableEventListeners(); var delay = getValue(options.delay, 0); var lastTriggerEvent = _this._(key).lastTriggerEvent; if (lastTriggerEvent) { _this._(key).followCursorListener(delay && _this._(key).lastMouseMoveEvent ? _this._(key).lastMouseMoveEvent : lastTriggerEvent); } } // Re-apply transition durations applyTransitionDuration([tooltip, backdrop, backdrop ? content : null], duration); if (backdrop) { getComputedStyle(backdrop)[prefix('transform')]; } if (options.interactive) { reference.classList.add('tippy-active'); } if (options.sticky) { _makeSticky.call(_this); } setVisibilityState([tooltip, backdrop], 'visible'); _onTransitionEnd.call(_this, duration, function () { if (!options.updateDuration) { tooltip.classList.add('tippy-notransition'); } if (options.interactive) { focus(popper); } reference.setAttribute('aria-describedby', 'tippy-' + _this.id); options.onShown.call(popper, _this); }); }); } /** * Hides the tooltip * @param {Number} duration in milliseconds * @memberof Tippy * @public */ }, { key: 'hide', value: function hide(duration) { var _this2 = this; if (this.state.destroyed || !this.state.enabled) return; var popper = this.popper, reference = this.reference, options = this.options; var _getInnerElements2 = getInnerElements(popper), tooltip = _getInnerElements2.tooltip, backdrop = _getInnerElements2.backdrop, content = _getInnerElements2.content; options.onHide.call(popper, this); duration = getValue(duration !== undefined ? duration : options.duration, 1); if (!options.updateDuration) { tooltip.classList.remove('tippy-notransition'); } if (options.interactive) { reference.classList.remove('tippy-active'); } popper.style.visibility = 'hidden'; this.state.visible = false; applyTransitionDuration([tooltip, backdrop, backdrop ? content : null], duration); setVisibilityState([tooltip, backdrop], 'hidden'); if (options.interactive && options.trigger.indexOf('click') > -1) { focus(reference); } /* * This call is deferred because sometimes when the tooltip is still transitioning in but hide() * is called before it finishes, the CSS transition won't reverse quickly enough, meaning * the CSS transition will finish 1-2 frames later, and onHidden() will run since the JS set it * more quickly. It should actually be onShown(). Seems to be something Chrome does, not Safari */ defer(function () { _onTransitionEnd.call(_this2, duration, function () { if (_this2.state.visible || !options.appendTo.contains(popper)) return; if (!_this2._(key).isPreparingToShow) { document.removeEventListener('mousemove', _this2._(key).followCursorListener); _this2._(key).lastMouseMoveEvent = null; } if (_this2.popperInstance) { _this2.popperInstance.disableEventListeners(); } reference.removeAttribute('aria-describedby'); options.appendTo.removeChild(popper); options.onHidden.call(popper, _this2); }); }); } /** * Destroys the tooltip instance * @param {Boolean} destroyTargetInstances - relevant only when destroying delegates * @memberof Tippy * @public */ }, { key: 'destroy', value: function destroy() { var _this3 = this; var destroyTargetInstances = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; if (this.state.destroyed) return; // Ensure the popper is hidden if (this.state.visible) { this.hide(0); } this.listeners.forEach(function (listener) { _this3.reference.removeEventListener(listener.event, listener.handler); }); // Restore title if (this.title) { this.reference.setAttribute('title', this.title); } delete this.reference._tippy; var attributes = ['data-original-title', 'data-tippy', 'data-tippy-delegate']; attributes.forEach(function (attr) { _this3.reference.removeAttribute(attr); }); if (this.options.target && destroyTargetInstances) { toArray(this.reference.querySelectorAll(this.options.target)).forEach(function (child) { return child._tippy && child._tippy.destroy(); }); } if (this.popperInstance) { this.popperInstance.destroy(); } this._(key).mutationObservers.forEach(function (observer) { observer.disconnect(); }); this.state.destroyed = true; } }]); return Tippy; }(); /** * ------------------------------------------------------------------------ * Private methods * ------------------------------------------------------------------------ * Standalone functions to be called with the instance's `this` context to make * them truly private and not accessible on the prototype */ /** * Determines if the tooltip instance has followCursor behavior * @return {Boolean} * @memberof Tippy * @private */ function _hasFollowCursorBehavior() { var lastTriggerEvent = this._(key).lastTriggerEvent; return this.options.followCursor && !browser.usingTouch && lastTriggerEvent && lastTriggerEvent.type !== 'focus'; } /** * Creates the Tippy instance for the child target of the delegate container * @param {Event} event * @memberof Tippy * @private */ function _createDelegateChildTippy(event) { var targetEl = closest(event.target, this.options.target); if (targetEl && !targetEl._tippy) { var title = targetEl.getAttribute('title') || this.title; if (title) { targetEl.setAttribute('title', title); tippy(targetEl, _extends({}, this.options, { target: null })); _enter.call(targetEl._tippy, event); } } } /** * Method used by event listeners to invoke the show method, taking into account delays and * the `wait` option * @param {Event} event * @memberof Tippy * @private */ function _enter(event) { var _this4 = this; var options = this.options; _clearDelayTimeouts.call(this); if (this.state.visible) return; // Is a delegate, create Tippy instance for the child target if (options.target) { _createDelegateChildTippy.call(this, event); return; } this._(key).isPreparingToShow = true; if (options.wait) { options.wait.call(this.popper, this.show.bind(this), event); return; } // If the tooltip has a delay, we need to be listening to the mousemove as soon as the trigger // event is fired so that it's in the correct position upon mount. if (_hasFollowCursorBehavior.call(this)) { if (!this._(key).followCursorListener) { _setFollowCursorListener.call(this); } var _getInnerElements3 = getInnerElements(this.popper), arrow = _getInnerElements3.arrow; if (arrow) arrow.style.margin = '0'; document.addEventListener('mousemove', this._(key).followCursorListener); } var delay = getValue(options.delay, 0); if (delay) { this._(key).showTimeout = setTimeout(function () { _this4.show(); }, delay); } else { this.show(); } } /** * Method used by event listeners to invoke the hide method, taking into account delays * @memberof Tippy * @private */ function _leave() { var _this5 = this; _clearDelayTimeouts.call(this); if (!this.state.visible) return; this._(key).isPreparingToShow = false; var delay = getValue(this.options.delay, 1); if (delay) { this._(key).hideTimeout = setTimeout(function () { if (_this5.state.visible) { _this5.hide(); } }, delay); } else { this.hide(); } } /** * Returns relevant listeners for the instance * @return {Object} of listeners * @memberof Tippy * @private */ function _getEventListeners() { var _this6 = this; var onTrigger = function onTrigger(event) { if (!_this6.state.enabled) return; var shouldStopEvent = browser.supportsTouch && browser.usingTouch && ['mouseenter', 'mouseover', 'focus'].indexOf(event.type) > -1; if (shouldStopEvent && _this6.options.touchHold) return; _this6._(key).lastTriggerEvent = event; // Toggle show/hide when clicking click-triggered tooltips if (event.type === 'click' && _this6.options.hideOnClick !== 'persistent' && _this6.state.visible) { _leave.call(_this6); } else { _enter.call(_this6, event); } }; var onMouseLeave = function onMouseLeave(event) { if (['mouseleave', 'mouseout'].indexOf(event.type) > -1 && browser.supportsTouch && browser.usingTouch && _this6.options.touchHold) return; if (_this6.options.interactive) { var hide = _leave.bind(_this6); var onMouseMove = function onMouseMove(event) { var referenceCursorIsOver = closest(event.target, selectors.REFERENCE); var cursorIsOverPopper = closest(event.target, selectors.POPPER) === _this6.popper; var cursorIsOverReference = referenceCursorIsOver === _this6.reference; if (cursorIsOverPopper || cursorIsOverReference) return; if (cursorIsOutsideInteractiveBorder(event, _this6.popper, _this6.options)) { document.body.removeEventListener('mouseleave', hide); document.removeEventListener('mousemove', onMouseMove); _leave.call(_this6, onMouseMove); } }; document.body.addEventListener('mouseleave', hide); document.addEventListener('mousemove', onMouseMove); return; } _leave.call(_this6); }; var onBlur = function onBlur(event) { if (event.target !== _this6.reference || browser.usingTouch) return; if (_this6.options.interactive) { if (!event.relatedTarget) return; if (closest(event.relatedTarget, selectors.POPPER)) return; } _leave.call(_this6); }; var onDelegateShow = function onDelegateShow(event) { if (closest(event.target, _this6.options.target)) { _enter.call(_this6, event); } }; var onDelegateHide = function onDelegateHide(event) { if (closest(event.target, _this6.options.target)) { _leave.call(_this6); } }; return { onTrigger: onTrigger, onMouseLeave: onMouseLeave, onBlur: onBlur, onDelegateShow: onDelegateShow, onDelegateHide: onDelegateHide }; } /** * Creates and returns a new popper instance * @return {Popper} * @memberof Tippy * @private */ function _createPopperInstance() { var _this7 = this; var popper = this.popper, reference = this.reference, options = this.options; var _getInnerElements4 = getInnerElements(popper), tooltip = _getInnerElements4.tooltip; var popperOptions = options.popperOptions; var arrowSelector = options.arrowType === 'round' ? selectors.ROUND_ARROW : selectors.ARROW; var arrow = tooltip.querySelector(arrowSelector); var config = _extends({ placement: options.placement }, popperOptions || {}, { modifiers: _extends({}, popperOptions ? popperOptions.modifiers : {}, { arrow: _extends({ element: arrowSelector }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.arrow : {}), flip: _extends({ enabled: options.flip, padding: options.distance + 5 /* 5px from viewport boundary */ , behavior: options.flipBehavior }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.flip : {}), offset: _extends({ offset: options.offset }, popperOptions && popperOptions.modifiers ? popperOptions.modifiers.offset : {}) }), onCreate: function onCreate() { tooltip.style[getPopperPlacement(popper)] = getOffsetDistanceInPx(options.distance); if (arrow && options.arrowTransform) { computeArrowTransform(popper, arrow, options.arrowTransform); } }, onUpdate: function onUpdate() { var styles = tooltip.style; styles.top = ''; styles.bottom = ''; styles.left = ''; styles.right = ''; styles[getPopperPlacement(popper)] = getOffsetDistanceInPx(options.distance); if (arrow && options.arrowTransform) { computeArrowTransform(popper, arrow, options.arrowTransform); } } }); _addMutationObserver.call(this, { target: popper, callback: function callback() { _this7.popperInstance.update(); }, options: { childList: true, subtree: true, characterData: true } }); return new Popper(reference, popper, config); } /** * Appends the popper element to the DOM, updating or creating the popper instance * @param {Function} callback * @memberof Tippy * @private */ function _mount(callback) { var options = this.options; if (!this.popperInstance) { this.popperInstance = _createPopperInstance.call(this); if (!options.livePlacement) { this.popperInstance.disableEventListeners(); } } else { this.popperInstance.scheduleUpdate(); if (options.livePlacement && !_hasFollowCursorBehavior.call(this)) { this.popperInstance.enableEventListeners(); } } // If the instance previously had followCursor behavior, it will be positioned incorrectly // if triggered by `focus` afterwards - update the reference back to the real DOM element if (!_hasFollowCursorBehavior.call(this)) { var _getInnerElements5 = getInnerElements(this.popper), arrow = _getInnerElements5.arrow; if (arrow) arrow.style.margin = ''; this.popperInstance.reference = this.reference; } updatePopperPosition(this.popperInstance, callback, true); if (!options.appendTo.contains(this.popper)) { options.appendTo.appendChild(this.popper); } } /** * Clears the show and hide delay timeouts * @memberof Tippy * @private */ function _clearDelayTimeouts() { var _ref = this._(key), showTimeout = _ref.showTimeout, hideTimeout = _ref.hideTimeout; clearTimeout(showTimeout); clearTimeout(hideTimeout); } /** * Sets the mousemove event listener function for `followCursor` option * @memberof Tippy * @private */ function _setFollowCursorListener() { var _this8 = this; this._(key).followCursorListener = function (event) { var _$lastMouseMoveEvent = _this8._(key).lastMouseMoveEvent = event, clientX = _$lastMouseMoveEvent.clientX, clientY = _$lastMouseMoveEvent.clientY; if (!_this8.popperInstance) return; _this8.popperInstance.reference = { getBoundingClientRect: function getBoundingClientRect() { return { width: 0, height: 0, top: clientY, left: clientX, right: clientX, bottom: clientY }; }, clientWidth: 0, clientHeight: 0 }; _this8.popperInstance.scheduleUpdate(); }; } /** * Updates the popper's position on each animation frame * @memberof Tippy * @private */ function _makeSticky() { var _this9 = this; var applyTransitionDuration$$1 = function applyTransitionDuration$$1() { _this9.popper.style[prefix('transitionDuration')] = _this9.options.updateDuration + 'ms'; }; var removeTransitionDuration = function removeTransitionDuration() { _this9.popper.style[prefix('transitionDuration')] = ''; }; var updatePosition = function updatePosition() { if (_this9.popperInstance) { _this9.popperInstance.update(); } applyTransitionDuration$$1(); if (_this9.state.visible) { requestAnimationFrame(updatePosition); } else { removeTransitionDuration(); } }; updatePosition(); } /** * Adds a mutation observer to an element and stores it in the instance * @param {Object} * @memberof Tippy * @private */ function _addMutationObserver(_ref2) { var target = _ref2.target, callback = _ref2.callback, options = _ref2.options; if (!window.MutationObserver) return; var observer = new MutationObserver(callback); observer.observe(target, options); this._(key).mutationObservers.push(observer); } /** * Fires the callback functions once the CSS transition ends for `show` and `hide` methods * @param {Number} duration * @param {Function} callback - callback function to fire once transition completes * @memberof Tippy * @private */ function _onTransitionEnd(duration, callback) { // Make callback synchronous if duration is 0 if (!duration) { return callback(); } var _getInnerElements6 = getInnerElements(this.popper), tooltip = _getInnerElements6.tooltip; var toggleListeners = function toggleListeners(action, listener) { if (!listener) return; tooltip[action + 'EventListener']('transition' in document.body.style ? 'transitionend' : 'webkitTransitionEnd', listener); }; var listener = function listener(e) { if (e.target === tooltip) { toggleListeners('remove', listener); callback(); } }; toggleListeners('remove', this._(key).transitionendListener); toggleListeners('add', listener); this._(key).transitionendListener = listener; } var idCounter = 1; /** * Creates tooltips for each reference element * @param {Element[]} els * @param {Object} config * @return {Tippy[]} Array of Tippy instances */ function createTooltips(els, config) { return els.reduce(function (acc, reference) { var id = idCounter; var options = evaluateOptions(reference, config.performance ? config : getIndividualOptions(reference, config)); var title = reference.getAttribute('title'); // Don't create an instance when: // * the `title` attribute is falsy (null or empty string), and // * it's not a delegate for tooltips, and // * there is no html template specified, and // * `dynamicTitle` option is false if (!title && !options.target && !options.html && !options.dynamicTitle) { return acc; } // Delegates should be highlighted as different reference.setAttribute(options.target ? 'data-tippy-delegate' : 'data-tippy', ''); removeTitle(reference); var popper = createPopperElement(id, title, options); var tippy = new Tippy({ id: id, reference: reference, popper: popper, options: options, title: title, popperInstance: null }); if (options.createPopperInstanceOnInit) { tippy.popperInstance = _createPopperInstance.call(tippy); tippy.popperInstance.disableEventListeners(); } var listeners = _getEventListeners.call(tippy); tippy.listeners = options.trigger.trim().split(' ').reduce(function (acc, eventType) { return acc.concat(createTrigger(eventType, reference, listeners, options)); }, []); // Update tooltip content whenever the title attribute on the reference changes if (options.dynamicTitle) { _addMutationObserver.call(tippy, { target: reference, callback: function callback() { var _getInnerElements = getInnerElements(popper), content = _getInnerElements.content; var title = reference.getAttribute('title'); if (title) { content[options.allowTitleHTML ? 'innerHTML' : 'textContent'] = tippy.title = title; removeTitle(reference); } }, options: { attributes: true } }); } // Shortcuts reference._tippy = tippy; popper._tippy = tippy; popper._reference = reference; acc.push(tippy); idCounter++; return acc; }, []); } /** * Hides all poppers * @param {Tippy} excludeTippy - tippy to exclude if needed */ function hideAllPoppers(excludeTippy) { var poppers = toArray(document.querySelectorAll(selectors.POPPER)); poppers.forEach(function (popper) { var tippy = popper._tippy; if (!tippy) return; var options = tippy.options; if ((options.hideOnClick === true || options.trigger.indexOf('focus') > -1) && (!excludeTippy || popper !== excludeTippy.popper)) { tippy.hide(); } }); } /** * Adds the needed event listeners */ function bindEventListeners() { var onDocumentTouch = function onDocumentTouch() { if (browser.usingTouch) return; browser.usingTouch = true; if (browser.iOS) { document.body.classList.add('tippy-touch'); } if (browser.dynamicInputDetection && window.performance) { document.addEventListener('mousemove', onDocumentMouseMove); } browser.onUserInputChange('touch'); }; var onDocumentMouseMove = function () { var time = void 0; return function () { var now = performance.now(); // Chrome 60+ is 1 mousemove per animation frame, use 20ms time difference if (now - time < 20) { browser.usingTouch = false; document.removeEventListener('mousemove', onDocumentMouseMove); if (!browser.iOS) { document.body.classList.remove('tippy-touch'); } browser.onUserInputChange('mouse'); } time = now; }; }(); var onDocumentClick = function onDocumentClick(event) { // Simulated events dispatched on the document if (!(event.target instanceof Element)) { return hideAllPoppers(); } var reference = closest(event.target, selectors.REFERENCE); var popper = closest(event.target, selectors.POPPER); if (popper && popper._tippy && popper._tippy.options.interactive) { return; } if (reference && reference._tippy) { var options = reference._tippy.options; var isClickTrigger = options.trigger.indexOf('click') > -1; var isMultiple = options.multiple; // Hide all poppers except the one belonging to the element that was clicked if (!isMultiple && browser.usingTouch || !isMultiple && isClickTrigger) { return hideAllPoppers(reference._tippy); } if (options.hideOnClick !== true || isClickTrigger) { return; } } hideAllPoppers(); }; var onWindowBlur = function onWindowBlur() { var _document = document, el = _document.activeElement; if (el && el.blur && matches$1.call(el, selectors.REFERENCE)) { el.blur(); } }; var onWindowResize = function onWindowResize() { toArray(document.querySelectorAll(selectors.POPPER)).forEach(function (popper) { var tippyInstance = popper._tippy; if (tippyInstance && !tippyInstance.options.livePlacement) { tippyInstance.popperInstance.scheduleUpdate(); } }); }; document.addEventListener('click', onDocumentClick); document.addEventListener('touchstart', onDocumentTouch); window.addEventListener('blur', onWindowBlur); window.addEventListener('resize', onWindowResize); if (!browser.supportsTouch && (navigator.maxTouchPoints || navigator.msMaxTouchPoints)) { document.addEventListener('pointerdown', onDocumentTouch); } } var eventListenersBound = false; /** * Exported module * @param {String|Element|Element[]|NodeList|Object} selector * @param {Object} options * @param {Boolean} one - create one tooltip * @return {Object} */ function tippy(selector, options, one) { if (browser.supported && !eventListenersBound) { bindEventListeners(); eventListenersBound = true; } if (isObjectLiteral(selector)) { polyfillVirtualReferenceProps(selector); } options = _extends({}, defaults, options); var references = getArrayOfElements(selector); var firstReference = references[0]; return { selector: selector, options: options, tooltips: browser.supported ? createTooltips(one && firstReference ? [firstReference] : references, options) : [], destroyAll: function destroyAll() { this.tooltips.forEach(function (tooltip) { return tooltip.destroy(); }); this.tooltips = []; } }; } tippy.version = version; tippy.browser = browser; tippy.defaults = defaults; tippy.one = function (selector, options) { return tippy(selector, options, true).tooltips[0]; }; tippy.disableAnimations = function () { defaults.updateDuration = defaults.duration = 0; defaults.animateFill = false; }; /** * Injects CSS styles to document head * @param {String} css */ function injectCSS() { var css = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; if (isBrowser && browser.supported) { var head = document.head || document.querySelector('head'); var style = document.createElement('style'); style.type = 'text/css'; head.insertBefore(style, head.firstChild); if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } } injectCSS(styles); return tippy; }))); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}]},{},[1]);