Skip to content

Commit b8cde24

Browse files
author
bozdoz
committed
Scroll parent element to targetElement; resolves usablica#210; resolves usablica#350;
1 parent 1b9879f commit b8cde24

File tree

3 files changed

+158
-30
lines changed

3 files changed

+158
-30
lines changed

example/hello-world/withScroll.html

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Basic usage</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<meta name="description" content="Intro.js - Better introductions for websites and features with a step-by-step guide for your projects.">
8+
<meta name="author" content="Afshin Mehrabani (@afshinmeh) in usabli.ca group">
9+
10+
<!-- styles -->
11+
<link href="../assets/css/bootstrap.min.css" rel="stylesheet">
12+
<link href="../assets/css/demo.css" rel="stylesheet">
13+
14+
<!-- Add IntroJs styles -->
15+
<link href="../../introjs.css" rel="stylesheet">
16+
17+
<link href="../assets/css/bootstrap-responsive.min.css" rel="stylesheet">
18+
19+
<style>
20+
.marketing {
21+
height: 300px;
22+
height: 40vh;
23+
margin-top: 500px;
24+
margin-top: 40vh;
25+
overflow: auto;
26+
}
27+
</style>
28+
</head>
29+
30+
<body>
31+
32+
<div class="container-narrow">
33+
34+
<div class="masthead">
35+
<ul class="nav nav-pills pull-right">
36+
<li><a href="https://github.com/usablica/intro.js/tags"><i class='icon-black icon-download-alt'></i> Download</a></li>
37+
<li><a href="https://github.com/usablica/intro.js">Github</a></li>
38+
<li><a href="https://twitter.com/usablica">@usablica</a></li>
39+
</ul>
40+
<h3 class="muted">Intro.js</h3>
41+
</div>
42+
43+
<hr>
44+
45+
<div class="jumbotron">
46+
<h1 data-step="3" data-intro="This is a tooltip!">Works with a Scrollable Element</h1>
47+
<p class="lead">This is the basic usage of IntroJs, with <code>data-step</code> and <code>data-intro</code> attributes.</p>
48+
<a class="btn btn-large btn-success" href="javascript:void(0);" onclick="javascript:introJs().start();">Show me how</a>
49+
</div>
50+
51+
<hr>
52+
53+
<div class="row-fluid marketing">
54+
<h4 data-step="2" data-intro="Another step.">Section One</h4>
55+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
56+
57+
<h4>Section Two</h4>
58+
<div>
59+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
60+
<h5>testing</h5>
61+
</div>
62+
63+
<h4>Section Three</h4>
64+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
65+
66+
<h4>Section Four</h4>
67+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
68+
69+
<h4>Section Five</h4>
70+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
71+
72+
<h4 data-step="1" data-intro="A scrolling step.">Section Six</h4>
73+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
74+
75+
<h4>Section Seven</h4>
76+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
77+
78+
<h4>Section Eight</h4>
79+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
80+
81+
<h4>Section Nine</h4>
82+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci
83+
faucibus. Phasellus nec metus purus.</p>
84+
85+
<h4>Section Ten</h4>
86+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
87+
88+
<h4>Section Eleven</h4>
89+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
90+
91+
<h4>Section Twelve</h4>
92+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
93+
</div>
94+
95+
<hr>
96+
</div>
97+
<script type="text/javascript" src="../../intro.js"></script>
98+
</body>
99+
</html>

example/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ <h3 class="muted">Examples</h3>
2525
<li><a href="hello-world/withoutBullets.html" title='Basic usage with buttons'>Basic usage with buttons</a></li>
2626
<li><a href="hello-world/withoutButtons.html" title='Basic usage with bullets'>Basic usage with bullets</a></li>
2727
<li><a href="hello-world/withProgress.html" title='Basic usage with progress-bar'>Basic usage with progress-bar</a></li>
28+
<li><a href="hello-world/withScroll.html" title='Basic usage with a scrolling element'>Basic usage with a scrolling element</a></li>
2829
<li><a href="programmatic/index.html" title='Programmatic defining using JSON'>Programmatic defining using JSON</a></li>
2930
<li><a href="multi-page/index.html" title='Multi-Page introduction'>Multi-Page introduction</a></li>
3031
<li><a href="auto-position/index.html" title='Auto-positioning'>Auto-positioning</a></li>

