1/*! 2 * Intro.js v3.0.1 3 * https://github.com/usablica/intro.js 4 * 5 * Copyright (C) 2017-2020 Afshin Mehrabani (@afshinmeh). 6 * https://raw.githubusercontent.com/usablica/intro.js/master/license.md 7 * 8 * Date: Sat, 17 Oct 2020 10:36:20 GMT 9 */ 10 11(function (global, factory) { 12 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 13 typeof define === 'function' && define.amd ? define(factory) : 14 (global = global || self, global.introJs = factory()); 15}(this, (function () { 16 'use strict'; 17 18 function _typeof(obj) { 19 "@babel/helpers - typeof"; 20 21 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { 22 _typeof = function (obj) { 23 return typeof obj; 24 }; 25 } else { 26 _typeof = function (obj) { 27 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 28 }; 29 } 30 31 return _typeof(obj); 32 } 33 34 /** 35 * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1 36 * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically 37 * 38 * @param obj1 39 * @param obj2 40 * @returns obj3 a new object based on obj1 and obj2 41 */ 42 function mergeOptions(obj1, obj2) { 43 var obj3 = {}; 44 var attrname; 45 46 for (attrname in obj1) { 47 obj3[attrname] = obj1[attrname]; 48 } 49 50 for (attrname in obj2) { 51 obj3[attrname] = obj2[attrname]; 52 } 53 54 return obj3; 55 } 56 57 /** 58 * Mark any object with an incrementing number 59 * used for keeping track of objects 60 * 61 * @param Object obj Any object or DOM Element 62 * @param String key 63 * @return Object 64 */ 65 var stamp = function () { 66 var keys = {}; 67 return function stamp(obj) { 68 var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "introjs-stamp"; 69 // each group increments from 0 70 keys[key] = keys[key] || 0; // stamp only once per object 71 72 if (obj[key] === undefined) { 73 // increment key for each new object 74 obj[key] = keys[key]++; 75 } 76 77 return obj[key]; 78 }; 79 }(); 80 81 /** 82 * Iterates arrays 83 * 84 * @param {Array} arr 85 * @param {Function} forEachFnc 86 * @param {Function} completeFnc 87 * @return {Null} 88 */ 89 function forEach(arr, forEachFnc, completeFnc) { 90 // in case arr is an empty query selector node list 91 if (arr) { 92 for (var i = 0, len = arr.length; i < len; i++) { 93 forEachFnc(arr[i], i); 94 } 95 } 96 97 if (typeof completeFnc === "function") { 98 completeFnc(); 99 } 100 } 101 102 /** 103 * Remove a class from an element 104 * 105 * @api private 106 * @method _removeClass 107 * @param {Object} element 108 * @param {RegExp|String} classNameRegex can be regex or string 109 * @returns null 110 */ 111 function removeClass(element, classNameRegex) { 112 if (element instanceof SVGElement) { 113 var pre = element.getAttribute("class") || ""; 114 element.setAttribute("class", pre.replace(classNameRegex, "").replace(/^\s+|\s+$/g, "")); 115 } else { 116 element.className = element.className.replace(classNameRegex, "").replace(/^\s+|\s+$/g, ""); 117 } 118 } 119 120 /** 121 * DOMEvent Handles all DOM events 122 * 123 * methods: 124 * 125 * on - add event handler 126 * off - remove event 127 */ 128 129 var DOMEvent = function () { 130 function DOMEvent() { 131 var events_key = "introjs_event"; 132 /** 133 * Gets a unique ID for an event listener 134 * 135 * @param obj Object 136 * @param type event type 137 * @param listener Function 138 * @param context Object 139 * @return String 140 */ 141 142 this._id = function (obj, type, listener, context) { 143 return type + stamp(listener) + (context ? "_".concat(stamp(context)) : ""); 144 }; 145 /** 146 * Adds event listener 147 * 148 * @param obj Object obj
149 * @param type String 150 * @param listener Function 151 * @param context Object 152 * @param useCapture Boolean 153 * @return null 154 */ 155 156 157 this.on = function (obj, type, listener, context, useCapture) { 158 var id = this._id.apply(this, arguments); 159 160 var handler = function handler(e) { 161 return listener.call(context || obj, e || window.event); 162 }; 163 164 if ("addEventListener" in obj) { 165 obj.addEventListener(type, handler, useCapture); 166 } else if ("attachEvent" in obj) { 167 obj.attachEvent("on".concat(type), handler); 168 } 169 170 obj[events_key] = obj[events_key] || {}; 171 obj[events_key][id] = handler; 172 }; 173 /** 174 * Removes event listener 175 * 176 * @param obj Object 177 * @param type String 178 * @param listener Function 179 * @param context Object 180 * @param useCapture Boolean 181 * @return null 182 */ 183 184 185 this.off = function (obj, type, listener, context, useCapture) { 186 var id = this._id.apply(this, arguments); 187 188 var handler = obj[events_key] && obj[events_key][id]; 189 190 if (!handler) { 191 return; 192 } 193 194 if ("removeEventListener" in obj) { 195 obj.removeEventListener(type, handler, useCapture); 196 } else if ("detachEvent" in obj) { 197 obj.detachEvent("on".concat(type), handler); 198 } 199 200 obj[events_key][id] = null; 201 }; 202 } 203 204 return new DOMEvent(); 205 }(); 206 207 /** 208 * Append a class to an element 209 * 210 * @api private 211 * @method _addClass 212 * @param {Object} element 213 * @param {String} className 214 * @returns null 215 */ 216 217 function addClass(element, className) { 218 if (element instanceof SVGElement) { 219 // svg 220 var pre = element.getAttribute("class") || ""; 221 element.setAttribute("class", "".concat(pre, " ").concat(className)); 222 } else { 223 if (element.classList !== undefined) { 224 // check for modern classList property 225 var classes = className.split(" "); 226 forEach(classes, function (cls) { 227 element.classList.add(cls); 228 }); 229 } else if (!element.className.match(className)) { 230 // check if element doesn't already have className 231 element.className += " ".concat(className); 232 } 233 } 234 } 235 236 /** 237 * Get an element CSS property on the page 238 * Thanks to JavaScript Kit: http://www.javascriptkit.com/dhtmltutors/dhtmlcascade4.shtml 239 * 240 * @api private 241 * @method _getPropValue 242 * @param {Object} element 243 * @param {String} propName 244 * @returns string property value 245 */ 246 function getPropValue(element, propName) { 247 var propValue = ""; 248 249 if (element.currentStyle) { 250 //IE 251 propValue = element.currentStyle[propName]; 252 } else if (document.defaultView && document.defaultView.getComputedStyle) { 253 //Others 254 propValue = document.defaultView.getComputedStyle(element, null).getPropertyValue(propName); 255 } //Prevent exception in IE 256 257 258 if (propValue && propValue.toLowerCase) { 259 return propValue.toLowerCase(); 260 } else { 261 return propValue; 262 } 263 } 264 265 /** 266 * To set the show element 267 * This function set a relative (in most cases) position and changes the z-index 268 * 269 * @api private 270 * @method _setShowElement 271 * @param {Object} targetElement 272 */ 273 274 function setShowElement(_ref) { 275 var element = _ref.element; 276 var parentElm;
276 // we need to add this show element class to the parent of SVG elements 277 // because the SVG elements can't have independent z-index 278 279 if (element instanceof SVGElement) { 280 parentElm = element.parentNode; 281 282 while (element.parentNode !== null) { 283 if (!parentElm.tagName || parentElm.tagName.toLowerCase() === "body") break; 284 285 if (parentElm.tagName.toLowerCase() === "svg") { 286 addClass(parentElm, "introjs-showElement introjs-relativePosition"); 287 } 288 289 parentElm = parentElm.parentNode; 290 } 291 } 292 293 addClass(element, "introjs-showElement"); 294 var currentElementPosition = getPropValue(element, "position"); 295 296 if (currentElementPosition !== "absolute" && currentElementPosition !== "relative" && currentElementPosition !== "fixed") { 297 //change to new intro item 298 addClass(element, "introjs-relativePosition"); 299 } 300 301 parentElm = element.parentNode; 302 303 while (parentElm !== null) { 304 if (!parentElm.tagName || parentElm.tagName.toLowerCase() === "body") break; //fix The Stacking Context problem. 305 //More detail: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context 306 307 var zIndex = getPropValue(parentElm, "z-index"); 308 var opacity = parseFloat(getPropValue(parentElm, "opacity")); 309 var transform = getPropValue(parentElm, "transform") || getPropValue(parentElm, "-webkit-transform") || getPropValue(parentElm, "-moz-transform") || getPropValue(parentElm, "-ms-transform") || getPropValue(parentElm, "-o-transform"); 310 311 if (/[0-9]+/.test(zIndex) || opacity < 1 || transform !== "none" && transform !== undefined) { 312 addClass(parentElm, "introjs-fixParent"); 313 } 314 315 parentElm = parentElm.parentNode; 316 } 317 } 318 319 /** 320 * scroll a scrollable element to a child element 321 * 322 * @param Element parent 323 * @param Element element 324 * @return Null 325 */ 326 function scrollParentToElement(parent, _ref) { 327 var offsetTop = _ref.offsetTop; 328 parent.scrollTop = offsetTop - parent.offsetTop; 329 } 330 331 /** 332 * Find the nearest scrollable parent 333 * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent 334 * 335 * @param Element element 336 * @return Element 337 */ 338 function getScrollParent(element) { 339 var style = window.getComputedStyle(element); 340 var excludeStaticParent = style.position === "absolute"; 341 var overflowRegex = /(auto|scroll)/; 342 if (style.position === "fixed") return document.body; 343 344 for (var parent = element; parent = parent.parentElement;) { 345 style = window.getComputedStyle(parent); 346 347 if (excludeStaticParent && style.position === "static") { 348 continue; 349 } 350 351 if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent; 352 } 353 354 return document.body; 355 } 356 357 /** 358 * Provides a cross-browser way to get the screen dimensions 359 * via: http://stackoverflow.com/questions/5864467/internet-explorer-innerheight 360 * 361 * @api private 362 * @method _getWinSize 363 * @returns {Object} width and height attributes 364 */ 365 function getWinSize() { 366 if (window.innerWidth !== undefined) { 367 return { 368 width: window.innerWidth, 369 height: window.innerHeight 370 }; 371 } else { 372 var D = document.documentElement; 373 return { 374 width: D.clientWidth, 375 height: D.clientHeight 376 }; 377 } 378 } 379 380 /** 381 * Check to see if the element is in the viewport or not 382 * http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport 383 * 384 * @api private 385 * @method _elementInViewport 386 * @param {Object} el 387 */ 388 function elementInViewport(el) { 389 var rect = el.getBoundingClientRect(); 390 return rect.top >= 0 && rect.left >= 0 && rect.bottom + 80 <= window.innerHeight && // add 80 to get the text right 391 rect.right <= window.innerWidth; 392 } 393 394 /** 395 * To change the scroll of `window` after highlighting an element 396 * 397 * @api private 398 * @method _scrollTo 399 * @param {String} scrollTo 400 * @param {Object} targetElement 401 * @param {Object} tooltipLayer 402 */ 403 404 function scrollTo(scrollTo, _ref, tooltipLayer) { 405 var element = _ref.element; 406 if (scrollTo === "off") return; 407 var rect; 408 if (!this._options.scrollToElement) return; 409 410 if (scrollTo === "tooltip") { 411 rect = tooltipLayer.getBoundingClientRect(); 412 } else { 413 rect = element.getBoundingClientRect(); 414 } 415 416 if (!elementInViewport(element)) { 417 var winHeight = getWinSize().height; 418 var top = rect.bottom - (rect.bottom - rect.top); // TODO (afshinm): do we need scroll padding now? 419 // I have changed the scroll option and now it scrolls the window to 420 // the center of the target element or tooltip. 421 422 if (top < 0 || element.clientHeight > winHeight) { 423 window.scrollBy(0, rect.top - (winHeight / 2 - rect.height / 2) - this._options.scrollPadding); // 30px padding from edge to look nice 424 //Scroll down 425 } else { 426 window.scrollBy(0, rect.top - (winHeight / 2 - rect.height / 2) + this._options.scrollPadding); // 30px padding from edge to look nice 427 } 428 } 429 } 430 431 /** 432 * Setting anchors to behave like buttons 433 * 434 * @api private 435 * @method _setAnchorAsButton 436 */ 437 function setAnchorAsButton(anchor) { 438 anchor.setAttribute("role", "button"); 439 anchor.tabIndex = 0; 440 } 441 442 /** 443 * Get an element position on the page 444 * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966 445 * 446 * @api private 447 * @method _getOffset 448 * @param {Object} element 449 * @returns Element's position info 450 */ 451 function getOffset(element) { 452 var body = document.body; 453 var docEl = document.documentElement; 454 var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop; 455 var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft; 456 var x = element.getBoundingClientRect(); 457 return { 458 top: x.top + scrollTop, 459 width: x.width, 460 height: x.height, 461 left: x.left + scrollLeft 462 }; 463 } 464 465 /** 466 * Checks to see if target element (or parents) position is fixed or not 467 * 468 * @api private 469 * @method _isFixed 470 * @param {Object} element 471 * @returns Boolean 472 */ 473 474 function isFixed(element) { 475 var p = element.parentNode; 476 477 if (!p || p.nodeName === "HTML") { 478 return false; 479 } 480 481 if (getPropValue(element, "position") === "fixed") { 482 return true; 483 } 484 485 return isFixed(p); 486 } 487 488 /** 489 * Update the position of the helper layer on the screen 490 * 491 * @api private 492 * @method _setHelperLayerPosition 493 * @param {Object} helperLayer 494 */ 495 496 function setHelperLayerPosition(helperLayer) {
497 if (helperLayer) { 498 //prevent error when `this._currentStep` in undefined 499 if (!this._introItems[this._currentStep]) return; 500 var currentElement = this._introItems[this._currentStep]; 501 var elementPosition = getOffset(currentElement.element); 502 var widthHeightPadding = this._options.helperElementPadding; // If the target element is fixed, the tooltip should be fixed as well. 503 // Otherwise, remove a fixed class that may be left over from the previous 504 // step. 505 506 if (isFixed(currentElement.element)) { 507 addClass(helperLayer, "introjs-fixedTooltip"); 508 } else { 509 removeClass(helperLayer, "introjs-fixedTooltip"); 510 } 511 512 if (currentElement.position === "floating") { 513 widthHeightPadding = 0; 514 } //set new position to helper layer 515 516 517 helperLayer.style.cssText = "width: ".concat(elementPosition.width + widthHeightPadding, "px; height:").concat(elementPosition.height + widthHeightPadding, "px; top:").concat(elementPosition.top - widthHeightPadding / 2, "px;left: ").concat(elementPosition.left - widthHeightPadding / 2, "px;"); 518 } 519 } 520 521 /** 522 * Set tooltip left so it doesn't go off the right side of the window 523 * 524 * @return boolean true, if tooltipLayerStyleLeft is ok. false, otherwise. 525 */ 526 function checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer) { 527 if (targetOffset.left + tooltipLayerStyleLeft + tooltipOffset.width > windowSize.width) { 528 // off the right side of the window 529 tooltipLayer.left = "".concat(windowSize.width - tooltipOffset.width - targetOffset.left, "px"); 530 return false; 531 } 532 533 tooltipLayer.left = "".concat(tooltipLayerStyleLeft, "px"); 534 return true; 535 } 536 537 /** 538 * Set tooltip right so it doesn't go off the left side of the window 539 * 540 * @return boolean true, if tooltipLayerStyleRight is ok. false, otherwise. 541 */ 542 function checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer) { 543 if (targetOffset.left + targetOffset.width - tooltipLayerStyleRight - tooltipOffset.width < 0) { 544 // off the left side of the window 545 tooltipLayer.style.left = "".concat(-targetOffset.left, "px"); 546 return false; 547 } 548 549 tooltipLayer.style.right = "".concat(tooltipLayerStyleRight, "px"); 550 return true; 551 } 552 553 /** 554 * Remove an entry from a string array if it's there, does nothing if it isn't there. 555 * 556 * @param {Array} stringArray 557 * @param {String} stringToRemove 558 */ 559 function removeEntry(stringArray, stringToRemove) { 560 if (stringArray.includes(stringToRemove)) { 561 stringArray.splice(stringArray.indexOf(stringToRemove), 1); 562 } 563 } 564 565 /** 566 * auto-determine alignment 567 * @param {Integer} offsetLeft 568 * @param {Integer} tooltipWidth 569 * @param {Object} windowSize 570 * @param {String} desiredAlignment 571 * @return {String} calculatedAlignment 572 */ 573 574 function _determineAutoAlignment(offsetLeft, tooltipWidth, _ref, desiredAlignment) { 575 var width = _ref.width; 576 var halfTooltipWidth = tooltipWidth / 2; 577 var winWidth = Math.min(width, window.screen.width); 578 var possibleAlignments = ["-left-aligned", "-middle-aligned", "-right-aligned"]; 579 var calculatedAlignment = ""; // valid left must be at least a tooltipWidth 580 // away from right side 581 582 if (winWidth - offsetLeft < tooltipWidth) { 583 removeEntry(possibleAlignments, "-left-aligned"); 584 } // valid middle must be at least half 585 // width away from both sides 586 587 588 if (offsetLeft < halfTooltipWidth || winWidth - offsetLeft < halfTooltipWidth) { 589 removeEntry(possibleAlignments, "-middle-aligned"); 590 } // valid right must be at least a tooltipWidth 591 // width away from left side 592 593 594 if (offsetLeft < tooltipWidth) { 595 removeEntry(possibleAlignments, "-right-aligned"); 596 } 597 598 if (possibleAlignments.length) { 599 if (possibleAlignments.includes(desiredAlignment)) { 600 // the desired alignment is valid 601 calculatedAlignment = desiredAlignment; 602 } else { 603 // pick the first valid position, in order 604 calculatedAlignment = possibleAlignments[0]; 605 } 606 } else { 607 // if screen width is too small 608 // for ANY alignment, middle is 609 // probably the best for visibility 610 calculatedAlignment = "-middle-aligned"; 611 } 612 613 return calculatedAlignment; 614 } 615 /** 616 * Determines the position of the tooltip based on the position precedence and availability 617 * of screen space. 618 * 619 * @param {Object} targetElement 620 * @param {Object} tooltipLayer 621 * @param {String} desiredTooltipPosition 622 * @return {String} calculatedPosition 623 */ 624 625 626 function _determineAutoPosition(targetElement, tooltipLayer, desiredTooltipPosition) {
627 // Take a clone of position precedence. These will be the available 628 var possiblePositions = this._options.positionPrecedence.slice(); 629 630 var windowSize = getWinSize(); 631 var tooltipHeight = getOffset(tooltipLayer).height + 10; 632 var tooltipWidth = getOffset(tooltipLayer).width + 20; 633 var targetElementRect = targetElement.getBoundingClientRect(); // If we check all the possible areas, and there are no valid places for the tooltip, the element 634 // must take up most of the screen real estate. Show the tooltip floating in the middle of the screen. 635 636 var calculatedPosition = "floating"; 637 /* 638 * auto determine position 639 */ 640 // Check for space below 641 642 if (targetElementRect.bottom + tooltipHeight > windowSize.height) { 643 removeEntry(possiblePositions, "bottom"); 644 } // Check for space above 645 646 647 if (targetElementRect.top - tooltipHeight < 0) { 648 removeEntry(possiblePositions, "top"); 649 } // Check for space to the right 650 651 652 if (targetElementRect.right + tooltipWidth > windowSize.width) { 653 removeEntry(possiblePositions, "right"); 654 } // Check for space to the left 655 656 657 if (targetElementRect.left - tooltipWidth < 0) { 658 removeEntry(possiblePositions, "left"); 659 } // @var {String} ex: 'right-aligned' 660 661 662 var desiredAlignment = function (pos) { 663 var hyphenIndex = pos.indexOf("-"); 664 665 if (hyphenIndex !== -1) { 666 // has alignment 667 return pos.substr(hyphenIndex); 668 } 669 670 return ""; 671 }(desiredTooltipPosition || ""); // strip alignment from position 672 673 674 if (desiredTooltipPosition) { 675 // ex: "bottom-right-aligned" 676 // should return 'bottom' 677 desiredTooltipPosition = desiredTooltipPosition.split("-")[0]; 678 } 679 680 if (possiblePositions.length) { 681 if (desiredTooltipPosition !== "auto" && possiblePositions.includes(desiredTooltipPosition)) { 682 // If the requested position is in the list, choose that 683 calculatedPosition = desiredTooltipPosition; 684 } else { 685 // Pick the first valid position, in order 686 calculatedPosition = possiblePositions[0]; 687 } 688 } // only top and bottom positions have optional alignments 689 690 691 if (["top", "bottom"].includes(calculatedPosition)) { 692 calculatedPosition += _determineAutoAlignment(targetElementRect.left, tooltipWidth, windowSize, desiredAlignment); 693 } 694 695 return calculatedPosition; 696 } 697 /** 698 * Render tooltip box in the page 699 * 700 * @api private 701 * @method placeTooltip 702 * @param {HTMLElement} targetElement 703 * @param {HTMLElement} tooltipLayer 704 * @param {HTMLElement} arrowLayer 705 * @param {HTMLElement} helperNumberLayer 706 * @param {Boolean} hintMode 707 */ 708 709 710 function placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer, hintMode) { 711 var tooltipCssClass = ""; 712 var currentStepObj; 713 var tooltipOffset; 714 var targetOffset; 715 var windowSize; 716 var currentTooltipPosition; 717 hintMode = hintMode || false; //reset the old style 718 719 tooltipLayer.style.top = null; 720 tooltipLayer.style.right = null; 721 tooltipLayer.style.bottom = null; 722 tooltipLayer.style.left = null; 723 tooltipLayer.style.marginLeft = null; 724 tooltipLayer.style.marginTop = null; 725 arrowLayer.style.display = "inherit"; 726 727 if (typeof helperNumberLayer !== "undefined" && helperNumberLayer !== null) { 728 helperNumberLayer.style.top = null; 729 helperNumberLayer.style.left = null; 730 } //prevent error when `this._currentStep` is undefined 731 732 733 if (!this._introItems[this._currentStep]) return; //if we have a custom css class for each step 734 735 currentStepObj = this._introItems[this._currentStep]; 736 737 if (typeof currentStepObj.tooltipClass === "string") { 738 tooltipCssClass = currentStepObj.tooltipClass; 739 } else { 740 tooltipCssClass = this._options.tooltipClass; 741 } 742 743 tooltipLayer.className = "introjs-tooltip ".concat(tooltipCssClass).replace(/^\s+|\s+$/g, ""); 744 tooltipLayer.setAttribute("role", "dialog"); 745 currentTooltipPosition = this._introItems[this._currentStep].position; // Floating is always valid, no point in calculating 746 747 if (currentTooltipPosition !== "floating") { 748 currentTooltipPosition = _determineAutoPosition.call(this, targetElement, tooltipLayer, currentTooltipPosition); 749 } 750 751 var tooltipLayerStyleLeft; 752 targetOffset = getOffset(targetElement); 753 tooltipOffset = getOffset(tooltipLayer); 754 windowSize = getWinSize(); 755 addClass(tooltipLayer, "introjs-".concat(currentTooltipPosition)); 756 757 switch (currentTooltipPosition) { 758 case "top-right-aligned": 759 arrowLayer.className = "introjs-arrow bottom-right"; 760 var tooltipLayerStyleRight = 0; 761 checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer); 762 tooltipLayer.style.bottom = "".concat(targetOffset.height + 20, "px"); 763 break; 764 765 case "top-middle-aligned": 766 arrowLayer.className = "introjs-arrow bottom-middle"; 767 var tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2; // a fix for middle aligned hints 768 769 if (hintMode) { 770 tooltipLayerStyleLeftRight += 5; 771 } 772 773 if (checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) { 774 tooltipLayer.style.right = null; 775 checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer); 776 } 777 778 tooltipLayer.style.bottom = "".concat(targetOffset.height + 20, "px"); 779 break; 780 781 case "top-left-aligned": // top-left-aligned is the same as the default top 782 783 case "top": 784 arrowLayer.className = "introjs-arrow bottom"; 785 tooltipLayerStyleLeft = hintMode ? 0 : 15; 786 checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer); 787 tooltipLayer.style.bottom = "".concat(targetOffset.height + 20, "px"); 788 break; 789 790 case "right": 791 tooltipLayer.style.left = "".concat(targetOffset.width + 20, "px"); 792 793 if (targetOffset.top + tooltipOffset.height > windowSize.height) { 794 // In this case, right would have fallen below the bottom of the screen. 795 // Modify so that the bottom of the tooltip connects with the target 796 arrowLayer.className = "introjs-arrow left-bottom"; 797 tooltipLayer.style.top = "-".concat(tooltipOffset.height - targetOffset.height - 20, "px"); 798 } else { 799 arrowLayer.className = "introjs-arrow left"; 800 } 801 802 break; 803
804 case "left": 805 if (!hintMode && this._options.showStepNumbers === true) { 806 tooltipLayer.style.top = "15px"; 807 } 808 809 if (targetOffset.top + tooltipOffset.height > windowSize.height) { 810 // In this case, left would have fallen below the bottom of the screen. 811 // Modify so that the bottom of the tooltip connects with the target 812 tooltipLayer.style.top = "-".concat(tooltipOffset.height - targetOffset.height - 20, "px"); 813 arrowLayer.className = "introjs-arrow right-bottom"; 814 } else { 815 arrowLayer.className = "introjs-arrow right"; 816 } 817 818 tooltipLayer.style.right = "".concat(targetOffset.width + 20, "px"); 819 break; 820 821 case "floating": 822 arrowLayer.style.display = "none"; //we have to adjust the top and left of layer manually for intro items without element 823 824 tooltipLayer.style.left = "50%"; 825 tooltipLayer.style.top = "50%"; 826 tooltipLayer.style.marginLeft = "-".concat(tooltipOffset.width / 2, "px"); 827 tooltipLayer.style.marginTop = "-".concat(tooltipOffset.height / 2, "px"); 828 829 if (typeof helperNumberLayer !== "undefined" && helperNumberLayer !== null) { 830 helperNumberLayer.style.left = "-".concat(tooltipOffset.width / 2 + 18, "px"); 831 helperNumberLayer.style.top = "-".concat(tooltipOffset.height / 2 + 18, "px"); 832 } 833 834 break; 835 836 case "bottom-right-aligned": 837 arrowLayer.className = "introjs-arrow top-right"; 838 tooltipLayerStyleRight = 0; 839 checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer); 840 tooltipLayer.style.top = "".concat(targetOffset.height + 20, "px"); 841 break; 842 843 case "bottom-middle-aligned": 844 arrowLayer.className = "introjs-arrow top-middle"; 845 tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2; // a fix for middle aligned hints 846 847 if (hintMode) { 848 tooltipLayerStyleLeftRight += 5; 849 } 850 851 if (checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) { 852 tooltipLayer.style.right = null; 853 checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer); 854 } 855 856 tooltipLayer.style.top = "".concat(targetOffset.height + 20, "px"); 857 break; 858 // case 'bottom-left-aligned': 859 // Bottom-left-aligned is the same as the default bottom 860 // case 'bottom': 861 // Bottom going to follow the default behavior 862 863 default: 864 arrowLayer.className = "introjs-arrow top"; 865 tooltipLayerStyleLeft = 0; 866 checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer); 867 tooltipLayer.style.top = "".concat(targetOffset.height + 20, "px"); 868 } 869 } 870 871 /** 872 * To remove all show element(s) 873 * 874 * @api private 875 * @method _removeShowElement 876 */ 877 878 function removeShowElement() { 879 var elms = document.querySelectorAll(".introjs-showElement"); 880 forEach(elms, function (elm) { 881 removeClass(elm, /introjs-[a-zA-Z]+/g); 882 }); 883 } 884 885 /** 886 * Gets the current progress percentage 887 * 888 * @api private 889 * @method _getProgress 890 * @returns current progress percentage 891 */ 892 893 function _getProgress() { 894 // Steps are 0 indexed 895 var currentStep = parseInt(this._currentStep + 1, 10); 896 return currentStep / this._introItems.length * 100; 897 } 898 /** 899 * Add disableinteraction layer and adjust the size and position of the layer 900 * 901 * @api private 902 * @method _disableInteraction 903 */ 904 905 906 function _disableInteraction() { 907 var disableInteractionLayer = document.querySelector(".introjs-disableInteraction"); 908 909 if (disableInteractionLayer === null) { 910 disableInteractionLayer = document.createElement("div"); 911 disableInteractionLayer.className = "introjs-disableInteraction"; 912 913 this._targetElement.appendChild(disableInteractionLayer); 914 } 915 916 setHelperLayerPosition.call(this, disableInteractionLayer); 917 } 918 /** 919 * Show an element on the page 920 * 921 * @api private 922 * @method _showElement 923 * @param {Object} targetElement 924 */ 925 926 927 function _showElement(targetElement) { 928 if (typeof this._introChangeCallback !== "undefined") { 929 this._introChangeCallback.call(this, targetElement.element); 930 } 931 932 var self = this; 933 var oldHelperLayer = document.querySelector(".introjs-helperLayer"); 934 var oldReferenceLayer = document.querySelector(".introjs-tooltipReferenceLayer"); 935 var highlightClass = "introjs-helperLayer"; 936 var nextTooltipButton; 937 var prevTooltipButton; 938 var skipTooltipButton; 939 var scrollParent; //check for a current step highlight class 940 941 if (typeof targetElement.highlightClass === "string") { 942 highlightClass += " ".concat(targetElement.highlightClass); 943 } //check for options highlight class 944 945 946 if (typeof this._options.highlightClass === "string") { 947 highlightClass += " ".concat(this._options.highlightClass); 948 } 949 950 if (oldHelperLayer !== null) {
951 var oldHelperNumberLayer = oldReferenceLayer.querySelector(".introjs-helperNumberLayer"); 952 var oldtooltipLayer = oldReferenceLayer.querySelector(".introjs-tooltiptext"); 953 var oldArrowLayer = oldReferenceLayer.querySelector(".introjs-arrow"); 954 var oldtooltipContainer = oldReferenceLayer.querySelector(".introjs-tooltip"); 955 skipTooltipButton = oldReferenceLayer.querySelector(".introjs-skipbutton"); 956 prevTooltipButton = oldReferenceLayer.querySelector(".introjs-prevbutton"); 957 nextTooltipButton = oldReferenceLayer.querySelector(".introjs-nextbutton"); //update or reset the helper highlight class 958 959 oldHelperLayer.className = highlightClass; //hide the tooltip 960 961 oldtooltipContainer.style.opacity = 0; 962 oldtooltipContainer.style.display = "none"; 963 964 if (oldHelperNumberLayer !== null) { 965 var lastIntroItem = this._introItems[targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0]; 966 967 if (lastIntroItem !== null && this._direction === "forward" && lastIntroItem.position === "floating" || this._direction === "backward" && targetElement.position === "floating") { 968 oldHelperNumberLayer.style.opacity = 0; 969 } 970 } // scroll to element 971 972 973 scrollParent = getScrollParent(targetElement.element); 974 975 if (scrollParent !== document.body) { 976 // target is within a scrollable element 977 scrollParentToElement(scrollParent, targetElement.element); 978 } // set new position to helper layer 979 980 981 setHelperLayerPosition.call(self, oldHelperLayer); 982 setHelperLayerPosition.call(self, oldReferenceLayer); //remove `introjs-fixParent` class from the elements 983 984 var fixParents = document.querySelectorAll(".introjs-fixParent"); 985 forEach(fixParents, function (parent) { 986 removeClass(parent, /introjs-fixParent/g); 987 }); //remove old classes if the element still exist 988 989 removeShowElement(); //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation 990 991 if (self._lastShowElementTimer) { 992 window.clearTimeout(self._lastShowElementTimer); 993 } 994 995 self._lastShowElementTimer = window.setTimeout(function () { 996 //set current step to the label 997 if (oldHelperNumberLayer !== null) { 998 oldHelperNumberLayer.innerHTML = targetElement.step; 999 } //set current tooltip text 1000 1001 1002 oldtooltipLayer.innerHTML = targetElement.intro; //set the tooltip position 1003 1004 oldtooltipContainer.style.display = "block"; 1005 placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer); //change active bullet 1006 1007 if (self._options.showBullets) { 1008 oldReferenceLayer.querySelector(".introjs-bullets li > a.active").className = ""; 1009 oldReferenceLayer.querySelector(".introjs-bullets li > a[data-stepnumber=\"".concat(targetElement.step, "\"]")).className = "active"; 1010 } 1011 1012 oldReferenceLayer.querySelector(".introjs-progress .introjs-progressbar").style.cssText = "width:".concat(_getProgress.call(self), "%;"); 1013 oldReferenceLayer.querySelector(".introjs-progress .introjs-progressbar").setAttribute("aria-valuenow", _getProgress.call(self)); //show the tooltip 1014 1015 oldtooltipContainer.style.opacity = 1; 1016 if (oldHelperNumberLayer) oldHelperNumberLayer.style.opacity = 1; //reset button focus 1017 1018 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null && /introjs-donebutton/gi.test(skipTooltipButton.className)) { 1019 // skip button is now "done" button 1020 skipTooltipButton.focus(); 1021 } else if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1022 //still in the tour, focus on next 1023 nextTooltipButton.focus(); 1024 } // change the scroll of the window, if needed 1025 1026 1027 scrollTo.call(self, targetElement.scrollTo, targetElement, oldtooltipLayer); 1028 }, 350); // end of old element if-else condition 1029 } else { 1030 var helperLayer = document.createElement("div"); 1031 var referenceLayer = document.createElement("div"); 1032 var arrowLayer = document.createElement("div"); 1033 var tooltipLayer = document.createElement("div"); 1034 var tooltipTextLayer = document.createElement("div"); 1035 var bulletsLayer = document.createElement("div"); 1036 var progressLayer = document.createElement("div"); 1037 var buttonsLayer = document.createElement("div"); 1038 helperLayer.className = highlightClass; 1039 referenceLayer.className = "introjs-tooltipReferenceLayer"; // scroll to element 1040 1041 scrollParent = getScrollParent(targetElement.element); 1042 1043 if (scrollParent !== document.body) { 1044 // target is within a scrollable element 1045 scrollParentToElement(scrollParent, targetElement.element); 1046 } //set new position to helper layer 1047 1048 1049 setHelperLayerPosition.call(self, helperLayer); 1050 setHelperLayerPosition.call(self, referenceLayer); //add helper layer to target element 1051 1052 this._targetElement.appendChild(helperLayer); 1053 1054 this._targetElement.appendChild(referenceLayer); 1055 1056 arrowLayer.className = "introjs-arrow"; 1057 tooltipTextLayer.className = "introjs-tooltiptext"; 1058 tooltipTextLayer.innerHTML = targetElement.intro; 1059 bulletsLayer.className = "introjs-bullets"; 1060 1061 if (this._options.showBullets === false) { 1062 bulletsLayer.style.display = "none"; 1063 } 1064 1065 var ulContainer = document.createElement("ul"); 1066 ulContainer.setAttribute("role", "tablist"); 1067 1068 var anchorClick = function anchorClick() { 1069 self.goToStep(this.getAttribute("data-stepnumber")); 1070 }; 1071
1072 forEach(this._introItems, function (_ref, i) { 1073 var step = _ref.step; 1074 var innerLi = document.createElement("li"); 1075 var anchorLink = document.createElement("a"); 1076 innerLi.setAttribute("role", "presentation"); 1077 anchorLink.setAttribute("role", "tab"); 1078 anchorLink.onclick = anchorClick; 1079 1080 if (i === targetElement.step - 1) { 1081 anchorLink.className = "active"; 1082 } 1083 1084 setAnchorAsButton(anchorLink); 1085 anchorLink.innerHTML = " "; 1086 anchorLink.setAttribute("data-stepnumber", step); 1087 innerLi.appendChild(anchorLink); 1088 ulContainer.appendChild(innerLi); 1089 }); 1090 bulletsLayer.appendChild(ulContainer); 1091 progressLayer.className = "introjs-progress"; 1092 1093 if (this._options.showProgress === false) { 1094 progressLayer.style.display = "none"; 1095 } 1096 1097 var progressBar = document.createElement("div"); 1098 progressBar.className = "introjs-progressbar"; 1099 progressBar.setAttribute("role", "progress"); 1100 progressBar.setAttribute("aria-valuemin", 0); 1101 progressBar.setAttribute("aria-valuemax", 100); 1102 progressBar.setAttribute("aria-valuenow", _getProgress.call(this)); 1103 progressBar.style.cssText = "width:".concat(_getProgress.call(this), "%;"); 1104 progressLayer.appendChild(progressBar); 1105 buttonsLayer.className = "introjs-tooltipbuttons"; 1106 1107 if (this._options.showButtons === false) { 1108 buttonsLayer.style.display = "none"; 1109 } 1110 1111 tooltipLayer.className = "introjs-tooltip"; 1112 tooltipLayer.appendChild(tooltipTextLayer); 1113 tooltipLayer.appendChild(bulletsLayer); 1114 tooltipLayer.appendChild(progressLayer); //add helper layer number 1115 1116 var helperNumberLayer = document.createElement("span"); 1117 1118 if (this._options.showStepNumbers === true) { 1119 helperNumberLayer.className = "introjs-helperNumberLayer"; 1120 helperNumberLayer.innerHTML = targetElement.step; 1121 referenceLayer.appendChild(helperNumberLayer); 1122 } 1123 1124 tooltipLayer.appendChild(arrowLayer); 1125 referenceLayer.appendChild(tooltipLayer); //next button 1126 1127 nextTooltipButton = document.createElement("a"); 1128 1129 nextTooltipButton.onclick = function () { 1130 if (self._introItems.length - 1 !== self._currentStep) { 1131 nextStep.call(self); 1132 } 1133 }; 1134 1135 setAnchorAsButton(nextTooltipButton); 1136 nextTooltipButton.innerHTML = this._options.nextLabel; //previous button 1137 1138 prevTooltipButton = document.createElement("a"); 1139 1140 prevTooltipButton.onclick = function () { 1141 if (self._currentStep !== 0) { 1142 previousStep.call(self); 1143 } 1144 }; 1145 1146 setAnchorAsButton(prevTooltipButton); 1147 prevTooltipButton.innerHTML = this._options.prevLabel; //skip button 1148 1149 skipTooltipButton = document.createElement("a"); 1150 skipTooltipButton.className = "".concat(this._options.buttonClass, " introjs-skipbutton "); 1151 setAnchorAsButton(skipTooltipButton); 1152 skipTooltipButton.innerHTML = this._options.skipLabel; 1153 1154 skipTooltipButton.onclick = function () { 1155 if (self._introItems.length - 1 === self._currentStep && typeof self._introCompleteCallback === "function") { 1156 self._introCompleteCallback.call(self); 1157 } 1158 1159 if (typeof self._introSkipCallback === "function") { 1160 self._introSkipCallback.call(self); 1161 } 1162 1163 exitIntro.call(self, self._targetElement); 1164 }; 1165 1166 buttonsLayer.appendChild(skipTooltipButton); //in order to prevent displaying next/previous button always 1167 1168 if (this._introItems.length > 1) { 1169 buttonsLayer.appendChild(prevTooltipButton); 1170 buttonsLayer.appendChild(nextTooltipButton); 1171 } 1172 1173 tooltipLayer.appendChild(buttonsLayer); //set proper position 1174 1175 placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer); // change the scroll of the window, if needed 1176 1177 scrollTo.call(this, targetElement.scrollTo, targetElement, tooltipLayer); //end of new element if-else condition 1178 } // removing previous disable interaction layer 1179 1180 1181 var disableInteractionLayer = self._targetElement.querySelector(".introjs-disableInteraction"); 1182 1183 if (disableInteractionLayer) { 1184 disableInteractionLayer.parentNode.removeChild(disableInteractionLayer); 1185 } //disable interaction 1186 1187 1188 if (targetElement.disableInteraction) { 1189 _disableInteraction.call(self); 1190 } // when it's the first step of tour 1191 1192 1193 if (this._currentStep === 0 && this._introItems.length > 1) { 1194 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { 1195 skipTooltipButton.className = "".concat(this._options.buttonClass, " introjs-skipbutton"); 1196 } 1197 1198 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1199 nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton"); 1200 } 1201 1202 if (this._options.hidePrev === true) { 1203 if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { 1204 prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton introjs-hidden"); 1205 } 1206 1207 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1208 addClass(nextTooltipButton, "introjs-fullbutton"); 1209 } 1210 } else { 1211 if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { 1212 prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton introjs-disabled"); 1213 } 1214 } 1215 1216 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { 1217 skipTooltipButton.innerHTML = this._options.skipLabel; 1218 } 1219 } else if (this._introItems.length - 1 === this._currentStep || this._introItems.length === 1) { 1220 // last step of tour 1221 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { 1222 skipTooltipButton.innerHTML = this._options.doneLabel; // adding donebutton class in addition to skipbutton 1223 1224 addClass(skipTooltipButton, "introjs-donebutton"); 1225 } 1226 1227 if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { 1228 prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton"); 1229 } 1230 1231 if (this._options.hideNext === true) { 1232 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1233 nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton introjs-hidden"); 1234 } 1235 1236 if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { 1237 addClass(prevTooltipButton, "introjs-fullbutton"); 1238 } 1239 } else { 1240 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1241 nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton introjs-disabled"); 1242 } 1243 } 1244 } else { 1245 // steps between start and end 1246 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { 1247 skipTooltipButton.className = "".concat(this._options.buttonClass, " introjs-skipbutton"); 1248 } 1249 1250 if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { 1251 prevTooltipButton.className = "".concat(this._options.buttonClass, " introjs-prevbutton"); 1252 } 1253 1254 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1255 nextTooltipButton.className = "".concat(this._options.buttonClass, " introjs-nextbutton"); 1256 } 1257 1258 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { 1259 skipTooltipButton.innerHTML = this._options.skipLabel; 1260 } 1261 } 1262 1263 if (typeof prevTooltipButton !== "undefined" && prevTooltipButton !== null) { 1264 prevTooltipButton.setAttribute("role", "button"); 1265 } 1266 1267 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1268 nextTooltipButton.setAttribute("role", "button"); 1269 } 1270 1271 if (typeof skipTooltipButton !== "undefined" && skipTooltipButton !== null) { 1272 skipTooltipButton.setAttribute("role", "button"); 1273 } //Set focus on "next" button, so that hitting Enter always moves you onto the next step 1274 1275 1276 if (typeof nextTooltipButton !== "undefined" && nextTooltipButton !== null) { 1277 nextTooltipButton.focus(); 1278 } 1279 1280 setShowElement(targetElement); 1281 1282 if (typeof this._introAfterChangeCallback !== "undefined") { 1283 this._introAfterChangeCallback.call(this, targetElement.element); 1284 } 1285 } 1286 1287 /** 1288 * Go to specific step of introduction 1289 * 1290 * @api private 1291 * @method _goToStep 1292 */ 1293 1294 function goToStep(step) { 1295 //because steps starts with zero 1296 this._currentStep = step - 2; 1297 1298 if (typeof this._introItems !== "undefined") { 1299 nextStep.call(this); 1300 } 1301 } 1302 /** 1303 * Go to the specific step of introduction with the explicit [data-step] number 1304 * 1305 * @api private 1306 * @method _goToStepNumber 1307 */ 1308 1309 function goToStepNumber(step) { 1310 this._currentStepNumber = step; 1311 1312 if (typeof this._introItems !== "undefined") { 1313 nextStep.call(this); 1314 } 1315 } 1316 /**
1317 * Go to next step on intro 1318 * 1319 * @api private 1320 * @method _nextStep 1321 */ 1322 1323 function nextStep() { 1324 var _this = this; 1325 1326 this._direction = "forward"; 1327 1328 if (typeof this._currentStepNumber !== "undefined") { 1329 forEach(this._introItems, function (_ref, i) { 1330 var step = _ref.step; 1331 1332 if (step === _this._currentStepNumber) { 1333 _this._currentStep = i - 1; 1334 _this._currentStepNumber = undefined; 1335 } 1336 }); 1337 } 1338 1339 if (typeof this._currentStep === "undefined") { 1340 this._currentStep = 0; 1341 } else { 1342 ++this._currentStep; 1343 } 1344 1345 var nextStep = this._introItems[this._currentStep]; 1346 var continueStep = true; 1347 1348 if (typeof this._introBeforeChangeCallback !== "undefined") { 1349 continueStep = this._introBeforeChangeCallback.call(this, nextStep.element); 1350 } // if `onbeforechange` returned `false`, stop displaying the element 1351 1352 1353 if (continueStep === false) { 1354 --this._currentStep; 1355 return false; 1356 } 1357 1358 if (this._introItems.length <= this._currentStep) { 1359 //end of the intro 1360 //check if any callback is defined 1361 if (typeof this._introCompleteCallback === "function") { 1362 this._introCompleteCallback.call(this); 1363 } 1364 1365 exitIntro.call(this, this._targetElement); 1366 return; 1367 } 1368 1369 _showElement.call(this, nextStep); 1370 } 1371 /** 1372 * Go to previous step on intro 1373 * 1374 * @api private 1375 * @method _previousStep 1376 */ 1377 1378 function previousStep() { 1379 this._direction = "backward"; 1380 1381 if (this._currentStep === 0) { 1382 return false; 1383 } 1384 1385 --this._currentStep; 1386 var nextStep = this._introItems[this._currentStep]; 1387 var continueStep = true; 1388 1389 if (typeof this._introBeforeChangeCallback !== "undefined") { 1390 continueStep = this._introBeforeChangeCallback.call(this, nextStep.element); 1391 } // if `onbeforechange` returned `false`, stop displaying the element 1392 1393 1394 if (continueStep === false) { 1395 ++this._currentStep; 1396 return false; 1397 } 1398 1399 _showElement.call(this, nextStep); 1400 } 1401 /** 1402 * Returns the current step of the intro 1403 * 1404 * @returns {boolean} 1405 */ 1406 1407 function currentStep() { 1408 return this._currentStep; 1409 } 1410 1411 /** 1412 * on keyCode: 1413 * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode 1414 * This feature has been removed from the Web standards. 1415 * Though some browsers may still support it, it is in 1416 * the process of being dropped. 1417 * Instead, you should use KeyboardEvent.code, 1418 * if it's implemented. 1419 * 1420 * jQuery's approach is to test for 1421 * (1) e.which, then 1422 * (2) e.charCode, then 1423 * (3) e.keyCode 1424 * https://github.com/jquery/jquery/blob/a6b0705294d336ae2f63f7276de0da1195495363/src/event.js#L638 1425 * 1426 * @param type var 1427 * @return type 1428 */ 1429 1430 function onKeyDown(e) {
1431 var code = e.code === null ? e.which : e.code; // if code/e.which is null 1432 1433 if (code === null) { 1434 code = e.charCode === null ? e.keyCode : e.charCode; 1435 } 1436 1437 if ((code === "Escape" || code === 27) && this._options.exitOnEsc === true) { 1438 //escape key pressed, exit the intro 1439 //check if exit callback is defined 1440 exitIntro.call(this, this._targetElement); 1441 } else if (code === "ArrowLeft" || code === 37) { 1442 //left arrow 1443 previousStep.call(this); 1444 } else if (code === "ArrowRight" || code === 39) { 1445 //right arrow 1446 nextStep.call(this); 1447 } else if (code === "Enter" || code === 13) { 1448 //srcElement === ie 1449 var target = e.target || e.srcElement; 1450 1451 if (target && target.className.match("introjs-prevbutton")) { 1452 //user hit enter while focusing on previous button 1453 previousStep.call(this); 1454 } else if (target && target.className.match("introjs-skipbutton")) { 1455 //user hit enter while focusing on skip button 1456 if (this._introItems.length - 1 === this._currentStep && typeof this._introCompleteCallback === "function") { 1457 this._introCompleteCallback.call(this); 1458 } 1459 1460 exitIntro.call(this, this._targetElement); 1461 } else if (target && target.getAttribute("data-stepnumber")) { 1462 // user hit enter while focusing on step bullet 1463 target.click(); 1464 } else { 1465 //default behavior for responding to enter 1466 nextStep.call(this); 1467 } //prevent default behaviour on hitting Enter, to prevent steps being skipped in some browsers 1468 1469 1470 if (e.preventDefault) { 1471 e.preventDefault(); 1472 } else { 1473 e.returnValue = false; 1474 } 1475 } 1476 } 1477 1478 /* 1479 * makes a copy of the object 1480 * @api private 1481 * @method _cloneObject 1482 */ 1483 function cloneObject(object) { 1484 if (object === null || _typeof(object) !== "object" || typeof object.nodeType !== "undefined") { 1485 return object; 1486 } 1487 1488 var temp = {}; 1489 1490 for (var key in object) { 1491 if (typeof window.jQuery !== "undefined" && object[key] instanceof window.jQuery) { 1492 temp[key] = object[key]; 1493 } else { 1494 temp[key] = cloneObject(object[key]); 1495 } 1496 } 1497 1498 return temp; 1499 } 1500 1501 /** 1502 * Get a queryselector within the hint wrapper 1503 * 1504 * @param {String} selector 1505 * @return {NodeList|Array} 1506 */ 1507 1508 function hintQuerySelectorAll(selector) { 1509 var hintsWrapper = document.querySelector(".introjs-hints"); 1510 return hintsWrapper ? hintsWrapper.querySelectorAll(selector) : []; 1511 } 1512 /** 1513 * Hide a hint 1514 * 1515 * @api private 1516 * @method hideHint 1517 */ 1518 1519 function hideHint(stepId) { 1520 var hint = hintQuerySelectorAll(".introjs-hint[data-step=\"".concat(stepId, "\"]"))[0]; 1521 removeHintTooltip.call(this); 1522 1523 if (hint) { 1524 addClass(hint, "introjs-hidehint"); 1525 } // call the callback function (if any) 1526 1527 1528 if (typeof this._hintCloseCallback !== "undefined") { 1529 this._hintCloseCallback.call(this, stepId); 1530 } 1531 } 1532 /** 1533 * Hide all hints 1534 * 1535 * @api private 1536 * @method hideHints 1537 */ 1538 1539 function hideHints() { 1540 var _this = this; 1541 1542 var hints = hintQuerySelectorAll(".introjs-hint"); 1543 forEach(hints, function (hint) { 1544 hideHint.call(_this, hint.getAttribute("data-step")); 1545 }); 1546 } 1547 /** 1548 * Show all hints 1549 * 1550 * @api private 1551 * @method _showHints 1552 */ 1553 1554 function showHints() { 1555 var _this2 = this; 1556 1557 var hints = hintQuerySelectorAll(".introjs-hint"); 1558 1559 if (hints && hints.length) {
1560 forEach(hints, function (hint) { 1561 showHint.call(_this2, hint.getAttribute("data-step")); 1562 }); 1563 } else { 1564 populateHints.call(this, this._targetElement); 1565 } 1566 } 1567 /** 1568 * Show a hint 1569 * 1570 * @api private 1571 * @method showHint 1572 */ 1573 1574 function showHint(stepId) { 1575 var hint = hintQuerySelectorAll(".introjs-hint[data-step=\"".concat(stepId, "\"]"))[0]; 1576 1577 if (hint) { 1578 removeClass(hint, /introjs-hidehint/g); 1579 } 1580 } 1581 /** 1582 * Removes all hint elements on the page 1583 * Useful when you want to destroy the elements and add them again (e.g. a modal or popup) 1584 * 1585 * @api private 1586 * @method removeHints 1587 */ 1588 1589 function removeHints() { 1590 var _this3 = this; 1591 1592 var hints = hintQuerySelectorAll(".introjs-hint"); 1593 forEach(hints, function (hint) { 1594 removeHint.call(_this3, hint.getAttribute("data-step")); 1595 }); 1596 } 1597 /** 1598 * Remove one single hint element from the page 1599 * Useful when you want to destroy the element and add them again (e.g. a modal or popup) 1600 * Use removeHints if you want to remove all elements. 1601 * 1602 * @api private 1603 * @method removeHint 1604 */ 1605 1606 function removeHint(stepId) { 1607 var hint = hintQuerySelectorAll(".introjs-hint[data-step=\"".concat(stepId, "\"]"))[0]; 1608 1609 if (hint) { 1610 hint.parentNode.removeChild(hint); 1611 } 1612 } 1613 /** 1614 * Add all available hints to the page 1615 * 1616 * @api private 1617 * @method addHints 1618 */ 1619 1620 function addHints() { 1621 var _this4 = this; 1622 1623 var self = this; 1624 var hintsWrapper = document.querySelector(".introjs-hints"); 1625 1626 if (hintsWrapper === null) { 1627 hintsWrapper = document.createElement("div"); 1628 hintsWrapper.className = "introjs-hints"; 1629 } 1630 /** 1631 * Returns an event handler unique to the hint iteration 1632 * 1633 * @param {Integer} i 1634 * @return {Function} 1635 */ 1636 1637 1638 var getHintClick = function getHintClick(i) { 1639 return function (e) { 1640 var evt = e ? e : window.event; 1641 1642 if (evt.stopPropagation) { 1643 evt.stopPropagation(); 1644 } 1645 1646 if (evt.cancelBubble !== null) { 1647 evt.cancelBubble = true; 1648 } 1649 1650 showHintDialog.call(self, i); 1651 }; 1652 }; 1653 1654 forEach(this._introItems, function (item, i) { 1655 // avoid append a hint twice 1656 if (document.querySelector(".introjs-hint[data-step=\"".concat(i, "\"]"))) { 1657 return; 1658 } 1659 1660 var hint = document.createElement("a"); 1661 setAnchorAsButton(hint); 1662 hint.onclick = getHintClick(i); 1663 hint.className = "introjs-hint"; 1664 1665 if (!item.hintAnimation) { 1666 addClass(hint, "introjs-hint-no-anim"); 1667 } // hint's position should be fixed if the target element's position is fixed 1668 1669 1670 if (isFixed(item.element)) { 1671 addClass(hint, "introjs-fixedhint"); 1672 } 1673 1674 var hintDot = document.createElement("div"); 1675 hintDot.className = "introjs-hint-dot"; 1676 var hintPulse = document.createElement("div"); 1677 hintPulse.className = "introjs-hint-pulse"; 1678 hint.appendChild(hintDot); 1679 hint.appendChild(hintPulse); 1680 hint.setAttribute("data-step", i); // we swap the hint element with target element 1681 // because _setHelperLayerPosition uses `element` property 1682 1683 item.targetElement = item.element; 1684 item.element = hint; // align the hint position 1685 1686 alignHintPosition.call(_this4, item.hintPosition, hint, item.targetElement); 1687 hintsWrapper.appendChild(hint); 1688 }); // adding the hints wrapper 1689 1690 document.body.appendChild(hintsWrapper); // call the callback function (if any) 1691 1692 if (typeof this._hintsAddedCallback !== "undefined") { 1693 this._hintsAddedCallback.call(this); 1694 } 1695 } 1696 /** 1697 * Aligns hint position 1698 * 1699 * @api private 1700 * @method alignHintPosition 1701 * @param {String} position 1702 * @param {Object} hint 1703 * @param {Object} element 1704 */ 1705 1706 function alignHintPosition(position, _ref, element) { 1707 var style = _ref.style; 1708 // get/calculate offset of target element 1709 var offset = getOffset.call(this, element); 1710 var iconWidth = 20; 1711 var iconHeight = 20; // align the hint element 1712 1713 switch (position) { 1714 default: 1715 case "top-left": 1716 style.left = "".concat(offset.left, "px"); 1717 style.top = "".concat(offset.top, "px"); 1718 break; 1719 1720 case "top-right": 1721 style.left = "".concat(offset.left + offset.width - iconWidth, "px"); 1722 style.top = "".concat(offset.top, "px"); 1723 break; 1724 1725 case "bottom-left": 1726 style.left = "".concat(offset.left, "px"); 1727 style.top = "".concat(offset.top + offset.height - iconHeight, "px"); 1728 break; 1729 1730 case "bottom-right": 1731 style.left = "".concat(offset.left + offset.width - iconWidth, "px"); 1732 style.top = "".concat(offset.top + offset.height - iconHeight, "px"); 1733 break; 1734 1735 case "middle-left": 1736 style.left = "".concat(offset.left, "px"); 1737 style.top = "".concat(offset.top + (offset.height - iconHeight) / 2, "px"); 1738 break; 1739 1740 case "middle-right": 1741 style.left = "".concat(offset.left + offset.width - iconWidth, "px"); 1742 style.top = "".concat(offset.top + (offset.height - iconHeight) / 2, "px"); 1743 break; 1744 1745 case "middle-middle": 1746 style.left = "".concat(offset.left + (offset.width - iconWidth) / 2, "px"); 1747 style.top = "".concat(offset.top + (offset.height - iconHeight) / 2, "px"); 1748 break; 1749 1750 case "bottom-middle": 1751 style.left = "".concat(offset.left + (offset.width - iconWidth) / 2, "px"); 1752 style.top = "".concat(offset.top + offset.height - iconHeight, "px"); 1753 break; 1754 1755 case "top-middle": 1756 style.left = "".concat(offset.left + (offset.width - iconWidth) / 2, "px"); 1757 style.top = "".concat(offset.top, "px"); 1758 break; 1759 } 1760 } 1761 /** 1762 * Triggers when user clicks on the hint element 1763 * 1764 * @api private 1765 * @method _showHintDialog 1766 * @param {Number} stepId 1767 */ 1768 1769 function showHintDialog(stepId) { 1770 var hintElement = document.querySelector(".introjs-hint[data-step=\"".concat(stepId, "\"]")); 1771 var item = this._introItems[stepId]; // call the callback function (if any) 1772 1773 if (typeof this._hintClickCallback !== "undefined") { 1774 this._hintClickCallback.call(this, hintElement, item, stepId
1774); 1775 } // remove all open tooltips 1776 1777 1778 var removedStep = removeHintTooltip.call(this); // to toggle the tooltip 1779 1780 if (parseInt(removedStep, 10) === stepId) { 1781 return; 1782 } 1783 1784 var tooltipLayer = document.createElement("div"); 1785 var tooltipTextLayer = document.createElement("div"); 1786 var arrowLayer = document.createElement("div"); 1787 var referenceLayer = document.createElement("div"); 1788 tooltipLayer.className = "introjs-tooltip"; 1789 1790 tooltipLayer.onclick = function (e) { 1791 //IE9 & Other Browsers 1792 if (e.stopPropagation) { 1793 e.stopPropagation(); 1794 } //IE8 and Lower 1795 else { 1796 e.cancelBubble = true; 1797 } 1798 }; 1799 1800 tooltipTextLayer.className = "introjs-tooltiptext"; 1801 var tooltipWrapper = document.createElement("p"); 1802 tooltipWrapper.innerHTML = item.hint; 1803 var closeButton = document.createElement("a"); 1804 closeButton.className = this._options.buttonClass; 1805 closeButton.setAttribute("role", "button"); 1806 closeButton.innerHTML = this._options.hintButtonLabel; 1807 closeButton.onclick = hideHint.bind(this, stepId); 1808 tooltipTextLayer.appendChild(tooltipWrapper); 1809 tooltipTextLayer.appendChild(closeButton); 1810 arrowLayer.className = "introjs-arrow"; 1811 tooltipLayer.appendChild(arrowLayer); 1812 tooltipLayer.appendChild(tooltipTextLayer); // set current step for _placeTooltip function 1813 1814 this._currentStep = hintElement.getAttribute("data-step"); // align reference layer position 1815 1816 referenceLayer.className = "introjs-tooltipReferenceLayer introjs-hintReference"; 1817 referenceLayer.setAttribute("data-step", hintElement.getAttribute("data-step")); 1818 setHelperLayerPosition.call(this, referenceLayer); 1819 referenceLayer.appendChild(tooltipLayer); 1820 document.body.appendChild(referenceLayer); //set proper position 1821 1822 placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer, null, true); 1823 } 1824 /** 1825 * Removes open hint (tooltip hint) 1826 * 1827 * @api private 1828 * @method _removeHintTooltip 1829 */ 1830 1831 function removeHintTooltip() { 1832 var tooltip = document.querySelector(".introjs-hintReference"); 1833 1834 if (tooltip) { 1835 var step = tooltip.getAttribute("data-step"); 1836 tooltip.parentNode.removeChild(tooltip); 1837 return step; 1838 } 1839 } 1840 /** 1841 * Start parsing hint items 1842 * 1843 * @api private 1844 * @param {Object} targetElm 1845 * @method _startHint 1846 */ 1847 1848 function populateHints(targetElm) { 1849 var _this5 = this; 1850 1851 this._introItems = []; 1852 1853 if (this._options.hints) { 1854 forEach(this._options.hints, function (hint) { 1855 var currentItem = cloneObject(hint); 1856 1857 if (typeof currentItem.element === "string") { 1858 //grab the element with given selector from the page 1859 currentItem.element = document.querySelector(currentItem.element); 1860 } 1861 1862 currentItem.hintPosition = currentItem.hintPosition || _this5._options.hintPosition; 1863 currentItem.hintAnimation = currentItem.hintAnimation || _this5._options.hintAnimation; 1864 1865 if (currentItem.element !== null) { 1866 _this5._introItems.push(currentItem); 1867 } 1868 }); 1869 } else { 1870 var hints = targetElm.querySelectorAll("*[data-hint]"); 1871 1872 if (!hints || !hints.length) { 1873 return false; 1874 } //first add intro items with data-step 1875 1876 1877 forEach(hints, function (currentElement) { 1878 // hint animation 1879 var hintAnimation = currentElement.getAttribute("data-hintanimation"); 1880 1881 if (hintAnimation) { 1882 hintAnimation = hintAnimation === "true"; 1883 } else { 1884 hintAnimation = _this5._options.hintAnimation; 1885 } 1886 1887 _this5._introItems.push({ 1888 element: currentElement, 1889 hint: currentElement.getAttribute("data-hint"), 1890 hintPosition: currentElement.getAttribute("data-hintposition") || _this5._options.hintPosition, 1891 hintAnimation: hintAnimation, 1892 tooltipClass: currentElement.getAttribute("data-tooltipclass"), 1893 position: currentElement.getAttribute("data-position") || _this5._options.tooltipPosition 1894 }); 1895 }); 1896 } 1897 1898 addHints.call(this); 1899 /* 1900 todo: 1901 these events should be removed at some point 1902 */ 1903 1904 DOMEvent.on(document, "click", removeHintTooltip, this, false); 1905 DOMEvent.on(window, "resize", reAlignHints, this, true); 1906 } 1907 /** 1908 * Re-aligns all hint elements 1909 * 1910 * @api private 1911 * @method _reAlignHints 1912 */ 1913 1914 function reAlignHints() { 1915 var _this6 = this; 1916
1917 forEach(this._introItems, function (_ref2) { 1918 var targetElement = _ref2.targetElement, 1919 hintPosition = _ref2.hintPosition, 1920 element = _ref2.element; 1921 1922 if (typeof targetElement === "undefined") { 1923 return; 1924 } 1925 1926 alignHintPosition.call(_this6, hintPosition, element, targetElement); 1927 }); 1928 } 1929 1930 /** 1931 * Update placement of the intro objects on the screen 1932 * @api private 1933 */ 1934 1935 function refresh() { 1936 // re-align intros 1937 setHelperLayerPosition.call(this, document.querySelector(".introjs-helperLayer")); 1938 setHelperLayerPosition.call(this, document.querySelector(".introjs-tooltipReferenceLayer")); 1939 setHelperLayerPosition.call(this, document.querySelector(".introjs-disableInteraction")); // re-align tooltip 1940 1941 if (this._currentStep !== undefined && this._currentStep !== null) { 1942 var oldHelperNumberLayer = document.querySelector(".introjs-helperNumberLayer"); 1943 var oldArrowLayer = document.querySelector(".introjs-arrow"); 1944 var oldtooltipContainer = document.querySelector(".introjs-tooltip"); 1945 placeTooltip.call(this, this._introItems[this._currentStep].element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer); 1946 } //re-align hints 1947 1948 1949 reAlignHints.call(this); 1950 return this; 1951 } 1952 1953 function onResize() { 1954 refresh.call(this); 1955 } 1956 1957 /** 1958 * Exit from intro 1959 * 1960 * @api private 1961 * @method _exitIntro 1962 * @param {Object} targetElement 1963 * @param {Boolean} force - Setting to `true` will skip the result of beforeExit callback 1964 */ 1965 1966 function exitIntro(targetElement, force) { 1967 var continueExit = true; // calling onbeforeexit callback 1968 // 1969 // If this callback return `false`, it would halt the process 1970 1971 if (this._introBeforeExitCallback !== undefined) { 1972 continueExit = this._introBeforeExitCallback.call(this); 1973 } // skip this check if `force` parameter is `true` 1974 // otherwise, if `onbeforeexit` returned `false`, don't exit the intro 1975 1976 1977 if (!force && continueExit === false) return; //remove overlay layers from the page 1978 1979 var overlayLayers = targetElement.querySelectorAll(".introjs-overlay"); 1980 1981 if (overlayLayers && overlayLayers.length) { 1982 forEach(overlayLayers, function (overlayLayer) { 1983 overlayLayer.style.opacity = 0; 1984 window.setTimeout(function () { 1985 if (this.parentNode) { 1986 this.parentNode.removeChild(this); 1987 } 1988 }.bind(overlayLayer), 500); 1989 }); 1990 } //remove all helper layers 1991 1992 1993 var helperLayer = targetElement.querySelector(".introjs-helperLayer"); 1994 1995 if (helperLayer) { 1996 helperLayer.parentNode.removeChild(helperLayer); 1997 } 1998 1999 var referenceLayer = targetElement.querySelector(".introjs-tooltipReferenceLayer"); 2000 2001 if (referenceLayer) { 2002 referenceLayer.parentNode.removeChild(referenceLayer); 2003 } //remove disableInteractionLayer 2004 2005 2006 var disableInteractionLayer = targetElement.querySelector(".introjs-disableInteraction"); 2007 2008 if (disableInteractionLayer) { 2009 disableInteractionLayer.parentNode.removeChild(disableInteractionLayer); 2010 } //remove intro floating element 2011 2012 2013 var floatingElement = document.querySelector(".introjsFloatingElement"); 2014 2015 if (floatingElement) { 2016 floatingElement.parentNode.removeChild(floatingElement); 2017 } 2018 2019 removeShowElement(); //remove `introjs-fixParent` class from the elements 2020 2021 var fixParents = document.querySelectorAll(".introjs-fixParent"); 2022 forEach(fixParents, function (parent) { 2023 removeClass(parent, /introjs-fixParent/g); 2024 }); //clean listeners 2025 2026 DOMEvent.off(window, "keydown", onKeyDown, this, true); 2027 DOMEvent.off(window, "resize", onResize, this, true); //check if any callback is defined 2028 2029 if (this._introExitCallback !== undefined) { 2030 this._introExitCallback.call(this); 2031 } //set the step to zero 2032 2033 2034 this._currentStep = undefined; 2035 } 2036 2037 /** 2038 * Add overlay layer to the page 2039 * 2040 * @api private 2041 * @method _addOverlayLayer 2042 * @param {Object} targetElm 2043 */ 2044 2045 function addOverlayLayer(targetElm) { 2046 var overlayLayer = document.createElement("div"); 2047 var styleText = ""; 2048 var self = this; //set css class name 2049 2050 overlayLayer.className = "introjs-overlay"; //check if the target element is body, we should calculate the size of overlay layer in a better way 2051 2052 if (!targetElm.tagName || targetElm.tagName.toLowerCase() === "body") { 2053 styleText += "top: 0;bottom: 0; left: 0;right: 0;position: fixed;"; 2054 overlayLayer.style.cssText = styleText; 2055 } else { 2056 //set overlay layer position 2057 var elementPosition = getOffset(targetElm); 2058 2059 if (elementPosition) { 2060 styleText += "width: ".concat(elementPosition.width, "px; height:").concat(elementPosition.height, "px; top:").concat(elementPosition.top, "px;left: ").concat(elementPosition.left, "px;"); 2061 overlayLayer.style.cssText = styleText; 2062 } 2063 } 2064 2065 targetElm.appendChild(overlayLayer); 2066 2067 overlayLayer.onclick = function () { 2068 if (self._options.exitOnOverlayClick === true) { 2069 exitIntro.call(self, targetElm); 2070 } 2071 }; 2072 2073 window.setTimeout(function () { 2074 styleText += "opacity: ".concat(self._options.overlayOpacity.toString(), ";"); 2075 overlayLayer.style.cssText = styleText; 2076 }, 10); 2077 return true; 2078 } 2079 2080 /** 2081 * Initiate a new introduction/guide from an element in the page 2082 * 2083 * @api private 2084 * @method _introForElement 2085 * @param {Object} targetElm 2086 * @param {String} group 2087 * @returns {Boolean} Success or not? 2088 */ 2089 2090 function introForElement(targetElm, group) { 2091 var _this = this; 2092 2093 var allIntroSteps = targetElm.querySelectorAll("*[data-intro]"); 2094 var introItems = []; 2095 2096 if (this._options.steps) { 2097 //use steps passed programmatically
2098 forEach(this._options.steps, function (step) { 2099 var currentItem = cloneObject(step); //set the step 2100 2101 currentItem.step = introItems.length + 1; //use querySelector function only when developer used CSS selector 2102 2103 if (typeof currentItem.element === "string") { 2104 //grab the element with given selector from the page 2105 currentItem.element = document.querySelector(currentItem.element); 2106 } //intro without element 2107 2108 2109 if (typeof currentItem.element === "undefined" || currentItem.element === null) { 2110 var floatingElementQuery = document.querySelector(".introjsFloatingElement"); 2111 2112 if (floatingElementQuery === null) { 2113 floatingElementQuery = document.createElement("div"); 2114 floatingElementQuery.className = "introjsFloatingElement"; 2115 document.body.appendChild(floatingElementQuery); 2116 } 2117 2118 currentItem.element = floatingElementQuery; 2119 currentItem.position = "floating"; 2120 } 2121 2122 currentItem.scrollTo = currentItem.scrollTo || _this._options.scrollTo; 2123 2124 if (typeof currentItem.disableInteraction === "undefined") { 2125 currentItem.disableInteraction = _this._options.disableInteraction; 2126 } 2127 2128 if (currentItem.element !== null) { 2129 introItems.push(currentItem); 2130 } 2131 }); 2132 } else { 2133 //use steps from data-* annotations 2134 var elmsLength = allIntroSteps.length; 2135 var disableInteraction; //if there's no element to intro 2136 2137 if (elmsLength < 1) { 2138 return false; 2139 } 2140 2141 forEach(allIntroSteps, function (currentElement) { 2142 // PR #80 2143 // start intro for groups of elements 2144 if (group && currentElement.getAttribute("data-intro-group") !== group) { 2145 return; 2146 } // skip hidden elements 2147 2148 2149 if (currentElement.style.display === "none") { 2150 return; 2151 } 2152 2153 var step = parseInt(currentElement.getAttribute("data-step"), 10); 2154 2155 if (typeof currentElement.getAttribute("data-disable-interaction") !== "undefined") { 2156 disableInteraction = !!currentElement.getAttribute("data-disable-interaction"); 2157 } else { 2158 disableInteraction = _this._options.disableInteraction; 2159 } 2160 2161 if (step > 0) { 2162 introItems[step - 1] = { 2163 element: currentElement, 2164 intro: currentElement.getAttribute("data-intro"), 2165 step: parseInt(currentElement.getAttribute("data-step"), 10), 2166 tooltipClass: currentElement.getAttribute("data-tooltipclass"), 2167 highlightClass: currentElement.getAttribute("data-highlightclass"), 2168 position: currentElement.getAttribute("data-position") || _this._options.tooltipPosition, 2169 scrollTo: currentElement.getAttribute("data-scrollto") || _this._options.scrollTo, 2170 disableInteraction: disableInteraction 2171 }; 2172 } 2173 }); //next add intro items without data-step 2174 //todo: we need a cleanup here, two loops are redundant 2175 2176 var _nextStep = 0; 2177 forEach(allIntroSteps, function (currentElement) { 2178 // PR #80 2179 // start intro for groups of elements 2180 if (group && currentElement.getAttribute("data-intro-group") !== group) { 2181 return; 2182 } 2183 2184 if (currentElement.getAttribute("data-step") === null) { 2185 while (true) { 2186 if (typeof introItems[_nextStep] === "undefined") { 2187 break; 2188 } else { 2189 _nextStep++; 2190 } 2191 } 2192 2193 if (typeof currentElement.getAttribute("data-disable-interaction") !== "undefined") { 2194 disableInteraction = !!currentElement.getAttribute("data-disable-interaction"); 2195 } else { 2196 disableInteraction = _this._options.disableInteraction; 2197 } 2198 2199 introItems[_nextStep] = { 2200 element: currentElement, 2201 intro: currentElement.getAttribute("data-intro"), 2202 step: _nextStep + 1, 2203 tooltipClass: currentElement.getAttribute("data-tooltipclass"), 2204 highlightClass: currentElement.getAttribute("data-highlightclass"), 2205 position: currentElement.getAttribute("data-position") || _this._options.tooltipPosition, 2206 scrollTo: currentElement.getAttribute("data-scrollto") || _this._options.scrollTo, 2207 disableInteraction: disableInteraction 2208 }; 2209 } 2210 }); 2211 } //removing undefined/null elements 2212 2213 2214 var tempIntroItems = []; 2215 2216 for (var z = 0; z < introItems.length; z++) { 2217 if (introItems[z]) { 2218 // copy non-falsy values to the end of the array 2219 tempIntroItems.push(introItems[z]); 2220 } 2221 } 2222 2223 introItems = tempIntroItems; //Ok, sort all items with given steps 2224 2225 introItems.sort(function (a, b) { 2226 return a.step - b.step; 2227 }); //set it to the introJs object 2228 2229 this._introItems = introItems; //add overlay layer to the page 2230 2231 if (addOverlayLayer.call(this, targetElm)) { 2232 //then, start the show 2233 nextStep.call(this); 2234 2235 if (this._options.keyboardNavigation) { 2236 DOMEvent.on(window, "keydown", onKeyDown, this, true); 2237 } //for window resize 2238 2239 2240 DOMEvent.on(window, "resize", onResize, this, true); 2241 } 2242 2243 return false; 2244 } 2245 2246 var version = "3.0.1"; 2247 2248 /** 2249 * IntroJs main class 2250 * 2251 * @class IntroJs 2252 */ 2253 2254 function IntroJs(obj) { 2255 this._targetElement = obj; 2256 this._introItems = []; 2257 this._options = { 2258 /* Next button label in tooltip box */ 2259 nextLabel: "Next →", 2260 2261 /* Previous button label in tooltip box */ 2262 prevLabel: "← Back", 2263 2264 /* Skip button label in tooltip box */ 2265 skipLabel: "Skip", 2266 2267 /* Done button label in tooltip box */ 2268 doneLabel: "Done", 2269 2270 /* Hide previous button in the first step? Otherwise, it will be disabled button. */ 2271 hidePrev: false, 2272 2273 /* Hide next button in the last step? Otherwise, it will be disabled button. */ 2274 hideNext: false, 2275 2276 /* Default tooltip box position */ 2277 tooltipPosition: "bottom", 2278 2279 /* Next CSS class for tooltip boxes */ 2280 tooltipClass: "", 2281 2282 /* CSS class that is added to the helperLayer */ 2283 highlightClass: "", 2284 2285 /* Close introduction when pressing Escape button? */ 2286 exitOnEsc: true, 2287 2288 /* Close introduction when clicking on overlay layer? */ 2289 exitOnOverlayClick: true, 2290 2291 /* Show step numbers in introduction? */ 2292 showStepNumbers: true, 2293 2294 /* Let user use keyboard to navigate the tour? */ 2295 keyboardNavigation: true, 2296
2297 /* Show tour control buttons? */ 2298 showButtons: true, 2299 2300 /* Show tour bullets? */ 2301 showBullets: true, 2302 2303 /* Show tour progress? */ 2304 showProgress: false, 2305 2306 /* Scroll to highlighted element? */ 2307 scrollToElement: true, 2308 2309 /* 2310 * Should we scroll the tooltip or target element? 2311 * 2312 * Options are: 'element' or 'tooltip' 2313 */ 2314 scrollTo: "element", 2315 2316 /* Padding to add after scrolling when element is not in the viewport (in pixels) */ 2317 scrollPadding: 30, 2318 2319 /* Set the overlay opacity */ 2320 overlayOpacity: 0.8, 2321 2322 /* Precedence of positions, when auto is enabled */ 2323 positionPrecedence: ["bottom", "top", "right", "left"], 2324 2325 /* Disable an interaction with element? */ 2326 disableInteraction: false, 2327 2328 /* Set how much padding to be used around helper element */ 2329 helperElementPadding: 10, 2330 2331 /* Default hint position */ 2332 hintPosition: "top-middle", 2333 2334 /* Hint button label */ 2335 hintButtonLabel: "Got it", 2336 2337 /* Adding animation to hints? */ 2338 hintAnimation: true, 2339 2340 /* additional classes to put on the buttons */ 2341 buttonClass: "introjs-button" 2342 }; 2343 } 2344 2345 var introJs = function introJs(targetElm) { 2346 var instance; 2347 2348 if (_typeof(targetElm) === "object") { 2349 //Ok, create a new instance 2350 instance = new IntroJs(targetElm); 2351 } else if (typeof targetElm === "string") { 2352 //select the target element with query selector 2353 var targetElement = document.querySelector(targetElm); 2354 2355 if (targetElement) { 2356 instance = new IntroJs(targetElement); 2357 } else { 2358 throw new Error("There is no element with given selector."); 2359 } 2360 } else { 2361 instance = new IntroJs(document.body); 2362 } // add instance to list of _instances 2363 // passing group to stamp to increment 2364 // from 0 onward somewhat reliably 2365 2366 2367 introJs.instances[stamp(instance, "introjs-instance")] = instance; 2368 return instance; 2369 }; 2370 /** 2371 * Current IntroJs version 2372 * 2373 * @property version
2374 * @type String 2375 */ 2376 2377 2378 introJs.version = version; 2379 /** 2380 * key-val object helper for introJs instances 2381 * 2382 * @property instances 2383 * @type Object 2384 */ 2385 2386 introJs.instances = {}; //Prototype 2387 2388 introJs.fn = IntroJs.prototype = { 2389 clone: function clone() { 2390 return new IntroJs(this); 2391 }, 2392 setOption: function setOption(option, value) { 2393 this._options[option] = value; 2394 return this; 2395 }, 2396 setOptions: function setOptions(options) { 2397 this._options = mergeOptions(this._options, options); 2398 return this; 2399 }, 2400 start: function start(group) { 2401 introForElement.call(this, this._targetElement, group); 2402 return this; 2403 }, 2404 goToStep: function goToStep$1(step) { 2405 goToStep.call(this, step); 2406 2407 return this; 2408 }, 2409 addStep: function addStep(options) { 2410 if (!this._options.steps) { 2411 this._options.steps = []; 2412 } 2413 2414 this._options.steps.push(options); 2415 2416 return this; 2417 }, 2418 addSteps: function addSteps(steps) { 2419 if (!steps.length) return; 2420 2421 for (var index = 0; index < steps.length; index++) { 2422 this.addStep(steps[index]); 2423 } 2424 2425 return this; 2426 }, 2427 goToStepNumber: function goToStepNumber$1(step) { 2428 goToStepNumber.call(this, step); 2429 2430 return this; 2431 }, 2432 nextStep: function nextStep$1() { 2433 nextStep.call(this); 2434 2435 return this; 2436 }, 2437 previousStep: function previousStep$1() { 2438 previousStep.call(this); 2439 2440 return this; 2441 }, 2442 currentStep: function currentStep$1() { 2443 return currentStep.call(this); 2444 }, 2445 exit: function exit(force) { 2446 exitIntro.call(this, this._targetElement, force); 2447 return this; 2448 }, 2449 refresh: function refresh$1() { 2450 refresh.call(this); 2451 2452 return this; 2453 }, 2454 onbeforechange: function onbeforechange(providedCallback) { 2455 if (typeof providedCallback === "function") { 2456 this._introBeforeChangeCallback = providedCallback; 2457 } else { 2458 throw new Error("Provided callback for onbeforechange was not a function"); 2459 } 2460 2461 return this; 2462 }, 2463 onchange: function onchange(providedCallback) { 2464 if (typeof providedCallback === "function") { 2465 this._introChangeCallback = providedCallback; 2466 } else { 2467 throw new Error("Provided callback for onchange was not a function."); 2468 } 2469 2470 return this; 2471 }, 2472 onafterchange: function onafterchange(providedCallback) { 2473 if (typeof providedCallback === "function") { 2474 this._introAfterChangeCallback = providedCallback; 2475 } else { 2476 throw new Error("Provided callback for onafterchange was not a function"); 2477 } 2478 2479 return this; 2480 },
2481 oncomplete: function oncomplete(providedCallback) { 2482 if (typeof providedCallback === "function") { 2483 this._introCompleteCallback = providedCallback; 2484 } else { 2485 throw new Error("Provided callback for oncomplete was not a function."); 2486 } 2487 2488 return this; 2489 }, 2490 onhintsadded: function onhintsadded(providedCallback) { 2491 if (typeof providedCallback === "function") { 2492 this._hintsAddedCallback = providedCallback; 2493 } else { 2494 throw new Error("Provided callback for onhintsadded was not a function."); 2495 } 2496 2497 return this; 2498 }, 2499 onhintclick: function onhintclick(providedCallback) { 2500 if (typeof providedCallback === "function") { 2501 this._hintClickCallback = providedCallback; 2502 } else { 2503 throw new Error("Provided callback for onhintclick was not a function."); 2504 } 2505 2506 return this; 2507 }, 2508 onhintclose: function onhintclose(providedCallback) { 2509 if (typeof providedCallback === "function") { 2510 this._hintCloseCallback = providedCallback; 2511 } else { 2512 throw new Error("Provided callback for onhintclose was not a function."); 2513 } 2514 2515 return this; 2516 }, 2517 onexit: function onexit(providedCallback) { 2518 if (typeof providedCallback === "function") { 2519 this._introExitCallback = providedCallback; 2520 } else { 2521 throw new Error("Provided callback for onexit was not a function."); 2522 } 2523 2524 return this; 2525 }, 2526 onskip: function onskip(providedCallback) { 2527 if (typeof providedCallback === "function") { 2528 this._introSkipCallback = providedCallback; 2529 } else { 2530 throw new Error("Provided callback for onskip was not a function."); 2531 } 2532 2533 return this; 2534 }, 2535 onbeforeexit: function onbeforeexit(providedCallback) { 2536 if (typeof providedCallback === "function") { 2537 this._introBeforeExitCallback = providedCallback; 2538 } else { 2539 throw new Error("Provided callback for onbeforeexit was not a function."); 2540 } 2541 2542 return this; 2543 }, 2544 addHints: function addHints() { 2545 populateHints.call(this, this._targetElement); 2546 return this; 2547 }, 2548 hideHint: function hideHint$1(stepId) { 2549 hideHint.call(this, stepId); 2550 2551 return this; 2552 }, 2553 hideHints: function hideHints$1() { 2554 hideHints.call(this); 2555 2556 return this; 2557 }, 2558 showHint: function showHint$1(stepId) { 2559 showHint.call(this, stepId); 2560 2561 return this; 2562 }, 2563 showHints: function showHints$1() { 2564 showHints.call(this); 2565 2566 return this; 2567 }, 2568 removeHints: function removeHints$1() { 2569 removeHints.call(this); 2570 2571 return this; 2572 }, 2573 removeHint: function removeHint$1(stepId) { 2574 removeHint().call(this, stepId); 2575 2576 return this; 2577 }, 2578 showHintDialog: function showHintDialog$1(stepId) { 2579 showHintDialog.call(this, stepId); 2580 2581 return this; 2582 } 2583 }; 2584 2585 return introJs; 2586 2587})));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.