Skip to content

Commit be96db0

Browse files
committed
Add ability to define introductions without focusing on elements + fix IE8 issue in programmatic version
1 parent 44852a1 commit be96db0

File tree

7 files changed

+234
-37
lines changed

7 files changed

+234
-37
lines changed

example/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ <h3 class="muted">Examples</h3>
2929
<li><a href="RTL/index.html" title='RTL version'>RTL version</a></li>
3030
<li><a href="html-tooltip/index.html" title='HTML in tooltip'>HTML in tooltip</a></li>
3131
<li><a href="custom-class/index.html" title='Custom CSS Class'>Custom CSS Class</a></li>
32+
<li><a href="withoutElement/index.html" title='Introduction without focusing on elements'>Introduction without focusing on elements</a></li>
3233
</ul>
3334
</div>
3435
</body>

example/programmatic/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ <h4>Section Six</h4>
7474
var intro = introJs();
7575
intro.setOptions({
7676
steps: [
77+
{
78+
intro: "Hello world!"
79+
},
7780
{
7881
element: document.querySelector('#step1'),
7982
intro: "This is a tooltip."

example/withoutElement/index.html

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Intro without focusing on elements</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+
</head>
19+
20+
<body>
21+
22+
<div class="container-narrow">
23+
24+
<div class="masthead">
25+
<ul id="step5" class="nav nav-pills pull-right">
26+
<li><a href="https://github.com/usablica/intro.js/tags"><i class='icon-black icon-download-alt'></i> Download</a></li>
27+
<li><a href="https://github.com/usablica/intro.js">Github</a></li>
28+
<li><a href="https://twitter.com/usablica">@usablica</a></li>
29+
</ul>
30+
<h3 class="muted">Intro.js</h3>
31+
</div>
32+
33+
<hr>
34+
35+
<div class="jumbotron">
36+
<h1 id="step1">Without Element</h1>
37+
<p id="step4" class="lead">This example shows the introductions without focusing on elements.</p>
38+
<a class="btn btn-large btn-success" href="javascript:void(0);" onclick="startIntro();">Show me how</a>
39+
</div>
40+
41+
<hr>
42+
43+
<div class="row-fluid marketing">
44+
<div id="step2" class="span6">
45+
<h4>Section One</h4>
46+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
47+
48+
<h4>Section Two</h4>
49+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
50+
51+
<h4>Section Three</h4>
52+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
53+
</div>
54+
55+
<div id="step3" class="span6">
56+
<h4>Section Four</h4>
57+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
58+
59+
60+
<h4>Section Five</h4>
61+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
62+
63+
<h4>Section Six</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+
</div>
66+
</div>
67+
68+
<hr>
69+
70+
</div>
71+
<script type="text/javascript" src="../../intro.js"></script>
72+
<script type="text/javascript">
73+
function startIntro(){
74+
var intro = introJs();
75+
intro.setOptions({
76+
steps: [
77+
{
78+
intro: "Hello world!"
79+
},
80+
{
81+
intro: "You <b>don't need</b> to define element to focus, this is a floating tooltip."
82+
},
83+
{
84+
element: document.querySelector('#step1'),
85+
intro: "This is a tooltip."
86+
},
87+
{
88+
element: document.querySelectorAll('#step2')[0],
89+
intro: "Ok, wasn't that fun?",
90+
position: 'right'
91+
},
92+
{
93+
element: '#step3',
94+
intro: 'More features, more fun.',
95+
position: 'left'
96+
},
97+
{
98+
element: '#step4',
99+
intro: "Another step.",
100+
position: 'bottom'
101+
},
102+
{
103+
element: '#step5',
104+
intro: 'Get it, use it.'
105+
}
106+
]
107+
});
108+
109+
intro.start();
110+
}
111+
</script>
112+
</body>
113+
</html>

intro.js

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Intro.js v0.7.1
2+
* Intro.js v0.8.0
33
* https://github.com/usablica/intro.js
44
* MIT licensed
55
*
@@ -19,7 +19,7 @@
1919
}
2020
} (this, function (exports) {
2121
//Default config/variables
22-
var VERSION = '0.7.1';
22+
var VERSION = '0.8.0';
2323

2424
/**
2525
* IntroJs main class
@@ -85,6 +85,21 @@
8585
currentItem.element = document.querySelector(currentItem.element);
8686
}
8787

88+
//intro without element
89+
if (typeof(currentItem.element) === 'undefined' || currentItem.element == null) {
90+
var floatingElementQuery = document.querySelector(".introjsFloatingElement");
91+
92+
if (floatingElementQuery == null) {
93+
floatingElementQuery = document.createElement('div');
94+
floatingElementQuery.className = 'introjsFloatingElement';
95+
96+
document.body.appendChild(floatingElementQuery);
97+
}
98+
99+
currentItem.element = floatingElementQuery;
100+
currentItem.position = 'floating';
101+
}
102+
88103
if (currentItem.element != null) {
89104
introItems.push(currentItem);
90105
}
@@ -215,7 +230,7 @@
215230
* @method _cloneObject
216231
*/
217232
function _cloneObject(object) {
218-
if (object == null || typeof (object) != 'object' || object.hasOwnProperty("nodeName") === true || typeof (object.nodeType) != 'undefined') {
233+
if (object == null || typeof (object) != 'object' || typeof (object.nodeType) != 'undefined') {
219234
return object;
220235
}
221236
var temp = {};
@@ -266,6 +281,7 @@
266281
this._introBeforeChangeCallback.call(this, nextStep.element);
267282
}
268283

284+
this._direction = 'forward';
269285
_showElement.call(this, nextStep);
270286
}
271287

@@ -285,6 +301,7 @@
285301
this._introBeforeChangeCallback.call(this, nextStep.element);
286302
}
287303

304+
this._direction = 'backward';
288305
_showElement.call(this, nextStep);
289306
}
290307

@@ -298,22 +315,32 @@
298315
function _exitIntro(targetElement) {
299316
//remove overlay layer from the page
300317
var overlayLayer = targetElement.querySelector('.introjs-overlay');
318+
301319
//return if intro already completed or skipped
302320
if (overlayLayer == null) {
303321
return;
304322
}
323+
305324
//for fade-out animation
306325
overlayLayer.style.opacity = 0;
307326
setTimeout(function () {
308327
if (overlayLayer.parentNode) {
309328
overlayLayer.parentNode.removeChild(overlayLayer);
310329
}
311330
}, 500);
331+
312332
//remove all helper layers
313333
var helperLayer = targetElement.querySelector('.introjs-helperLayer');
314334
if (helperLayer) {
315335
helperLayer.parentNode.removeChild(helperLayer);
316336
}
337+
338+
//remove intro floating element
339+
var floatingElement = document.querySelector('.introjsFloatingElement');
340+
if (floatingElement) {
341+
floatingElement.parentNode.removeChild(floatingElement);
342+
}
343+
317344
//remove `introjs-showElement` class from the element
318345
var showElement = document.querySelector('.introjs-showElement');
319346
if (showElement) {
@@ -327,12 +354,14 @@
327354
fixParents[i].className = fixParents[i].className.replace(/introjs-fixParent/g, '').replace(/^\s+|\s+$/g, '');
328355
};
329356
}
357+
330358
//clean listeners
331359
if (window.removeEventListener) {
332360
window.removeEventListener('keydown', this._onKeyDown, true);
333361
} else if (document.detachEvent) { //IE
334362
document.detachEvent('onkeydown', this._onKeyDown);
335363
}
364+
336365
//set the step to zero
337366
this._currentStep = undefined;
338367
}
@@ -346,12 +375,21 @@
346375
* @param {Object} tooltipLayer
347376
* @param {Object} arrowLayer
348377
*/
349-
function _placeTooltip(targetElement, tooltipLayer, arrowLayer) {
378+
function _placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer) {
350379
//reset the old style
351-
tooltipLayer.style.top = null;
352-
tooltipLayer.style.right = null;
353-
tooltipLayer.style.bottom = null;
354-
tooltipLayer.style.left = null;
380+
tooltipLayer.style.top = null;
381+
tooltipLayer.style.right = null;
382+
tooltipLayer.style.bottom = null;
383+
tooltipLayer.style.left = null;
384+
tooltipLayer.style.marginLeft = null;
385+
tooltipLayer.style.marginTop = null;
386+
387+
arrowLayer.style.display = 'inherit';
388+
389+
if (typeof(helperNumberLayer) != 'undefined' && helperNumberLayer != null) {
390+
helperNumberLayer.style.top = null;
391+
helperNumberLayer.style.left = null;
392+
}
355393

356394
//prevent error when `this._currentStep` is undefined
357395
if (!this._introItems[this._currentStep]) return;
@@ -388,6 +426,23 @@
388426
}
389427
tooltipLayer.style.right = (_getOffset(targetElement).width + 20) + 'px';
390428
arrowLayer.className = 'introjs-arrow right';
429+
break;
430+
case 'floating':
431+
arrowLayer.style.display = 'none';
432+
433+
//we have to adjust the top and left of layer manually for intro items without element{
434+
var tooltipOffset = _getOffset(tooltipLayer);
435+
436+
tooltipLayer.style.left = '50%';
437+
tooltipLayer.style.top = '50%';
438+
tooltipLayer.style.marginLeft = '-' + (tooltipOffset.width / 2) + 'px';
439+
tooltipLayer.style.marginTop = '-' + (tooltipOffset.height / 2) + 'px';
440+
441+
if (typeof(helperNumberLayer) != 'undefined' && helperNumberLayer != null) {
442+
helperNumberLayer.style.left = '-' + ((tooltipOffset.width / 2) + 18) + 'px';
443+
helperNumberLayer.style.top = '-' + ((tooltipOffset.height / 2) + 18) + 'px';
444+
}
445+
391446
break;
392447
case 'bottom':
393448
// Bottom going to follow the default behavior
@@ -410,10 +465,17 @@
410465
//prevent error when `this._currentStep` in undefined
411466
if (!this._introItems[this._currentStep]) return;
412467

413-
var elementPosition = _getOffset(this._introItems[this._currentStep].element);
468+
var currentElement = this._introItems[this._currentStep];
469+
var elementPosition = _getOffset(currentElement.element);
470+
471+
var widthHeightPadding = 10;
472+
if (currentElement.position == 'floating') {
473+
widthHeightPadding = 0;
474+
}
475+
414476
//set new position to helper layer
415-
helperLayer.setAttribute('style', 'width: ' + (elementPosition.width + 10) + 'px; ' +
416-
'height:' + (elementPosition.height + 10) + 'px; ' +
477+
helperLayer.setAttribute('style', 'width: ' + (elementPosition.width + widthHeightPadding) + 'px; ' +
478+
'height:' + (elementPosition.height + widthHeightPadding) + 'px; ' +
417479
'top:' + (elementPosition.top - 5) + 'px;' +
418480
'left: ' + (elementPosition.left - 5) + 'px;');
419481
}
@@ -448,6 +510,14 @@
448510
//hide the tooltip
449511
oldtooltipContainer.style.opacity = 0;
450512

513+
if (oldHelperNumberLayer != null) {
514+
var lastIntroItem = this._introItems[(targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0)];
515+
516+
if (lastIntroItem != null && (this._direction == 'forward' && lastIntroItem.position == 'floating') || (this._direction == 'backward' && targetElement.position == 'floating')) {
517+
oldHelperNumberLayer.style.opacity = 0;
518+
}
519+
}
520+
451521
//set new position to helper layer
452522
_setHelperLayerPosition.call(self, oldHelperLayer);
453523

@@ -474,14 +544,15 @@
474544
//set current tooltip text
475545
oldtooltipLayer.innerHTML = targetElement.intro;
476546
//set the tooltip position
477-
_placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer);
547+
_placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);
478548

479549
//change active bullet
480550
oldHelperLayer.querySelector('.introjs-bullets li > a.active').className = '';
481551
oldHelperLayer.querySelector('.introjs-bullets li > a[data-stepnumber="' + targetElement.step + '"]').className = 'active';
482552

483553
//show the tooltip
484554
oldtooltipContainer.style.opacity = 1;
555+
oldHelperNumberLayer.style.opacity = 1;
485556
}, 350);
486557

487558
} else {
@@ -605,7 +676,7 @@
605676
tooltipLayer.appendChild(buttonsLayer);
606677

607678
//set proper position
608-
_placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer);
679+
_placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer);
609680
}
610681

611682
if (this._currentStep == 0 && this._introItems.length > 1) {

introjs.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,11 @@
245245
}
246246
.introjs-bullets ul li a.active {
247247
background: #999;
248+
}
249+
.introjsFloatingElement {
250+
position: absolute;
251+
height: 0;
252+
width: 0;
253+
left: 50%;
254+
top: 50%;
248255
}

0 commit comments

Comments
 (0)