intro.js

+58-30
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,8 @@
10091009
highlightClass = 'introjs-helperLayer',
10101010
nextTooltipButton,
10111011
prevTooltipButton,
1012-
skipTooltipButton;
1012+
skipTooltipButton,
1013+
scrollParent;
10131014

10141015
//check for a current step highlight class
10151016
if (typeof (targetElement.highlightClass) === 'string') {
@@ -1044,7 +1045,15 @@
10441045
}
10451046
}
10461047

1047-
//set new position to helper layer
1048+
// scroll to element
1049+
scrollParent = _getScrollParent( targetElement.element );
1050+
1051+
if (scrollParent !== document.body) {
1052+
// target is within a scrollable element
1053+
_scrollParentToElement(scrollParent, targetElement.element);
1054+
}
1055+
1056+
// set new position to helper layer
10481057
_setHelperLayerPosition.call(self, oldHelperLayer);
10491058
_setHelperLayerPosition.call(self, oldReferenceLayer);
10501059

@@ -1112,6 +1121,14 @@
11121121
helperLayer.className = highlightClass;
11131122
referenceLayer.className = 'introjs-tooltipReferenceLayer';
11141123

1124+
// scroll to element
1125+
scrollParent = _getScrollParent( targetElement.element );
1126+
1127+
if (scrollParent !== document.body) {
1128+
// target is within a scrollable element
1129+
_scrollParentToElement(scrollParent, targetElement.element);
1130+
}
1131+
11151132
//set new position to helper layer
11161133
_setHelperLayerPosition.call(self, helperLayer);
11171134
_setHelperLayerPosition.call(self, referenceLayer);
@@ -2090,42 +2107,53 @@
20902107
* @returns Element's position info
20912108
*/
20922109
function _getOffset(element) {
2093-
var elementPosition = {};
2094-
20952110
var body = document.body;
20962111
var docEl = document.documentElement;
2097-
20982112
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
20992113
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
2114+
var x = element.getBoundingClientRect();
2115+
return {
2116+
top: x.top + scrollTop,
2117+
width: x.width,
2118+
height: x.height,
2119+
left: x.left + scrollLeft
2120+
};
2121+
}
21002122

2101-
if (element instanceof SVGElement) {
2102-
var x = element.getBoundingClientRect();
2103-
elementPosition.top = x.top + scrollTop;
2104-
elementPosition.width = x.width;
2105-
elementPosition.height = x.height;
2106-
elementPosition.left = x.left + scrollLeft;
2107-
} else {
2108-
//set width
2109-
elementPosition.width = element.offsetWidth;
2110-
2111-
//set height
2112-
elementPosition.height = element.offsetHeight;
2113-
2114-
//calculate element top and left
2115-
var _x = 0;
2116-
var _y = 0;
2117-
while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) {
2118-
_x += element.offsetLeft;
2119-
_y += element.offsetTop;
2120-
element = element.offsetParent;
2123+
/**
2124+
* Find the nearest scrollable parent
2125+
* copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent
2126+
*
2127+
* @param Element element
2128+
* @return Element
2129+
*/
2130+
function _getScrollParent(element) {
2131+
var style = window.getComputedStyle(element);
2132+
var excludeStaticParent = (style.position === "absolute");
2133+
var overflowRegex = /(auto|scroll)/;
2134+
2135+
if (style.position === "fixed") return document.body;
2136+
2137+
for (var parent = element; (parent = parent.parentElement);) {
2138+
style = window.getComputedStyle(parent);
2139+
if (excludeStaticParent && style.position === "static") {
2140+
continue;
21212141
}
2122-
//set top
2123-
elementPosition.top = _y;
2124-
//set left
2125-
elementPosition.left = _x;
2142+
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
21262143
}
21272144

2128-
return elementPosition;
2145+
return document.body;
2146+
}
2147+
2148+
/**
2149+
* scroll a scrollable element to a child element
2150+
*
2151+
* @param Element parent
2152+
* @param Element element
2153+
* @return Null
2154+
*/
2155+
function _scrollParentToElement (parent, element) {
2156+
parent.scrollTop = element.offsetTop - parent.offsetTop;
21292157
}
21302158

21312159
/**

0 commit comments

Comments
 (0)