Skip to content

Commit

Permalink
Merge pull request #1 from ipastushenko/fix-scroll-elements
Browse files Browse the repository at this point in the history
Scroll parent element to targetElement; resolves usablica#210; resolves usablica#350;
  • Loading branch information
ipastushenko authored Feb 15, 2018
2 parents 96e11cf + b8cde24 commit 90a1a5c
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 30 deletions.
99 changes: 99 additions & 0 deletions example/hello-world/withScroll.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Basic usage</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Intro.js - Better introductions for websites and features with a step-by-step guide for your projects.">
<meta name="author" content="Afshin Mehrabani (@afshinmeh) in usabli.ca group">

<!-- styles -->
<link href="../assets/css/bootstrap.min.css" rel="stylesheet">
<link href="../assets/css/demo.css" rel="stylesheet">

<!-- Add IntroJs styles -->
<link href="../../introjs.css" rel="stylesheet">

<link href="../assets/css/bootstrap-responsive.min.css" rel="stylesheet">

<style>
.marketing {
height: 300px;
height: 40vh;
margin-top: 500px;
margin-top: 40vh;
overflow: auto;
}
</style>
</head>

<body>

<div class="container-narrow">

<div class="masthead">
<ul class="nav nav-pills pull-right">
<li><a href="https://github.com/usablica/intro.js/tags"><i class='icon-black icon-download-alt'></i> Download</a></li>
<li><a href="https://github.com/usablica/intro.js">Github</a></li>
<li><a href="https://twitter.com/usablica">@usablica</a></li>
</ul>
<h3 class="muted">Intro.js</h3>
</div>

<hr>

<div class="jumbotron">
<h1 data-step="3" data-intro="This is a tooltip!">Works with a Scrollable Element</h1>
<p class="lead">This is the basic usage of IntroJs, with <code>data-step</code> and <code>data-intro</code> attributes.</p>
<a class="btn btn-large btn-success" href="javascript:void(0);" onclick="javascript:introJs().start();">Show me how</a>
</div>

<hr>

<div class="row-fluid marketing">
<h4 data-step="2" data-intro="Another step.">Section One</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Two</h4>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
<h5>testing</h5>
</div>

<h4>Section Three</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Four</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Five</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4 data-step="1" data-intro="A scrolling step.">Section Six</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Seven</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Eight</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Nine</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci
faucibus. Phasellus nec metus purus.</p>

<h4>Section Ten</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Eleven</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>

<h4>Section Twelve</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
</div>

<hr>
</div>
<script type="text/javascript" src="../../intro.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ <h3 class="muted">Examples</h3>
<li><a href="hello-world/withoutBullets.html" title='Basic usage with buttons'>Basic usage with buttons</a></li>
<li><a href="hello-world/withoutButtons.html" title='Basic usage with bullets'>Basic usage with bullets</a></li>
<li><a href="hello-world/withProgress.html" title='Basic usage with progress-bar'>Basic usage with progress-bar</a></li>
<li><a href="hello-world/withScroll.html" title='Basic usage with a scrolling element'>Basic usage with a scrolling element</a></li>
<li><a href="programmatic/index.html" title='Programmatic defining using JSON'>Programmatic defining using JSON</a></li>
<li><a href="multi-page/index.html" title='Multi-Page introduction'>Multi-Page introduction</a></li>
<li><a href="auto-position/index.html" title='Auto-positioning'>Auto-positioning</a></li>
Expand Down
88 changes: 58 additions & 30 deletions intro.js
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,8 @@
highlightClass = 'introjs-helperLayer',
nextTooltipButton,
prevTooltipButton,
skipTooltipButton;
skipTooltipButton,
scrollParent;

//check for a current step highlight class
if (typeof (targetElement.highlightClass) === 'string') {
Expand Down Expand Up @@ -1044,7 +1045,15 @@
}
}

//set new position to helper layer
// scroll to element
scrollParent = _getScrollParent( targetElement.element );

if (scrollParent !== document.body) {
// target is within a scrollable element
_scrollParentToElement(scrollParent, targetElement.element);
}

// set new position to helper layer
_setHelperLayerPosition.call(self, oldHelperLayer);
_setHelperLayerPosition.call(self, oldReferenceLayer);

Expand Down Expand Up @@ -1112,6 +1121,14 @@
helperLayer.className = highlightClass;
referenceLayer.className = 'introjs-tooltipReferenceLayer';

// scroll to element
scrollParent = _getScrollParent( targetElement.element );

if (scrollParent !== document.body) {
// target is within a scrollable element
_scrollParentToElement(scrollParent, targetElement.element);
}

//set new position to helper layer
_setHelperLayerPosition.call(self, helperLayer);
_setHelperLayerPosition.call(self, referenceLayer);
Expand Down Expand Up @@ -2090,42 +2107,53 @@
* @returns Element's position info
*/
function _getOffset(element) {
var elementPosition = {};

var body = document.body;
var docEl = document.documentElement;

var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
var x = element.getBoundingClientRect();
return {
top: x.top + scrollTop,
width: x.width,
height: x.height,
left: x.left + scrollLeft
};
}

if (element instanceof SVGElement) {
var x = element.getBoundingClientRect();
elementPosition.top = x.top + scrollTop;
elementPosition.width = x.width;
elementPosition.height = x.height;
elementPosition.left = x.left + scrollLeft;
} else {
//set width
elementPosition.width = element.offsetWidth;

//set height
elementPosition.height = element.offsetHeight;

//calculate element top and left
var _x = 0;
var _y = 0;
while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) {
_x += element.offsetLeft;
_y += element.offsetTop;
element = element.offsetParent;
/**
* Find the nearest scrollable parent
* copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent
*
* @param Element element
* @return Element
*/
function _getScrollParent(element) {
var style = window.getComputedStyle(element);
var excludeStaticParent = (style.position === "absolute");
var overflowRegex = /(auto|scroll)/;

if (style.position === "fixed") return document.body;

for (var parent = element; (parent = parent.parentElement);) {
style = window.getComputedStyle(parent);
if (excludeStaticParent && style.position === "static") {
continue;
}
//set top
elementPosition.top = _y;
//set left
elementPosition.left = _x;
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
}

return elementPosition;
return document.body;
}

/**
* scroll a scrollable element to a child element
*
* @param Element parent
* @param Element element
* @return Null
*/
function _scrollParentToElement (parent, element) {
parent.scrollTop = element.offsetTop - parent.offsetTop;
}

/**
Expand Down

0 comments on commit 90a1a5c

Please sign in to comment.