{"version":3,"mappings":"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","names":["module","j","define","window","global","self","this","introJs","nextLabel","prevLabel","skipLabel","doneLabel","hidePrev","hideNext","tooltipPosition","tooltipClass","highlightClass","exitOnEsc","exitOnOverlayClick","showStepNumbers","keyboardNavigation","showButtons","showBullets","showProgress","scrollToElement","scrollTo","scrollPadding","overlayOpacity","positionPrecedence","disableInteraction","helperElementPadding","hintPosition","hintButtonLabel","hintAnimation","buttonClass","i","u","f","h","className","document","bind","o","n","r","element","intro","step","position","a","s","c","sort","xt","w","A","t","H","k","e","z","nt","_","B","l","st","P","replace","d","M","m","O","v","y","indexOf","gt","J","dt","ot","E","K","g","Z","W","D","T","Y","U","S","tt","Pt","I","x","R","onclick","Q","wt","yt","Ct","F","width","hint","At","ft","$","N","X","at","lt","ct","ut","top","height","left","parseInt","q","clone","setOption","setOptions","Nt","start","goToStep","addStep","addSteps","goToStepNumber","nextStep","previousStep","exit","refresh","onbeforechange","onchange","onafterchange","oncomplete","onhintsadded","onhintclick","onhintclose","onexit","onskip","onbeforeexit","addHints","hideHint","hideHints","showHint","showHints","removeHints","removeHint","showHintDialog"],"sources":["node_modules\\intro.js\\intro.js"],"sourcesContent":["/**\n * Intro.js v2.9.3\n * https://github.com/usablica/intro.js\n *\n * Copyright (C) 2017 Afshin Mehrabani (@afshinmeh)\n */\n\n(function(f) {\n if (typeof exports === \"object\" && typeof module !== \"undefined\") {\n module.exports = f();\n // deprecated function\n // @since 2.8.0\n module.exports.introJs = function () {\n console.warn('Deprecated: please use require(\"intro.js\") directly, instead of the introJs method of the function');\n // introJs()\n return f().apply(this, arguments);\n };\n } else if (typeof define === \"function\" && define.amd) {\n define([], f);\n } else {\n var g;\n if (typeof window !== \"undefined\") {\n g = window;\n } else if (typeof global !== \"undefined\") {\n g = global;\n } else if (typeof self !== \"undefined\") {\n g = self;\n } else {\n g = this;\n }\n g.introJs = f();\n }\n})(function () {\n //Default config/variables\n var VERSION = '2.9.3';\n\n /**\n * IntroJs main class\n *\n * @class IntroJs\n */\n function IntroJs(obj) {\n this._targetElement = obj;\n this._introItems = [];\n\n this._options = {\n /* Next button label in tooltip box */\n nextLabel: 'Next →',\n /* Previous button label in tooltip box */\n prevLabel: '← Back',\n /* Skip button label in tooltip box */\n skipLabel: 'Skip',\n /* Done button label in tooltip box */\n doneLabel: 'Done',\n /* Hide previous button in the first step? Otherwise, it will be disabled button. */\n hidePrev: false,\n /* Hide next button in the last step? Otherwise, it will be disabled button. */\n hideNext: false,\n /* Default tooltip box position */\n tooltipPosition: 'bottom',\n /* Next CSS class for tooltip boxes */\n tooltipClass: '',\n /* CSS class that is added to the helperLayer */\n highlightClass: '',\n /* Close introduction when pressing Escape button? */\n exitOnEsc: true,\n /* Close introduction when clicking on overlay layer? */\n exitOnOverlayClick: true,\n /* Show step numbers in introduction? */\n showStepNumbers: true,\n /* Let user use keyboard to navigate the tour? */\n keyboardNavigation: true,\n /* Show tour control buttons? */\n showButtons: true,\n /* Show tour bullets? */\n showBullets: true,\n /* Show tour progress? */\n showProgress: false,\n /* Scroll to highlighted element? */\n scrollToElement: true,\n /*\n * Should we scroll the tooltip or target element?\n *\n * Options are: 'element' or 'tooltip'\n */\n scrollTo: 'element',\n /* Padding to add after scrolling when element is not in the viewport (in pixels) */\n scrollPadding: 30,\n /* Set the overlay opacity */\n overlayOpacity: 0.8,\n /* Precedence of positions, when auto is enabled */\n positionPrecedence: [\"bottom\", \"top\", \"right\", \"left\"],\n /* Disable an interaction with element? */\n disableInteraction: false,\n /* Set how much padding to be used around helper element */\n helperElementPadding: 10,\n /* Default hint position */\n hintPosition: 'top-middle',\n /* Hint button label */\n hintButtonLabel: 'Got it',\n /* Adding animation to hints? */\n hintAnimation: true,\n /* additional classes to put on the buttons */\n buttonClass: \"introjs-button\"\n };\n }\n\n /**\n * Initiate a new introduction/guide from an element in the page\n *\n * @api private\n * @method _introForElement\n * @param {Object} targetElm\n * @param {String} group\n * @returns {Boolean} Success or not?\n */\n function _introForElement(targetElm, group) {\n var allIntroSteps = targetElm.querySelectorAll(\"*[data-intro]\"),\n introItems = [];\n\n if (this._options.steps) {\n //use steps passed programmatically\n _forEach(this._options.steps, function (step) {\n var currentItem = _cloneObject(step);\n\n //set the step\n currentItem.step = introItems.length + 1;\n\n //use querySelector function only when developer used CSS selector\n if (typeof (currentItem.element) === 'string') {\n //grab the element with given selector from the page\n currentItem.element = document.querySelector(currentItem.element);\n }\n\n //intro without element\n if (typeof (currentItem.element) === 'undefined' || currentItem.element === null) {\n var floatingElementQuery = document.querySelector(\".introjsFloatingElement\");\n\n if (floatingElementQuery === null) {\n floatingElementQuery = document.createElement('div');\n floatingElementQuery.className = 'introjsFloatingElement';\n\n document.body.appendChild(floatingElementQuery);\n }\n\n currentItem.element = floatingElementQuery;\n currentItem.position = 'floating';\n }\n\n currentItem.scrollTo = currentItem.scrollTo || this._options.scrollTo;\n\n if (typeof (currentItem.disableInteraction) === 'undefined') {\n currentItem.disableInteraction = this._options.disableInteraction;\n }\n\n if (currentItem.element !== null) {\n introItems.push(currentItem);\n } \n }.bind(this));\n\n } else {\n //use steps from data-* annotations\n var elmsLength = allIntroSteps.length;\n var disableInteraction;\n \n //if there's no element to intro\n if (elmsLength < 1) {\n return false;\n }\n\n _forEach(allIntroSteps, function (currentElement) {\n \n // PR #80\n // start intro for groups of elements\n if (group && (currentElement.getAttribute(\"data-intro-group\") !== group)) {\n return;\n }\n\n // skip hidden elements\n if (currentElement.style.display === 'none') {\n return;\n }\n\n var step = parseInt(currentElement.getAttribute('data-step'), 10);\n\n if (typeof (currentElement.getAttribute('data-disable-interaction')) !== 'undefined') {\n disableInteraction = !!currentElement.getAttribute('data-disable-interaction');\n } else {\n disableInteraction = this._options.disableInteraction;\n }\n\n if (step > 0) {\n introItems[step - 1] = {\n element: currentElement,\n intro: currentElement.getAttribute('data-intro'),\n step: parseInt(currentElement.getAttribute('data-step'), 10),\n tooltipClass: currentElement.getAttribute('data-tooltipclass'),\n highlightClass: currentElement.getAttribute('data-highlightclass'),\n position: currentElement.getAttribute('data-position') || this._options.tooltipPosition,\n scrollTo: currentElement.getAttribute('data-scrollto') || this._options.scrollTo,\n disableInteraction: disableInteraction\n };\n }\n }.bind(this));\n\n //next add intro items without data-step\n //todo: we need a cleanup here, two loops are redundant\n var nextStep = 0;\n\n _forEach(allIntroSteps, function (currentElement) {\n \n // PR #80\n // start intro for groups of elements\n if (group && (currentElement.getAttribute(\"data-intro-group\") !== group)) {\n return;\n }\n \n if (currentElement.getAttribute('data-step') === null) {\n\n while (true) {\n if (typeof introItems[nextStep] === 'undefined') {\n break;\n } else {\n nextStep++;\n }\n } \n\n if (typeof (currentElement.getAttribute('data-disable-interaction')) !== 'undefined') {\n disableInteraction = !!currentElement.getAttribute('data-disable-interaction');\n } else {\n disableInteraction = this._options.disableInteraction;\n }\n\n introItems[nextStep] = {\n element: currentElement,\n intro: currentElement.getAttribute('data-intro'),\n step: nextStep + 1,\n tooltipClass: currentElement.getAttribute('data-tooltipclass'),\n highlightClass: currentElement.getAttribute('data-highlightclass'),\n position: currentElement.getAttribute('data-position') || this._options.tooltipPosition,\n scrollTo: currentElement.getAttribute('data-scrollto') || this._options.scrollTo,\n disableInteraction: disableInteraction\n };\n }\n }.bind(this));\n }\n\n //removing undefined/null elements\n var tempIntroItems = [];\n for (var z = 0; z < introItems.length; z++) {\n if (introItems[z]) {\n // copy non-falsy values to the end of the array\n tempIntroItems.push(introItems[z]); \n } \n }\n\n introItems = tempIntroItems;\n\n //Ok, sort all items with given steps\n introItems.sort(function (a, b) {\n return a.step - b.step;\n });\n\n //set it to the introJs object\n this._introItems = introItems;\n\n //add overlay layer to the page\n if(_addOverlayLayer.call(this, targetElm)) {\n //then, start the show\n _nextStep.call(this);\n\n if (this._options.keyboardNavigation) {\n DOMEvent.on(window, 'keydown', _onKeyDown, this, true);\n }\n //for window resize\n DOMEvent.on(window, 'resize', _onResize, this, true);\n }\n return false;\n }\n\n function _onResize () {\n this.refresh.call(this);\n }\n\n /**\n * on keyCode:\n * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode\n * This feature has been removed from the Web standards.\n * Though some browsers may still support it, it is in\n * the process of being dropped.\n * Instead, you should use KeyboardEvent.code,\n * if it's implemented.\n *\n * jQuery's approach is to test for\n * (1) e.which, then\n * (2) e.charCode, then\n * (3) e.keyCode\n * https://github.com/jquery/jquery/blob/a6b0705294d336ae2f63f7276de0da1195495363/src/event.js#L638\n *\n * @param type var\n * @return type\n */\n function _onKeyDown (e) {\n var code = (e.code === null) ? e.which : e.code;\n\n // if code/e.which is null\n if (code === null) {\n code = (e.charCode === null) ? e.keyCode : e.charCode;\n }\n \n if ((code === 'Escape' || code === 27) && this._options.exitOnEsc === true) {\n //escape key pressed, exit the intro\n //check if exit callback is defined\n _exitIntro.call(this, this._targetElement);\n } else if (code === 'ArrowLeft' || code === 37) {\n //left arrow\n _previousStep.call(this);\n } else if (code === 'ArrowRight' || code === 39) {\n //right arrow\n _nextStep.call(this);\n } else if (code === 'Enter' || code === 13) {\n //srcElement === ie\n var target = e.target || e.srcElement;\n if (target && target.className.match('introjs-prevbutton')) {\n //user hit enter while focusing on previous button\n _previousStep.call(this);\n } else if (target && target.className.match('introjs-skipbutton')) {\n //user hit enter while focusing on skip button\n if (this._introItems.length - 1 === this._currentStep && typeof (this._introCompleteCallback) === 'function') {\n this._introCompleteCallback.call(this);\n }\n\n _exitIntro.call(this, this._targetElement);\n } else if (target && target.getAttribute('data-stepnumber')) {\n // user hit enter while focusing on step bullet\n target.click();\n } else {\n //default behavior for responding to enter\n _nextStep.call(this);\n }\n\n //prevent default behaviour on hitting Enter, to prevent steps being skipped in some browsers\n if(e.preventDefault) {\n e.preventDefault();\n } else {\n e.returnValue = false;\n }\n }\n }\n\n /*\n * makes a copy of the object\n * @api private\n * @method _cloneObject\n */\n function _cloneObject(object) {\n if (object === null || typeof (object) !== 'object' || typeof (object.nodeType) !== 'undefined') {\n return object;\n }\n var temp = {};\n for (var key in object) {\n if (typeof(window.jQuery) !== 'undefined' && object[key] instanceof window.jQuery) {\n temp[key] = object[key];\n } else {\n temp[key] = _cloneObject(object[key]);\n }\n }\n return temp;\n }\n /**\n * Go to specific step of introduction\n *\n * @api private\n * @method _goToStep\n */\n function _goToStep(step) {\n //because steps starts with zero\n this._currentStep = step - 2;\n if (typeof (this._introItems) !== 'undefined') {\n _nextStep.call(this);\n }\n }\n\n /**\n * Go to the specific step of introduction with the explicit [data-step] number\n *\n * @api private\n * @method _goToStepNumber\n */\n function _goToStepNumber(step) {\n this._currentStepNumber = step;\n if (typeof (this._introItems) !== 'undefined') {\n _nextStep.call(this);\n }\n }\n\n /**\n * Go to next step on intro\n *\n * @api private\n * @method _nextStep\n */\n function _nextStep() {\n this._direction = 'forward';\n\n if (typeof (this._currentStepNumber) !== 'undefined') {\n _forEach(this._introItems, function (item, i) {\n if( item.step === this._currentStepNumber ) {\n this._currentStep = i - 1;\n this._currentStepNumber = undefined;\n }\n }.bind(this));\n }\n\n if (typeof (this._currentStep) === 'undefined') {\n this._currentStep = 0;\n } else {\n ++this._currentStep;\n }\n\n var nextStep = this._introItems[this._currentStep];\n var continueStep = true;\n\n if (typeof (this._introBeforeChangeCallback) !== 'undefined') {\n continueStep = this._introBeforeChangeCallback.call(this, nextStep.element);\n }\n\n // if `onbeforechange` returned `false`, stop displaying the element\n if (continueStep === false) {\n --this._currentStep;\n return false;\n }\n\n if ((this._introItems.length) <= this._currentStep) {\n //end of the intro\n //check if any callback is defined\n if (typeof (this._introCompleteCallback) === 'function') {\n this._introCompleteCallback.call(this);\n }\n _exitIntro.call(this, this._targetElement);\n return;\n }\n\n _showElement.call(this, nextStep);\n }\n\n /**\n * Go to previous step on intro\n *\n * @api private\n * @method _previousStep\n */\n function _previousStep() {\n this._direction = 'backward';\n\n if (this._currentStep === 0) {\n return false;\n }\n\n --this._currentStep;\n\n var nextStep = this._introItems[this._currentStep];\n var continueStep = true;\n\n if (typeof (this._introBeforeChangeCallback) !== 'undefined') {\n continueStep = this._introBeforeChangeCallback.call(this, nextStep.element);\n }\n\n // if `onbeforechange` returned `false`, stop displaying the element\n if (continueStep === false) {\n ++this._currentStep;\n return false;\n }\n\n _showElement.call(this, nextStep);\n }\n\n /**\n * Update placement of the intro objects on the screen\n * @api private\n */\n function _refresh() {\n // re-align intros\n _setHelperLayerPosition.call(this, document.querySelector('.introjs-helperLayer'));\n _setHelperLayerPosition.call(this, document.querySelector('.introjs-tooltipReferenceLayer'));\n _setHelperLayerPosition.call(this, document.querySelector('.introjs-disableInteraction'));\n\n // re-align tooltip\n if(this._currentStep !== undefined && this._currentStep !== null) {\n var oldHelperNumberLayer = document.querySelector('.introjs-helperNumberLayer'),\n oldArrowLayer = document.querySelector('.introjs-arrow'),\n oldtooltipContainer = document.querySelector('.introjs-tooltip');\n _placeTooltip.call(this, this._introItems[this._currentStep].element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);\n }\n\n //re-align hints\n _reAlignHints.call(this);\n return this;\n }\n\n /**\n * Exit from intro\n *\n * @api private\n * @method _exitIntro\n * @param {Object} targetElement\n * @param {Boolean} force - Setting to `true` will skip the result of beforeExit callback\n */\n function _exitIntro(targetElement, force) {\n var continueExit = true;\n\n // calling onbeforeexit callback\n //\n // If this callback return `false`, it would halt the process\n if (this._introBeforeExitCallback !== undefined) {\n continueExit = this._introBeforeExitCallback.call(this);\n }\n\n // skip this check if `force` parameter is `true`\n // otherwise, if `onbeforeexit` returned `false`, don't exit the intro\n if (!force && continueExit === false) return;\n\n //remove overlay layers from the page\n var overlayLayers = targetElement.querySelectorAll('.introjs-overlay');\n\n if (overlayLayers && overlayLayers.length) {\n _forEach(overlayLayers, function (overlayLayer) {\n overlayLayer.style.opacity = 0;\n window.setTimeout(function () {\n if (this.parentNode) {\n this.parentNode.removeChild(this);\n }\n }.bind(overlayLayer), 500);\n }.bind(this));\n }\n\n //remove all helper layers\n var helperLayer = targetElement.querySelector('.introjs-helperLayer');\n if (helperLayer) {\n helperLayer.parentNode.removeChild(helperLayer);\n }\n\n var referenceLayer = targetElement.querySelector('.introjs-tooltipReferenceLayer');\n if (referenceLayer) {\n referenceLayer.parentNode.removeChild(referenceLayer);\n }\n\n //remove disableInteractionLayer\n var disableInteractionLayer = targetElement.querySelector('.introjs-disableInteraction');\n if (disableInteractionLayer) {\n disableInteractionLayer.parentNode.removeChild(disableInteractionLayer);\n }\n\n //remove intro floating element\n var floatingElement = document.querySelector('.introjsFloatingElement');\n if (floatingElement) {\n floatingElement.parentNode.removeChild(floatingElement);\n }\n\n _removeShowElement();\n\n //remove `introjs-fixParent` class from the elements\n var fixParents = document.querySelectorAll('.introjs-fixParent');\n _forEach(fixParents, function (parent) {\n _removeClass(parent, /introjs-fixParent/g);\n });\n\n //clean listeners\n DOMEvent.off(window, 'keydown', _onKeyDown, this, true);\n DOMEvent.off(window, 'resize', _onResize, this, true);\n\n //check if any callback is defined\n if (this._introExitCallback !== undefined) {\n this._introExitCallback.call(this);\n }\n\n //set the step to zero\n this._currentStep = undefined;\n }\n\n /**\n * Render tooltip box in the page\n *\n * @api private\n * @method _placeTooltip\n * @param {HTMLElement} targetElement\n * @param {HTMLElement} tooltipLayer\n * @param {HTMLElement} arrowLayer\n * @param {HTMLElement} helperNumberLayer\n * @param {Boolean} hintMode\n */\n function _placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer, hintMode) {\n var tooltipCssClass = '',\n currentStepObj,\n tooltipOffset,\n targetOffset,\n windowSize,\n currentTooltipPosition;\n\n hintMode = hintMode || false;\n\n //reset the old style\n tooltipLayer.style.top = null;\n tooltipLayer.style.right = null;\n tooltipLayer.style.bottom = null;\n tooltipLayer.style.left = null;\n tooltipLayer.style.marginLeft = null;\n tooltipLayer.style.marginTop = null;\n\n arrowLayer.style.display = 'inherit';\n\n if (typeof(helperNumberLayer) !== 'undefined' && helperNumberLayer !== null) {\n helperNumberLayer.style.top = null;\n helperNumberLayer.style.left = null;\n }\n\n //prevent error when `this._currentStep` is undefined\n if (!this._introItems[this._currentStep]) return;\n\n //if we have a custom css class for each step\n currentStepObj = this._introItems[this._currentStep];\n if (typeof (currentStepObj.tooltipClass) === 'string') {\n tooltipCssClass = currentStepObj.tooltipClass;\n } else {\n tooltipCssClass = this._options.tooltipClass;\n }\n\n tooltipLayer.className = ('introjs-tooltip ' + tooltipCssClass).replace(/^\\s+|\\s+$/g, '');\n tooltipLayer.setAttribute('role', 'dialog');\n\n currentTooltipPosition = this._introItems[this._currentStep].position;\n\n // Floating is always valid, no point in calculating\n if (currentTooltipPosition !== \"floating\") { \n currentTooltipPosition = _determineAutoPosition.call(this, targetElement, tooltipLayer, currentTooltipPosition);\n }\n\n var tooltipLayerStyleLeft;\n targetOffset = _getOffset(targetElement);\n tooltipOffset = _getOffset(tooltipLayer);\n windowSize = _getWinSize();\n\n _addClass(tooltipLayer, 'introjs-' + currentTooltipPosition);\n\n switch (currentTooltipPosition) {\n case 'top-right-aligned':\n arrowLayer.className = 'introjs-arrow bottom-right';\n\n var tooltipLayerStyleRight = 0;\n _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);\n tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px';\n break;\n\n case 'top-middle-aligned':\n arrowLayer.className = 'introjs-arrow bottom-middle';\n\n var tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2;\n\n // a fix for middle aligned hints\n if (hintMode) {\n tooltipLayerStyleLeftRight += 5;\n }\n\n if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {\n tooltipLayer.style.right = null;\n _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);\n }\n tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px';\n break;\n\n case 'top-left-aligned':\n // top-left-aligned is the same as the default top\n case 'top':\n arrowLayer.className = 'introjs-arrow bottom';\n\n tooltipLayerStyleLeft = (hintMode) ? 0 : 15;\n\n _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);\n tooltipLayer.style.bottom = (targetOffset.height + 20) + 'px';\n break;\n case 'right':\n tooltipLayer.style.left = (targetOffset.width + 20) + 'px';\n if (targetOffset.top + tooltipOffset.height > windowSize.height) {\n // In this case, right would have fallen below the bottom of the screen.\n // Modify so that the bottom of the tooltip connects with the target\n arrowLayer.className = \"introjs-arrow left-bottom\";\n tooltipLayer.style.top = \"-\" + (tooltipOffset.height - targetOffset.height - 20) + \"px\";\n } else {\n arrowLayer.className = 'introjs-arrow left';\n }\n break;\n case 'left':\n if (!hintMode && this._options.showStepNumbers === true) {\n tooltipLayer.style.top = '15px';\n }\n\n if (targetOffset.top + tooltipOffset.height > windowSize.height) {\n // In this case, left would have fallen below the bottom of the screen.\n // Modify so that the bottom of the tooltip connects with the target\n tooltipLayer.style.top = \"-\" + (tooltipOffset.height - targetOffset.height - 20) + \"px\";\n arrowLayer.className = 'introjs-arrow right-bottom';\n } else {\n arrowLayer.className = 'introjs-arrow right';\n }\n tooltipLayer.style.right = (targetOffset.width + 20) + 'px';\n\n break;\n case 'floating':\n arrowLayer.style.display = 'none';\n\n //we have to adjust the top and left of layer manually for intro items without element\n tooltipLayer.style.left = '50%';\n tooltipLayer.style.top = '50%';\n tooltipLayer.style.marginLeft = '-' + (tooltipOffset.width / 2) + 'px';\n tooltipLayer.style.marginTop = '-' + (tooltipOffset.height / 2) + 'px';\n\n if (typeof(helperNumberLayer) !== 'undefined' && helperNumberLayer !== null) {\n helperNumberLayer.style.left = '-' + ((tooltipOffset.width / 2) + 18) + 'px';\n helperNumberLayer.style.top = '-' + ((tooltipOffset.height / 2) + 18) + 'px';\n }\n\n break;\n case 'bottom-right-aligned':\n arrowLayer.className = 'introjs-arrow top-right';\n\n tooltipLayerStyleRight = 0;\n _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);\n tooltipLayer.style.top = (targetOffset.height + 20) + 'px';\n break;\n\n case 'bottom-middle-aligned':\n arrowLayer.className = 'introjs-arrow top-middle';\n\n tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2;\n\n // a fix for middle aligned hints\n if (hintMode) {\n tooltipLayerStyleLeftRight += 5;\n }\n\n if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {\n tooltipLayer.style.right = null;\n _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);\n }\n tooltipLayer.style.top = (targetOffset.height + 20) + 'px';\n break;\n\n // case 'bottom-left-aligned':\n // Bottom-left-aligned is the same as the default bottom\n // case 'bottom':\n // Bottom going to follow the default behavior\n default:\n arrowLayer.className = 'introjs-arrow top';\n\n tooltipLayerStyleLeft = 0;\n _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);\n tooltipLayer.style.top = (targetOffset.height + 20) + 'px';\n }\n }\n\n /**\n * Set tooltip left so it doesn't go off the right side of the window\n *\n * @return boolean true, if tooltipLayerStyleLeft is ok. false, otherwise.\n */\n function _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer) {\n if (targetOffset.left + tooltipLayerStyleLeft + tooltipOffset.width > windowSize.width) {\n // off the right side of the window\n tooltipLayer.style.left = (windowSize.width - tooltipOffset.width - targetOffset.left) + 'px';\n return false;\n }\n tooltipLayer.style.left = tooltipLayerStyleLeft + 'px';\n return true;\n }\n\n /**\n * Set tooltip right so it doesn't go off the left side of the window\n *\n * @return boolean true, if tooltipLayerStyleRight is ok. false, otherwise.\n */\n function _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer) {\n if (targetOffset.left + targetOffset.width - tooltipLayerStyleRight - tooltipOffset.width < 0) {\n // off the left side of the window\n tooltipLayer.style.left = (-targetOffset.left) + 'px';\n return false;\n }\n tooltipLayer.style.right = tooltipLayerStyleRight + 'px';\n return true;\n }\n\n /**\n * Determines the position of the tooltip based on the position precedence and availability\n * of screen space.\n *\n * @param {Object} targetElement\n * @param {Object} tooltipLayer\n * @param {String} desiredTooltipPosition\n * @return {String} calculatedPosition\n */\n function _determineAutoPosition(targetElement, tooltipLayer, desiredTooltipPosition) {\n\n // Take a clone of position precedence. These will be the available\n var possiblePositions = this._options.positionPrecedence.slice();\n\n var windowSize = _getWinSize();\n var tooltipHeight = _getOffset(tooltipLayer).height + 10;\n var tooltipWidth = _getOffset(tooltipLayer).width + 20;\n var targetElementRect = targetElement.getBoundingClientRect();\n\n // If we check all the possible areas, and there are no valid places for the tooltip, the element\n // must take up most of the screen real estate. Show the tooltip floating in the middle of the screen.\n var calculatedPosition = \"floating\";\n\n /*\n * auto determine position \n */\n\n // Check for space below\n if (targetElementRect.bottom + tooltipHeight + tooltipHeight > windowSize.height) {\n _removeEntry(possiblePositions, \"bottom\");\n }\n\n // Check for space above\n if (targetElementRect.top - tooltipHeight < 0) {\n _removeEntry(possiblePositions, \"top\");\n }\n\n // Check for space to the right\n if (targetElementRect.right + tooltipWidth > windowSize.width) {\n _removeEntry(possiblePositions, \"right\");\n }\n\n // Check for space to the left\n if (targetElementRect.left - tooltipWidth < 0) {\n _removeEntry(possiblePositions, \"left\");\n }\n\n // @var {String} ex: 'right-aligned'\n var desiredAlignment = (function (pos) {\n var hyphenIndex = pos.indexOf('-');\n if (hyphenIndex !== -1) {\n // has alignment\n return pos.substr(hyphenIndex);\n }\n return '';\n })(desiredTooltipPosition || '');\n\n // strip alignment from position\n if (desiredTooltipPosition) {\n // ex: \"bottom-right-aligned\"\n // should return 'bottom'\n desiredTooltipPosition = desiredTooltipPosition.split('-')[0];\n }\n\n if (possiblePositions.length) {\n if (desiredTooltipPosition !== \"auto\" &&\n possiblePositions.indexOf(desiredTooltipPosition) > -1) {\n // If the requested position is in the list, choose that\n calculatedPosition = desiredTooltipPosition;\n } else {\n // Pick the first valid position, in order\n calculatedPosition = possiblePositions[0];\n }\n }\n\n // only top and bottom positions have optional alignments\n if (['top', 'bottom'].indexOf(calculatedPosition) !== -1) {\n calculatedPosition += _determineAutoAlignment(targetElementRect.left, tooltipWidth, windowSize, desiredAlignment);\n }\n\n return calculatedPosition;\n }\n\n /**\n * auto-determine alignment\n * @param {Integer} offsetLeft\n * @param {Integer} tooltipWidth\n * @param {Object} windowSize\n * @param {String} desiredAlignment\n * @return {String} calculatedAlignment\n */\n function _determineAutoAlignment (offsetLeft, tooltipWidth, windowSize, desiredAlignment) {\n var halfTooltipWidth = tooltipWidth / 2,\n winWidth = Math.min(windowSize.width, window.screen.width),\n possibleAlignments = ['-left-aligned', '-middle-aligned', '-right-aligned'],\n calculatedAlignment = '';\n \n // valid left must be at least a tooltipWidth\n // away from right side\n if (winWidth - offsetLeft < tooltipWidth) {\n _removeEntry(possibleAlignments, '-left-aligned');\n }\n\n // valid middle must be at least half \n // width away from both sides\n if (offsetLeft < halfTooltipWidth || \n winWidth - offsetLeft < halfTooltipWidth) {\n _removeEntry(possibleAlignments, '-middle-aligned');\n }\n\n // valid right must be at least a tooltipWidth\n // width away from left side\n if (offsetLeft < tooltipWidth) {\n _removeEntry(possibleAlignments, '-right-aligned');\n }\n\n if (possibleAlignments.length) {\n if (possibleAlignments.indexOf(desiredAlignment) !== -1) {\n // the desired alignment is valid\n calculatedAlignment = desiredAlignment;\n } else {\n // pick the first valid position, in order\n calculatedAlignment = possibleAlignments[0];\n }\n } else {\n // if screen width is too small \n // for ANY alignment, middle is \n // probably the best for visibility\n calculatedAlignment = '-middle-aligned';\n }\n\n return calculatedAlignment;\n }\n\n /**\n * Remove an entry from a string array if it's there, does nothing if it isn't there.\n *\n * @param {Array} stringArray\n * @param {String} stringToRemove\n */\n function _removeEntry(stringArray, stringToRemove) {\n if (stringArray.indexOf(stringToRemove) > -1) {\n stringArray.splice(stringArray.indexOf(stringToRemove), 1);\n }\n }\n\n /**\n * Update the position of the helper layer on the screen\n *\n * @api private\n * @method _setHelperLayerPosition\n * @param {Object} helperLayer\n */\n function _setHelperLayerPosition(helperLayer) {\n if (helperLayer) {\n //prevent error when `this._currentStep` in undefined\n if (!this._introItems[this._currentStep]) return;\n\n var currentElement = this._introItems[this._currentStep],\n elementPosition = _getOffset(currentElement.element),\n widthHeightPadding = this._options.helperElementPadding;\n\n // If the target element is fixed, the tooltip should be fixed as well.\n // Otherwise, remove a fixed class that may be left over from the previous\n // step.\n if (_isFixed(currentElement.element)) {\n _addClass(helperLayer, 'introjs-fixedTooltip');\n } else {\n _removeClass(helperLayer, 'introjs-fixedTooltip');\n }\n\n if (currentElement.position === 'floating') {\n widthHeightPadding = 0;\n }\n\n //set new position to helper layer\n helperLayer.style.cssText = 'width: ' + (elementPosition.width + widthHeightPadding) + 'px; ' +\n 'height:' + (elementPosition.height + widthHeightPadding) + 'px; ' +\n 'top:' + (elementPosition.top - widthHeightPadding / 2) + 'px;' +\n 'left: ' + (elementPosition.left - widthHeightPadding / 2) + 'px;';\n\n }\n }\n\n /**\n * Add disableinteraction layer and adjust the size and position of the layer\n *\n * @api private\n * @method _disableInteraction\n */\n function _disableInteraction() {\n var disableInteractionLayer = document.querySelector('.introjs-disableInteraction');\n\n if (disableInteractionLayer === null) {\n disableInteractionLayer = document.createElement('div');\n disableInteractionLayer.className = 'introjs-disableInteraction';\n this._targetElement.appendChild(disableInteractionLayer);\n }\n\n _setHelperLayerPosition.call(this, disableInteractionLayer);\n }\n\n /**\n * Setting anchors to behave like buttons\n *\n * @api private\n * @method _setAnchorAsButton\n */\n function _setAnchorAsButton(anchor){\n anchor.setAttribute('role', 'button');\n anchor.tabIndex = 0;\n }\n\n /**\n * Show an element on the page\n *\n * @api private\n * @method _showElement\n * @param {Object} targetElement\n */\n function _showElement(targetElement) {\n if (typeof (this._introChangeCallback) !== 'undefined') {\n this._introChangeCallback.call(this, targetElement.element);\n }\n\n var self = this,\n oldHelperLayer = document.querySelector('.introjs-helperLayer'),\n oldReferenceLayer = document.querySelector('.introjs-tooltipReferenceLayer'),\n highlightClass = 'introjs-helperLayer',\n nextTooltipButton,\n prevTooltipButton,\n skipTooltipButton,\n scrollParent;\n\n //check for a current step highlight class\n if (typeof (targetElement.highlightClass) === 'string') {\n highlightClass += (' ' + targetElement.highlightClass);\n }\n //check for options highlight class\n if (typeof (this._options.highlightClass) === 'string') {\n highlightClass += (' ' + this._options.highlightClass);\n }\n\n if (oldHelperLayer !== null) {\n var oldHelperNumberLayer = oldReferenceLayer.querySelector('.introjs-helperNumberLayer'),\n oldtooltipLayer = oldReferenceLayer.querySelector('.introjs-tooltiptext'),\n oldArrowLayer = oldReferenceLayer.querySelector('.introjs-arrow'),\n oldtooltipContainer = oldReferenceLayer.querySelector('.introjs-tooltip');\n \n skipTooltipButton = oldReferenceLayer.querySelector('.introjs-skipbutton');\n prevTooltipButton = oldReferenceLayer.querySelector('.introjs-prevbutton');\n nextTooltipButton = oldReferenceLayer.querySelector('.introjs-nextbutton');\n\n //update or reset the helper highlight class\n oldHelperLayer.className = highlightClass;\n //hide the tooltip\n oldtooltipContainer.style.opacity = 0;\n oldtooltipContainer.style.display = \"none\";\n\n if (oldHelperNumberLayer !== null) {\n var lastIntroItem = this._introItems[(targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0)];\n\n if (lastIntroItem !== null && (this._direction === 'forward' && lastIntroItem.position === 'floating') || (this._direction === 'backward' && targetElement.position === 'floating')) {\n oldHelperNumberLayer.style.opacity = 0;\n }\n }\n\n // scroll to element\n scrollParent = _getScrollParent( targetElement.element );\n\n if (scrollParent !== document.body) {\n // target is within a scrollable element\n _scrollParentToElement(scrollParent, targetElement.element);\n }\n\n // set new position to helper layer\n _setHelperLayerPosition.call(self, oldHelperLayer);\n _setHelperLayerPosition.call(self, oldReferenceLayer);\n\n //remove `introjs-fixParent` class from the elements\n var fixParents = document.querySelectorAll('.introjs-fixParent');\n _forEach(fixParents, function (parent) {\n _removeClass(parent, /introjs-fixParent/g);\n });\n \n //remove old classes if the element still exist\n _removeShowElement();\n\n //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation\n if (self._lastShowElementTimer) {\n window.clearTimeout(self._lastShowElementTimer);\n }\n\n self._lastShowElementTimer = window.setTimeout(function() {\n //set current step to the label\n if (oldHelperNumberLayer !== null) {\n oldHelperNumberLayer.innerHTML = targetElement.step;\n }\n //set current tooltip text\n oldtooltipLayer.innerHTML = targetElement.intro;\n //set the tooltip position\n oldtooltipContainer.style.display = \"block\";\n _placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);\n\n //change active bullet\n if (self._options.showBullets) {\n oldReferenceLayer.querySelector('.introjs-bullets li > a.active').className = '';\n oldReferenceLayer.querySelector('.introjs-bullets li > a[data-stepnumber=\"' + targetElement.step + '\"]').className = 'active';\n }\n oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').style.cssText = 'width:' + _getProgress.call(self) + '%;';\n oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').setAttribute('aria-valuenow', _getProgress.call(self));\n\n //show the tooltip\n oldtooltipContainer.style.opacity = 1;\n if (oldHelperNumberLayer) oldHelperNumberLayer.style.opacity = 1;\n\n //reset button focus\n if (typeof skipTooltipButton !== \"undefined\" && skipTooltipButton !== null && /introjs-donebutton/gi.test(skipTooltipButton.className)) {\n // skip button is now \"done\" button\n skipTooltipButton.focus();\n } else if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n //still in the tour, focus on next\n nextTooltipButton.focus();\n }\n\n // change the scroll of the window, if needed\n _scrollTo.call(self, targetElement.scrollTo, targetElement, oldtooltipLayer);\n }, 350);\n\n // end of old element if-else condition\n } else {\n var helperLayer = document.createElement('div'),\n referenceLayer = document.createElement('div'),\n arrowLayer = document.createElement('div'),\n tooltipLayer = document.createElement('div'),\n tooltipTextLayer = document.createElement('div'),\n bulletsLayer = document.createElement('div'),\n progressLayer = document.createElement('div'),\n buttonsLayer = document.createElement('div');\n\n helperLayer.className = highlightClass;\n referenceLayer.className = 'introjs-tooltipReferenceLayer';\n\n // scroll to element\n scrollParent = _getScrollParent( targetElement.element );\n\n if (scrollParent !== document.body) {\n // target is within a scrollable element\n _scrollParentToElement(scrollParent, targetElement.element);\n }\n\n //set new position to helper layer\n _setHelperLayerPosition.call(self, helperLayer);\n _setHelperLayerPosition.call(self, referenceLayer);\n\n //add helper layer to target element\n this._targetElement.appendChild(helperLayer);\n this._targetElement.appendChild(referenceLayer);\n\n arrowLayer.className = 'introjs-arrow';\n\n tooltipTextLayer.className = 'introjs-tooltiptext';\n tooltipTextLayer.innerHTML = targetElement.intro;\n\n bulletsLayer.className = 'introjs-bullets';\n\n if (this._options.showBullets === false) {\n bulletsLayer.style.display = 'none';\n }\n\n var ulContainer = document.createElement('ul');\n ulContainer.setAttribute('role', 'tablist');\n\n var anchorClick = function () {\n self.goToStep(this.getAttribute('data-stepnumber'));\n };\n\n _forEach(this._introItems, function (item, i) {\n var innerLi = document.createElement('li');\n var anchorLink = document.createElement('a');\n \n innerLi.setAttribute('role', 'presentation');\n anchorLink.setAttribute('role', 'tab');\n\n anchorLink.onclick = anchorClick;\n\n if (i === (targetElement.step-1)) {\n anchorLink.className = 'active';\n } \n\n _setAnchorAsButton(anchorLink);\n anchorLink.innerHTML = \" \";\n anchorLink.setAttribute('data-stepnumber', item.step);\n\n innerLi.appendChild(anchorLink);\n ulContainer.appendChild(innerLi);\n });\n\n bulletsLayer.appendChild(ulContainer);\n\n progressLayer.className = 'introjs-progress';\n\n if (this._options.showProgress === false) {\n progressLayer.style.display = 'none';\n }\n var progressBar = document.createElement('div');\n progressBar.className = 'introjs-progressbar';\n progressBar.setAttribute('role', 'progress');\n progressBar.setAttribute('aria-valuemin', 0);\n progressBar.setAttribute('aria-valuemax', 100);\n progressBar.setAttribute('aria-valuenow', _getProgress.call(this));\n progressBar.style.cssText = 'width:' + _getProgress.call(this) + '%;';\n\n progressLayer.appendChild(progressBar);\n\n buttonsLayer.className = 'introjs-tooltipbuttons';\n if (this._options.showButtons === false) {\n buttonsLayer.style.display = 'none';\n }\n\n tooltipLayer.className = 'introjs-tooltip';\n tooltipLayer.appendChild(tooltipTextLayer);\n tooltipLayer.appendChild(bulletsLayer);\n tooltipLayer.appendChild(progressLayer);\n\n //add helper layer number\n var helperNumberLayer = document.createElement('span');\n if (this._options.showStepNumbers === true) {\n helperNumberLayer.className = 'introjs-helperNumberLayer';\n helperNumberLayer.innerHTML = targetElement.step;\n referenceLayer.appendChild(helperNumberLayer);\n }\n\n tooltipLayer.appendChild(arrowLayer);\n referenceLayer.appendChild(tooltipLayer);\n\n //next button\n nextTooltipButton = document.createElement('a');\n\n nextTooltipButton.onclick = function() {\n if (self._introItems.length - 1 !== self._currentStep) {\n _nextStep.call(self);\n }\n };\n\n _setAnchorAsButton(nextTooltipButton);\n nextTooltipButton.innerHTML = this._options.nextLabel;\n\n //previous button\n prevTooltipButton = document.createElement('a');\n\n prevTooltipButton.onclick = function() {\n if (self._currentStep !== 0) {\n _previousStep.call(self);\n }\n };\n\n _setAnchorAsButton(prevTooltipButton);\n prevTooltipButton.innerHTML = this._options.prevLabel;\n\n //skip button\n skipTooltipButton = document.createElement('a');\n skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton ';\n _setAnchorAsButton(skipTooltipButton);\n skipTooltipButton.innerHTML = this._options.skipLabel;\n\n skipTooltipButton.onclick = function() {\n if (self._introItems.length - 1 === self._currentStep && typeof (self._introCompleteCallback) === 'function') {\n self._introCompleteCallback.call(self);\n }\n\n if (self._introItems.length - 1 !== self._currentStep && typeof (self._introExitCallback) === 'function') {\n self._introExitCallback.call(self);\n }\n\n if (typeof(self._introSkipCallback) === 'function') {\n self._introSkipCallback.call(self);\n }\n\n _exitIntro.call(self, self._targetElement);\n };\n\n buttonsLayer.appendChild(skipTooltipButton);\n\n //in order to prevent displaying next/previous button always\n if (this._introItems.length > 1) {\n buttonsLayer.appendChild(prevTooltipButton);\n buttonsLayer.appendChild(nextTooltipButton);\n }\n\n tooltipLayer.appendChild(buttonsLayer);\n\n //set proper position\n _placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer);\n\n // change the scroll of the window, if needed\n _scrollTo.call(this, targetElement.scrollTo, targetElement, tooltipLayer);\n\n //end of new element if-else condition\n }\n\n // removing previous disable interaction layer\n var disableInteractionLayer = self._targetElement.querySelector('.introjs-disableInteraction');\n if (disableInteractionLayer) {\n disableInteractionLayer.parentNode.removeChild(disableInteractionLayer);\n }\n\n //disable interaction\n if (targetElement.disableInteraction) {\n _disableInteraction.call(self);\n }\n\n // when it's the first step of tour\n if (this._currentStep === 0 && this._introItems.length > 1) {\n if (typeof skipTooltipButton !== \"undefined\" && skipTooltipButton !== null) {\n skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton';\n }\n if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton';\n }\n\n if (this._options.hidePrev === true) {\n if (typeof prevTooltipButton !== \"undefined\" && prevTooltipButton !== null) {\n prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton introjs-hidden';\n }\n if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n _addClass(nextTooltipButton, 'introjs-fullbutton');\n }\n } else {\n if (typeof prevTooltipButton !== \"undefined\" && prevTooltipButton !== null) {\n prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton introjs-disabled';\n }\n }\n\n if (typeof skipTooltipButton !== \"undefined\" && skipTooltipButton !== null) {\n skipTooltipButton.innerHTML = this._options.skipLabel;\n }\n } else if (this._introItems.length - 1 === this._currentStep || this._introItems.length === 1) {\n // last step of tour\n if (typeof skipTooltipButton !== \"undefined\" && skipTooltipButton !== null) {\n skipTooltipButton.innerHTML = this._options.doneLabel;\n // adding donebutton class in addition to skipbutton\n _addClass(skipTooltipButton, 'introjs-donebutton');\n }\n if (typeof prevTooltipButton !== \"undefined\" && prevTooltipButton !== null) {\n prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton';\n }\n\n if (this._options.hideNext === true) {\n if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton introjs-hidden';\n }\n if (typeof prevTooltipButton !== \"undefined\" && prevTooltipButton !== null) {\n _addClass(prevTooltipButton, 'introjs-fullbutton');\n }\n } else {\n if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton introjs-disabled';\n }\n }\n } else {\n // steps between start and end\n if (typeof skipTooltipButton !== \"undefined\" && skipTooltipButton !== null) {\n skipTooltipButton.className = this._options.buttonClass + ' introjs-skipbutton';\n }\n if (typeof prevTooltipButton !== \"undefined\" && prevTooltipButton !== null) {\n prevTooltipButton.className = this._options.buttonClass + ' introjs-prevbutton';\n }\n if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n nextTooltipButton.className = this._options.buttonClass + ' introjs-nextbutton';\n }\n if (typeof skipTooltipButton !== \"undefined\" && skipTooltipButton !== null) {\n skipTooltipButton.innerHTML = this._options.skipLabel;\n }\n }\n\n prevTooltipButton.setAttribute('role', 'button');\n nextTooltipButton.setAttribute('role', 'button');\n skipTooltipButton.setAttribute('role', 'button');\n\n //Set focus on \"next\" button, so that hitting Enter always moves you onto the next step\n if (typeof nextTooltipButton !== \"undefined\" && nextTooltipButton !== null) {\n nextTooltipButton.focus();\n }\n\n _setShowElement(targetElement);\n\n if (typeof (this._introAfterChangeCallback) !== 'undefined') {\n this._introAfterChangeCallback.call(this, targetElement.element);\n }\n }\n\n /**\n * To change the scroll of `window` after highlighting an element\n *\n * @api private\n * @method _scrollTo\n * @param {String} scrollTo\n * @param {Object} targetElement\n * @param {Object} tooltipLayer\n */\n function _scrollTo(scrollTo, targetElement, tooltipLayer) {\n if (scrollTo === 'off') return; \n var rect;\n\n if (!this._options.scrollToElement) return;\n\n if (scrollTo === 'tooltip') {\n rect = tooltipLayer.getBoundingClientRect();\n } else {\n rect = targetElement.element.getBoundingClientRect();\n }\n\n if (!_elementInViewport(targetElement.element)) {\n var winHeight = _getWinSize().height;\n var top = rect.bottom - (rect.bottom - rect.top);\n\n // TODO (afshinm): do we need scroll padding now?\n // I have changed the scroll option and now it scrolls the window to\n // the center of the target element or tooltip.\n\n if (top < 0 || targetElement.element.clientHeight > winHeight) {\n window.scrollBy(0, rect.top - ((winHeight / 2) - (rect.height / 2)) - this._options.scrollPadding); // 30px padding from edge to look nice\n\n //Scroll down\n } else {\n window.scrollBy(0, rect.top - ((winHeight / 2) - (rect.height / 2)) + this._options.scrollPadding); // 30px padding from edge to look nice\n }\n }\n }\n\n /**\n * To remove all show element(s)\n *\n * @api private\n * @method _removeShowElement\n */\n function _removeShowElement() {\n var elms = document.querySelectorAll('.introjs-showElement');\n\n _forEach(elms, function (elm) {\n _removeClass(elm, /introjs-[a-zA-Z]+/g);\n });\n }\n\n /**\n * To set the show element\n * This function set a relative (in most cases) position and changes the z-index\n *\n * @api private\n * @method _setShowElement\n * @param {Object} targetElement\n */\n function _setShowElement(targetElement) {\n var parentElm;\n // we need to add this show element class to the parent of SVG elements\n // because the SVG elements can't have independent z-index\n if (targetElement.element instanceof SVGElement) {\n parentElm = targetElement.element.parentNode;\n\n while (targetElement.element.parentNode !== null) {\n if (!parentElm.tagName || parentElm.tagName.toLowerCase() === 'body') break;\n\n if (parentElm.tagName.toLowerCase() === 'svg') {\n _addClass(parentElm, 'introjs-showElement introjs-relativePosition');\n }\n\n parentElm = parentElm.parentNode;\n }\n }\n\n _addClass(targetElement.element, 'introjs-showElement');\n\n var currentElementPosition = _getPropValue(targetElement.element, 'position');\n if (currentElementPosition !== 'absolute' &&\n currentElementPosition !== 'relative' &&\n currentElementPosition !== 'fixed') {\n //change to new intro item\n _addClass(targetElement.element, 'introjs-relativePosition');\n }\n\n parentElm = targetElement.element.parentNode;\n while (parentElm !== null) {\n if (!parentElm.tagName || parentElm.tagName.toLowerCase() === 'body') break;\n\n //fix The Stacking Context problem.\n //More detail: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context\n var zIndex = _getPropValue(parentElm, 'z-index');\n var opacity = parseFloat(_getPropValue(parentElm, 'opacity'));\n var transform = _getPropValue(parentElm, 'transform') || _getPropValue(parentElm, '-webkit-transform') || _getPropValue(parentElm, '-moz-transform') || _getPropValue(parentElm, '-ms-transform') || _getPropValue(parentElm, '-o-transform');\n if (/[0-9]+/.test(zIndex) || opacity < 1 || (transform !== 'none' && transform !== undefined)) {\n _addClass(parentElm, 'introjs-fixParent');\n }\n\n parentElm = parentElm.parentNode;\n }\n }\n\n /**\n * Iterates arrays\n *\n * @param {Array} arr\n * @param {Function} forEachFnc\n * @param {Function} completeFnc\n * @return {Null}\n */\n function _forEach(arr, forEachFnc, completeFnc) {\n // in case arr is an empty query selector node list\n if (arr) {\n for (var i = 0, len = arr.length; i < len; i++) {\n forEachFnc(arr[i], i);\n }\n }\n\n if (typeof(completeFnc) === 'function') {\n completeFnc();\n }\n }\n\n /**\n * Mark any object with an incrementing number\n * used for keeping track of objects\n *\n * @param Object obj Any object or DOM Element\n * @param String key\n * @return Object\n */\n var _stamp = (function () {\n var keys = {};\n return function stamp (obj, key) {\n \n // get group key\n key = key || 'introjs-stamp';\n\n // each group increments from 0\n keys[key] = keys[key] || 0;\n\n // stamp only once per object\n if (obj[key] === undefined) {\n // increment key for each new object\n obj[key] = keys[key]++;\n }\n\n return obj[key];\n };\n })();\n\n /**\n * DOMEvent Handles all DOM events\n *\n * methods:\n *\n * on - add event handler\n * off - remove event\n */\n var DOMEvent = (function () {\n function DOMEvent () {\n var events_key = 'introjs_event';\n \n /**\n * Gets a unique ID for an event listener\n *\n * @param Object obj\n * @param String type event type\n * @param Function listener\n * @param Object context\n * @return String\n */\n this._id = function (obj, type, listener, context) {\n return type + _stamp(listener) + (context ? '_' + _stamp(context) : '');\n };\n\n /**\n * Adds event listener\n *\n * @param Object obj\n * @param String type event type\n * @param Function listener\n * @param Object context\n * @param Boolean useCapture\n * @return null\n */\n this.on = function (obj, type, listener, context, useCapture) {\n var id = this._id.apply(this, arguments),\n handler = function (e) {\n return listener.call(context || obj, e || window.event);\n };\n\n if ('addEventListener' in obj) {\n obj.addEventListener(type, handler, useCapture);\n } else if ('attachEvent' in obj) {\n obj.attachEvent('on' + type, handler);\n }\n\n obj[events_key] = obj[events_key] || {};\n obj[events_key][id] = handler;\n };\n\n /**\n * Removes event listener\n *\n * @param Object obj\n * @param String type event type\n * @param Function listener\n * @param Object context\n * @param Boolean useCapture\n * @return null\n */\n this.off = function (obj, type, listener, context, useCapture) {\n var id = this._id.apply(this, arguments),\n handler = obj[events_key] && obj[events_key][id];\n\n if (!handler) {\n return;\n }\n\n if ('removeEventListener' in obj) {\n obj.removeEventListener(type, handler, useCapture);\n } else if ('detachEvent' in obj) {\n obj.detachEvent('on' + type, handler);\n }\n\n obj[events_key][id] = null;\n };\n }\n\n return new DOMEvent();\n })();\n\n /**\n * Append a class to an element\n *\n * @api private\n * @method _addClass\n * @param {Object} element\n * @param {String} className\n * @returns null\n */\n function _addClass(element, className) {\n if (element instanceof SVGElement) {\n // svg\n var pre = element.getAttribute('class') || '';\n\n element.setAttribute('class', pre + ' ' + className);\n } else {\n if (element.classList !== undefined) {\n // check for modern classList property\n var classes = className.split(' ');\n _forEach(classes, function (cls) {\n element.classList.add( cls );\n });\n } else if (!element.className.match( className )) {\n // check if element doesn't already have className\n element.className += ' ' + className;\n }\n }\n }\n\n /**\n * Remove a class from an element\n *\n * @api private\n * @method _removeClass\n * @param {Object} element\n * @param {RegExp|String} classNameRegex can be regex or string\n * @returns null\n */\n function _removeClass(element, classNameRegex) {\n if (element instanceof SVGElement) {\n var pre = element.getAttribute('class') || '';\n\n element.setAttribute('class', pre.replace(classNameRegex, '').replace(/^\\s+|\\s+$/g, ''));\n } else {\n element.className = element.className.replace(classNameRegex, '').replace(/^\\s+|\\s+$/g, '');\n }\n }\n\n /**\n * Get an element CSS property on the page\n * Thanks to JavaScript Kit: http://www.javascriptkit.com/dhtmltutors/dhtmlcascade4.shtml\n *\n * @api private\n * @method _getPropValue\n * @param {Object} element\n * @param {String} propName\n * @returns Element's property value\n */\n function _getPropValue (element, propName) {\n var propValue = '';\n if (element.currentStyle) { //IE\n propValue = element.currentStyle[propName];\n } else if (document.defaultView && document.defaultView.getComputedStyle) { //Others\n propValue = document.defaultView.getComputedStyle(element, null).getPropertyValue(propName);\n }\n\n //Prevent exception in IE\n if (propValue && propValue.toLowerCase) {\n return propValue.toLowerCase();\n } else {\n return propValue;\n }\n }\n\n /**\n * Checks to see if target element (or parents) position is fixed or not\n *\n * @api private\n * @method _isFixed\n * @param {Object} element\n * @returns Boolean\n */\n function _isFixed (element) {\n var p = element.parentNode;\n\n if (!p || p.nodeName === 'HTML') {\n return false;\n }\n\n if (_getPropValue(element, 'position') === 'fixed') {\n return true;\n }\n\n return _isFixed(p);\n }\n\n /**\n * Provides a cross-browser way to get the screen dimensions\n * via: http://stackoverflow.com/questions/5864467/internet-explorer-innerheight\n *\n * @api private\n * @method _getWinSize\n * @returns {Object} width and height attributes\n */\n function _getWinSize() {\n if (window.innerWidth !== undefined) {\n return { width: window.innerWidth, height: window.innerHeight };\n } else {\n var D = document.documentElement;\n return { width: D.clientWidth, height: D.clientHeight };\n }\n }\n\n /**\n * Check to see if the element is in the viewport or not\n * http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport\n *\n * @api private\n * @method _elementInViewport\n * @param {Object} el\n */\n function _elementInViewport(el) {\n var rect = el.getBoundingClientRect();\n\n return (\n rect.top >= 0 &&\n rect.left >= 0 &&\n (rect.bottom+80) <= window.innerHeight && // add 80 to get the text right\n rect.right <= window.innerWidth\n );\n }\n\n /**\n * Add overlay layer to the page\n *\n * @api private\n * @method _addOverlayLayer\n * @param {Object} targetElm\n */\n function _addOverlayLayer(targetElm) {\n var overlayLayer = document.createElement('div'),\n styleText = '',\n self = this;\n\n //set css class name\n overlayLayer.className = 'introjs-overlay';\n\n //check if the target element is body, we should calculate the size of overlay layer in a better way\n if (!targetElm.tagName || targetElm.tagName.toLowerCase() === 'body') {\n styleText += 'top: 0;bottom: 0; left: 0;right: 0;position: fixed;';\n overlayLayer.style.cssText = styleText;\n } else {\n //set overlay layer position\n var elementPosition = _getOffset(targetElm);\n if (elementPosition) {\n styleText += 'width: ' + elementPosition.width + 'px; height:' + elementPosition.height + 'px; top:' + elementPosition.top + 'px;left: ' + elementPosition.left + 'px;';\n overlayLayer.style.cssText = styleText;\n }\n }\n\n targetElm.appendChild(overlayLayer);\n\n overlayLayer.onclick = function() {\n if (self._options.exitOnOverlayClick === true) {\n _exitIntro.call(self, targetElm);\n }\n };\n\n window.setTimeout(function() {\n styleText += 'opacity: ' + self._options.overlayOpacity.toString() + ';';\n overlayLayer.style.cssText = styleText;\n }, 10);\n\n return true;\n }\n\n /**\n * Removes open hint (tooltip hint)\n *\n * @api private\n * @method _removeHintTooltip\n */\n function _removeHintTooltip() {\n var tooltip = document.querySelector('.introjs-hintReference');\n\n if (tooltip) {\n var step = tooltip.getAttribute('data-step');\n tooltip.parentNode.removeChild(tooltip);\n return step;\n }\n }\n\n /**\n * Start parsing hint items\n *\n * @api private\n * @param {Object} targetElm\n * @method _startHint\n */\n function _populateHints(targetElm) {\n\n this._introItems = [];\n\n if (this._options.hints) {\n _forEach(this._options.hints, function (hint) {\n var currentItem = _cloneObject(hint);\n\n if (typeof(currentItem.element) === 'string') {\n //grab the element with given selector from the page\n currentItem.element = document.querySelector(currentItem.element);\n }\n\n currentItem.hintPosition = currentItem.hintPosition || this._options.hintPosition;\n currentItem.hintAnimation = currentItem.hintAnimation || this._options.hintAnimation;\n\n if (currentItem.element !== null) {\n this._introItems.push(currentItem);\n }\n }.bind(this));\n } else {\n var hints = targetElm.querySelectorAll('*[data-hint]');\n\n if (!hints || !hints.length) {\n return false;\n }\n\n //first add intro items with data-step\n _forEach(hints, function (currentElement) {\n // hint animation\n var hintAnimation = currentElement.getAttribute('data-hintanimation');\n\n if (hintAnimation) {\n hintAnimation = (hintAnimation === 'true');\n } else {\n hintAnimation = this._options.hintAnimation;\n }\n\n this._introItems.push({\n element: currentElement,\n hint: currentElement.getAttribute('data-hint'),\n hintPosition: currentElement.getAttribute('data-hintposition') || this._options.hintPosition,\n hintAnimation: hintAnimation,\n tooltipClass: currentElement.getAttribute('data-tooltipclass'),\n position: currentElement.getAttribute('data-position') || this._options.tooltipPosition\n });\n }.bind(this));\n }\n\n _addHints.call(this);\n\n /* \n todo:\n these events should be removed at some point \n */\n DOMEvent.on(document, 'click', _removeHintTooltip, this, false);\n DOMEvent.on(window, 'resize', _reAlignHints, this, true);\n }\n\n /**\n * Re-aligns all hint elements\n *\n * @api private\n * @method _reAlignHints\n */\n function _reAlignHints() {\n _forEach(this._introItems, function (item) {\n if (typeof(item.targetElement) === 'undefined') {\n return;\n }\n\n _alignHintPosition.call(this, item.hintPosition, item.element, item.targetElement);\n }.bind(this));\n }\n\n /**\n * Get a queryselector within the hint wrapper\n *\n * @param {String} selector\n * @return {NodeList|Array}\n */\n function _hintQuerySelectorAll(selector) {\n var hintsWrapper = document.querySelector('.introjs-hints');\n return (hintsWrapper) ? hintsWrapper.querySelectorAll(selector) : [];\n }\n\n /**\n * Hide a hint\n *\n * @api private\n * @method _hideHint\n */\n function _hideHint(stepId) {\n var hint = _hintQuerySelectorAll('.introjs-hint[data-step=\"' + stepId + '\"]')[0];\n \n _removeHintTooltip.call(this);\n\n if (hint) {\n _addClass(hint, 'introjs-hidehint');\n }\n\n // call the callback function (if any)\n if (typeof (this._hintCloseCallback) !== 'undefined') {\n this._hintCloseCallback.call(this, stepId);\n }\n }\n\n /**\n * Hide all hints\n *\n * @api private\n * @method _hideHints\n */\n function _hideHints() {\n var hints = _hintQuerySelectorAll('.introjs-hint');\n\n _forEach(hints, function (hint) {\n _hideHint.call(this, hint.getAttribute('data-step'));\n }.bind(this));\n }\n\n /**\n * Show all hints\n *\n * @api private\n * @method _showHints\n */\n function _showHints() {\n var hints = _hintQuerySelectorAll('.introjs-hint');\n\n if (hints && hints.length) {\n _forEach(hints, function (hint) {\n _showHint.call(this, hint.getAttribute('data-step'));\n }.bind(this));\n } else {\n _populateHints.call(this, this._targetElement);\n }\n }\n\n /**\n * Show a hint\n *\n * @api private\n * @method _showHint\n */\n function _showHint(stepId) {\n var hint = _hintQuerySelectorAll('.introjs-hint[data-step=\"' + stepId + '\"]')[0];\n\n if (hint) {\n _removeClass(hint, /introjs-hidehint/g);\n }\n }\n\n /**\n * Removes all hint elements on the page\n * Useful when you want to destroy the elements and add them again (e.g. a modal or popup)\n *\n * @api private\n * @method _removeHints\n */\n function _removeHints() {\n var hints = _hintQuerySelectorAll('.introjs-hint');\n\n _forEach(hints, function (hint) {\n _removeHint.call(this, hint.getAttribute('data-step'));\n }.bind(this));\n }\n\n /**\n * Remove one single hint element from the page\n * Useful when you want to destroy the element and add them again (e.g. a modal or popup)\n * Use removeHints if you want to remove all elements.\n *\n * @api private\n * @method _removeHint\n */\n function _removeHint(stepId) {\n var hint = _hintQuerySelectorAll('.introjs-hint[data-step=\"' + stepId + '\"]')[0];\n\n if (hint) {\n hint.parentNode.removeChild(hint);\n }\n }\n\n /**\n * Add all available hints to the page\n *\n * @api private\n * @method _addHints\n */\n function _addHints() {\n var self = this;\n\n var hintsWrapper = document.querySelector('.introjs-hints');\n\n if (hintsWrapper === null) {\n hintsWrapper = document.createElement('div');\n hintsWrapper.className = 'introjs-hints';\n }\n\n /**\n * Returns an event handler unique to the hint iteration\n * \n * @param {Integer} i\n * @return {Function}\n */\n var getHintClick = function (i) {\n return function(e) {\n var evt = e ? e : window.event;\n \n if (evt.stopPropagation) {\n evt.stopPropagation();\n }\n\n if (evt.cancelBubble !== null) {\n evt.cancelBubble = true;\n }\n\n _showHintDialog.call(self, i);\n };\n };\n\n _forEach(this._introItems, function(item, i) {\n // avoid append a hint twice\n if (document.querySelector('.introjs-hint[data-step=\"' + i + '\"]')) {\n return;\n }\n\n var hint = document.createElement('a');\n _setAnchorAsButton(hint);\n\n hint.onclick = getHintClick(i);\n\n hint.className = 'introjs-hint';\n\n if (!item.hintAnimation) {\n _addClass(hint, 'introjs-hint-no-anim');\n }\n\n // hint's position should be fixed if the target element's position is fixed\n if (_isFixed(item.element)) {\n _addClass(hint, 'introjs-fixedhint');\n }\n\n var hintDot = document.createElement('div');\n hintDot.className = 'introjs-hint-dot';\n var hintPulse = document.createElement('div');\n hintPulse.className = 'introjs-hint-pulse';\n\n hint.appendChild(hintDot);\n hint.appendChild(hintPulse);\n hint.setAttribute('data-step', i);\n\n // we swap the hint element with target element\n // because _setHelperLayerPosition uses `element` property\n item.targetElement = item.element;\n item.element = hint;\n\n // align the hint position\n _alignHintPosition.call(this, item.hintPosition, hint, item.targetElement);\n\n hintsWrapper.appendChild(hint);\n }.bind(this));\n\n // adding the hints wrapper\n document.body.appendChild(hintsWrapper);\n\n // call the callback function (if any)\n if (typeof (this._hintsAddedCallback) !== 'undefined') {\n this._hintsAddedCallback.call(this);\n }\n }\n\n /**\n * Aligns hint position\n *\n * @api private\n * @method _alignHintPosition\n * @param {String} position\n * @param {Object} hint\n * @param {Object} element\n */\n function _alignHintPosition(position, hint, element) {\n // get/calculate offset of target element\n var offset = _getOffset.call(this, element);\n var iconWidth = 20;\n var iconHeight = 20;\n\n // align the hint element\n switch (position) {\n default:\n case 'top-left':\n hint.style.left = offset.left + 'px';\n hint.style.top = offset.top + 'px';\n break;\n case 'top-right':\n hint.style.left = (offset.left + offset.width - iconWidth) + 'px';\n hint.style.top = offset.top + 'px';\n break;\n case 'bottom-left':\n hint.style.left = offset.left + 'px';\n hint.style.top = (offset.top + offset.height - iconHeight) + 'px';\n break;\n case 'bottom-right':\n hint.style.left = (offset.left + offset.width - iconWidth) + 'px';\n hint.style.top = (offset.top + offset.height - iconHeight) + 'px';\n break;\n case 'middle-left':\n hint.style.left = offset.left + 'px';\n hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px';\n break;\n case 'middle-right':\n hint.style.left = (offset.left + offset.width - iconWidth) + 'px';\n hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px';\n break;\n case 'middle-middle':\n hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px';\n hint.style.top = (offset.top + (offset.height - iconHeight) / 2) + 'px';\n break;\n case 'bottom-middle':\n hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px';\n hint.style.top = (offset.top + offset.height - iconHeight) + 'px';\n break;\n case 'top-middle':\n hint.style.left = (offset.left + (offset.width - iconWidth) / 2) + 'px';\n hint.style.top = offset.top + 'px';\n break;\n }\n }\n\n /**\n * Triggers when user clicks on the hint element\n *\n * @api private\n * @method _showHintDialog\n * @param {Number} stepId\n */\n function _showHintDialog(stepId) {\n var hintElement = document.querySelector('.introjs-hint[data-step=\"' + stepId + '\"]');\n var item = this._introItems[stepId];\n\n // call the callback function (if any)\n if (typeof (this._hintClickCallback) !== 'undefined') {\n this._hintClickCallback.call(this, hintElement, item, stepId);\n }\n\n // remove all open tooltips\n var removedStep = _removeHintTooltip.call(this);\n\n // to toggle the tooltip\n if (parseInt(removedStep, 10) === stepId) {\n return;\n }\n\n var tooltipLayer = document.createElement('div');\n var tooltipTextLayer = document.createElement('div');\n var arrowLayer = document.createElement('div');\n var referenceLayer = document.createElement('div');\n\n tooltipLayer.className = 'introjs-tooltip';\n\n tooltipLayer.onclick = function (e) {\n //IE9 & Other Browsers\n if (e.stopPropagation) {\n e.stopPropagation();\n }\n //IE8 and Lower\n else {\n e.cancelBubble = true;\n }\n };\n\n tooltipTextLayer.className = 'introjs-tooltiptext';\n\n var tooltipWrapper = document.createElement('p');\n tooltipWrapper.innerHTML = item.hint;\n\n var closeButton = document.createElement('a');\n closeButton.className = this._options.buttonClass;\n closeButton.setAttribute('role', 'button');\n closeButton.innerHTML = this._options.hintButtonLabel;\n closeButton.onclick = _hideHint.bind(this, stepId);\n\n tooltipTextLayer.appendChild(tooltipWrapper);\n tooltipTextLayer.appendChild(closeButton);\n\n arrowLayer.className = 'introjs-arrow';\n tooltipLayer.appendChild(arrowLayer);\n\n tooltipLayer.appendChild(tooltipTextLayer);\n\n // set current step for _placeTooltip function\n this._currentStep = hintElement.getAttribute('data-step');\n\n // align reference layer position\n referenceLayer.className = 'introjs-tooltipReferenceLayer introjs-hintReference';\n referenceLayer.setAttribute('data-step', hintElement.getAttribute('data-step'));\n _setHelperLayerPosition.call(this, referenceLayer);\n\n referenceLayer.appendChild(tooltipLayer);\n document.body.appendChild(referenceLayer);\n\n //set proper position\n _placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer, null, true);\n }\n\n /**\n * Get an element position on the page\n * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966\n *\n * @api private\n * @method _getOffset\n * @param {Object} element\n * @returns Element's position info\n */\n function _getOffset(element) {\n var body = document.body;\n var docEl = document.documentElement;\n var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;\n var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;\n var x = element.getBoundingClientRect();\n return {\n top: x.top + scrollTop,\n width: x.width,\n height: x.height,\n left: x.left + scrollLeft\n };\n }\n\n /**\n * Find the nearest scrollable parent\n * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent\n *\n * @param Element element\n * @return Element\n */\n function _getScrollParent(element) {\n var style = window.getComputedStyle(element);\n var excludeStaticParent = (style.position === \"absolute\");\n var overflowRegex = /(auto|scroll)/;\n\n if (style.position === \"fixed\") return document.body;\n \n for (var parent = element; (parent = parent.parentElement);) {\n style = window.getComputedStyle(parent);\n if (excludeStaticParent && style.position === \"static\") {\n continue;\n }\n if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;\n }\n\n return document.body;\n }\n\n /**\n * scroll a scrollable element to a child element\n *\n * @param Element parent\n * @param Element element\n * @return Null\n */\n function _scrollParentToElement (parent, element) {\n parent.scrollTop = element.offsetTop - parent.offsetTop;\n }\n\n /**\n * Gets the current progress percentage\n *\n * @api private\n * @method _getProgress\n * @returns current progress percentage\n */\n function _getProgress() {\n // Steps are 0 indexed\n var currentStep = parseInt((this._currentStep + 1), 10);\n return ((currentStep / this._introItems.length) * 100);\n }\n\n /**\n * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1\n * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically\n *\n * @param obj1\n * @param obj2\n * @returns obj3 a new object based on obj1 and obj2\n */\n function _mergeOptions(obj1,obj2) {\n var obj3 = {},\n attrname;\n for (attrname in obj1) { obj3[attrname] = obj1[attrname]; }\n for (attrname in obj2) { obj3[attrname] = obj2[attrname]; }\n return obj3;\n }\n\n var introJs = function (targetElm) {\n var instance;\n\n if (typeof (targetElm) === 'object') {\n //Ok, create a new instance\n instance = new IntroJs(targetElm);\n\n } else if (typeof (targetElm) === 'string') {\n //select the target element with query selector\n var targetElement = document.querySelector(targetElm);\n\n if (targetElement) {\n instance = new IntroJs(targetElement);\n } else {\n throw new Error('There is no element with given selector.');\n }\n } else {\n instance = new IntroJs(document.body);\n }\n // add instance to list of _instances\n // passing group to _stamp to increment\n // from 0 onward somewhat reliably\n introJs.instances[ _stamp(instance, 'introjs-instance') ] = instance;\n\n return instance;\n };\n\n /**\n * Current IntroJs version\n *\n * @property version\n * @type String\n */\n introJs.version = VERSION;\n\n /**\n * key-val object helper for introJs instances\n *\n * @property instances\n * @type Object\n */\n introJs.instances = {};\n\n //Prototype\n introJs.fn = IntroJs.prototype = {\n clone: function () {\n return new IntroJs(this);\n },\n setOption: function(option, value) {\n this._options[option] = value;\n return this;\n },\n setOptions: function(options) {\n this._options = _mergeOptions(this._options, options);\n return this;\n },\n start: function (group) {\n _introForElement.call(this, this._targetElement, group);\n return this;\n },\n goToStep: function(step) {\n _goToStep.call(this, step);\n return this;\n },\n addStep: function(options) {\n if (!this._options.steps) {\n this._options.steps = [];\n }\n\n this._options.steps.push(options);\n\n return this;\n },\n addSteps: function(steps) {\n if (!steps.length) return;\n\n for(var index = 0; index < steps.length; index++) {\n this.addStep(steps[index]);\n }\n\n return this;\n },\n goToStepNumber: function(step) {\n _goToStepNumber.call(this, step);\n\n return this;\n },\n nextStep: function() {\n _nextStep.call(this);\n return this;\n },\n previousStep: function() {\n _previousStep.call(this);\n return this;\n },\n exit: function(force) {\n _exitIntro.call(this, this._targetElement, force);\n return this;\n },\n refresh: function() {\n _refresh.call(this);\n return this;\n },\n onbeforechange: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introBeforeChangeCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onbeforechange was not a function');\n }\n return this;\n },\n onchange: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introChangeCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onchange was not a function.');\n }\n return this;\n },\n onafterchange: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introAfterChangeCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onafterchange was not a function');\n }\n return this;\n },\n oncomplete: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introCompleteCallback = providedCallback;\n } else {\n throw new Error('Provided callback for oncomplete was not a function.');\n }\n return this;\n },\n onhintsadded: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._hintsAddedCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onhintsadded was not a function.');\n }\n return this;\n },\n onhintclick: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._hintClickCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onhintclick was not a function.');\n }\n return this;\n },\n onhintclose: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._hintCloseCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onhintclose was not a function.');\n }\n return this;\n },\n onexit: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introExitCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onexit was not a function.');\n }\n return this;\n },\n onskip: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introSkipCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onskip was not a function.');\n }\n return this;\n },\n onbeforeexit: function(providedCallback) {\n if (typeof (providedCallback) === 'function') {\n this._introBeforeExitCallback = providedCallback;\n } else {\n throw new Error('Provided callback for onbeforeexit was not a function.');\n }\n return this;\n },\n addHints: function() {\n _populateHints.call(this, this._targetElement);\n return this;\n },\n hideHint: function (stepId) {\n _hideHint.call(this, stepId);\n return this;\n },\n hideHints: function () {\n _hideHints.call(this);\n return this;\n },\n showHint: function (stepId) {\n _showHint.call(this, stepId);\n return this;\n },\n showHints: function () {\n _showHints.call(this);\n return this;\n },\n removeHints: function () {\n _removeHints.call(this);\n return this;\n },\n removeHint: function (stepId) {\n _removeHint.call(this, stepId);\n return this;\n },\n showHintDialog: function (stepId) {\n _showHintDialog.call(this, stepId);\n return this;\n }\n };\n\n return introJs;\n});\n"],"sourceRoot":"webpack:///","file":"scripts.766e1c760ba9e49c.js"}