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