Skip to content

Commit

Permalink
Add ability to define introductions without focusing on elements + fi…
Browse files Browse the repository at this point in the history
…x IE8 issue in programmatic version
  • Loading branch information
afshinm committed Mar 25, 2014
1 parent 44852a1 commit be96db0
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 37 deletions.
1 change: 1 addition & 0 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ <h3 class="muted">Examples</h3>
<li><a href="RTL/index.html" title='RTL version'>RTL version</a></li>
<li><a href="html-tooltip/index.html" title='HTML in tooltip'>HTML in tooltip</a></li>
<li><a href="custom-class/index.html" title='Custom CSS Class'>Custom CSS Class</a></li>
<li><a href="withoutElement/index.html" title='Introduction without focusing on elements'>Introduction without focusing on elements</a></li>
</ul>
</div>
</body>
Expand Down
3 changes: 3 additions & 0 deletions example/programmatic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ <h4>Section Six</h4>
var intro = introJs();
intro.setOptions({
steps: [
{
intro: "Hello world!"
},
{
element: document.querySelector('#step1'),
intro: "This is a tooltip."
Expand Down
113 changes: 113 additions & 0 deletions example/withoutElement/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Intro without focusing on elements</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">
</head>

<body>

<div class="container-narrow">

<div class="masthead">
<ul id="step5" 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 id="step1">Without Element</h1>
<p id="step4" class="lead">This example shows the introductions without focusing on elements.</p>
<a class="btn btn-large btn-success" href="javascript:void(0);" onclick="startIntro();">Show me how</a>
</div>

<hr>

<div class="row-fluid marketing">
<div id="step2" class="span6">
<h4>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>
<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 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>
</div>

<div id="step3" class="span6">
<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>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>
</div>
</div>

<hr>

</div>
<script type="text/javascript" src="../../intro.js"></script>
<script type="text/javascript">
function startIntro(){
var intro = introJs();
intro.setOptions({
steps: [
{
intro: "Hello world!"
},
{
intro: "You <b>don't need</b> to define element to focus, this is a floating tooltip."
},
{
element: document.querySelector('#step1'),
intro: "This is a tooltip."
},
{
element: document.querySelectorAll('#step2')[0],
intro: "Ok, wasn't that fun?",
position: 'right'
},
{
element: '#step3',
intro: 'More features, more fun.',
position: 'left'
},
{
element: '#step4',
intro: "Another step.",
position: 'bottom'
},
{
element: '#step5',
intro: 'Get it, use it.'
}
]
});

intro.start();
}
</script>
</body>
</html>
97 changes: 84 additions & 13 deletions intro.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Intro.js v0.7.1
* Intro.js v0.8.0
* https://github.com/usablica/intro.js
* MIT licensed
*
Expand All @@ -19,7 +19,7 @@
}
} (this, function (exports) {
//Default config/variables
var VERSION = '0.7.1';
var VERSION = '0.8.0';

/**
* IntroJs main class
Expand Down Expand Up @@ -85,6 +85,21 @@
currentItem.element = document.querySelector(currentItem.element);
}

//intro without element
if (typeof(currentItem.element) === 'undefined' || currentItem.element == null) {
var floatingElementQuery = document.querySelector(".introjsFloatingElement");

if (floatingElementQuery == null) {
floatingElementQuery = document.createElement('div');
floatingElementQuery.className = 'introjsFloatingElement';

document.body.appendChild(floatingElementQuery);
}

currentItem.element = floatingElementQuery;
currentItem.position = 'floating';
}

if (currentItem.element != null) {
introItems.push(currentItem);
}
Expand Down Expand Up @@ -215,7 +230,7 @@
* @method _cloneObject
*/
function _cloneObject(object) {
if (object == null || typeof (object) != 'object' || object.hasOwnProperty("nodeName") === true || typeof (object.nodeType) != 'undefined') {
if (object == null || typeof (object) != 'object' || typeof (object.nodeType) != 'undefined') {
return object;
}
var temp = {};
Expand Down Expand Up @@ -266,6 +281,7 @@
this._introBeforeChangeCallback.call(this, nextStep.element);
}

this._direction = 'forward';

This comment has been minimized.

Copy link
@SamyCookie

SamyCookie Mar 25, 2014

@afshinm
should this property be affected before _introBeforeChangeCallback function ? I have a use case which needs this property there.
example #143

This comment has been minimized.

Copy link
@afshinm

afshinm Mar 25, 2014

Author Contributor

Ops, yeah you're right. I will fix it.

This comment has been minimized.

Copy link
@SamyCookie

SamyCookie Mar 25, 2014

Thanks a lot for that ! :)
(and thanks for your great software btw !)

This comment has been minimized.

Copy link
@afshinm

afshinm Mar 25, 2014

Author Contributor

No problem dude. Fixed!

_showElement.call(this, nextStep);
}

Expand All @@ -285,6 +301,7 @@
this._introBeforeChangeCallback.call(this, nextStep.element);
}

this._direction = 'backward';

This comment has been minimized.

Copy link
@SamyCookie

SamyCookie Mar 25, 2014

@afshinm
same as my previous comment

_showElement.call(this, nextStep);
}

Expand All @@ -298,22 +315,32 @@
function _exitIntro(targetElement) {
//remove overlay layer from the page
var overlayLayer = targetElement.querySelector('.introjs-overlay');

//return if intro already completed or skipped
if (overlayLayer == null) {
return;
}

//for fade-out animation
overlayLayer.style.opacity = 0;
setTimeout(function () {
if (overlayLayer.parentNode) {
overlayLayer.parentNode.removeChild(overlayLayer);
}
}, 500);

//remove all helper layers
var helperLayer = targetElement.querySelector('.introjs-helperLayer');
if (helperLayer) {
helperLayer.parentNode.removeChild(helperLayer);
}

//remove intro floating element
var floatingElement = document.querySelector('.introjsFloatingElement');
if (floatingElement) {
floatingElement.parentNode.removeChild(floatingElement);
}

//remove `introjs-showElement` class from the element
var showElement = document.querySelector('.introjs-showElement');
if (showElement) {
Expand All @@ -327,12 +354,14 @@
fixParents[i].className = fixParents[i].className.replace(/introjs-fixParent/g, '').replace(/^\s+|\s+$/g, '');
};
}

//clean listeners
if (window.removeEventListener) {
window.removeEventListener('keydown', this._onKeyDown, true);
} else if (document.detachEvent) { //IE
document.detachEvent('onkeydown', this._onKeyDown);
}

//set the step to zero
this._currentStep = undefined;
}
Expand All @@ -346,12 +375,21 @@
* @param {Object} tooltipLayer
* @param {Object} arrowLayer
*/
function _placeTooltip(targetElement, tooltipLayer, arrowLayer) {
function _placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer) {
//reset the old style
tooltipLayer.style.top = null;
tooltipLayer.style.right = null;
tooltipLayer.style.bottom = null;
tooltipLayer.style.left = null;
tooltipLayer.style.top = null;
tooltipLayer.style.right = null;
tooltipLayer.style.bottom = null;
tooltipLayer.style.left = null;
tooltipLayer.style.marginLeft = null;
tooltipLayer.style.marginTop = null;

arrowLayer.style.display = 'inherit';

if (typeof(helperNumberLayer) != 'undefined' && helperNumberLayer != null) {
helperNumberLayer.style.top = null;
helperNumberLayer.style.left = null;
}

//prevent error when `this._currentStep` is undefined
if (!this._introItems[this._currentStep]) return;
Expand Down Expand Up @@ -388,6 +426,23 @@
}
tooltipLayer.style.right = (_getOffset(targetElement).width + 20) + 'px';
arrowLayer.className = 'introjs-arrow right';
break;
case 'floating':
arrowLayer.style.display = 'none';

//we have to adjust the top and left of layer manually for intro items without element{
var tooltipOffset = _getOffset(tooltipLayer);

tooltipLayer.style.left = '50%';
tooltipLayer.style.top = '50%';
tooltipLayer.style.marginLeft = '-' + (tooltipOffset.width / 2) + 'px';
tooltipLayer.style.marginTop = '-' + (tooltipOffset.height / 2) + 'px';

if (typeof(helperNumberLayer) != 'undefined' && helperNumberLayer != null) {
helperNumberLayer.style.left = '-' + ((tooltipOffset.width / 2) + 18) + 'px';
helperNumberLayer.style.top = '-' + ((tooltipOffset.height / 2) + 18) + 'px';
}

break;
case 'bottom':
// Bottom going to follow the default behavior
Expand All @@ -410,10 +465,17 @@
//prevent error when `this._currentStep` in undefined
if (!this._introItems[this._currentStep]) return;

var elementPosition = _getOffset(this._introItems[this._currentStep].element);
var currentElement = this._introItems[this._currentStep];
var elementPosition = _getOffset(currentElement.element);

var widthHeightPadding = 10;
if (currentElement.position == 'floating') {
widthHeightPadding = 0;
}

//set new position to helper layer
helperLayer.setAttribute('style', 'width: ' + (elementPosition.width + 10) + 'px; ' +
'height:' + (elementPosition.height + 10) + 'px; ' +
helperLayer.setAttribute('style', 'width: ' + (elementPosition.width + widthHeightPadding) + 'px; ' +
'height:' + (elementPosition.height + widthHeightPadding) + 'px; ' +
'top:' + (elementPosition.top - 5) + 'px;' +
'left: ' + (elementPosition.left - 5) + 'px;');
}
Expand Down Expand Up @@ -448,6 +510,14 @@
//hide the tooltip
oldtooltipContainer.style.opacity = 0;

if (oldHelperNumberLayer != null) {
var lastIntroItem = this._introItems[(targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0)];

if (lastIntroItem != null && (this._direction == 'forward' && lastIntroItem.position == 'floating') || (this._direction == 'backward' && targetElement.position == 'floating')) {
oldHelperNumberLayer.style.opacity = 0;
}
}

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

Expand All @@ -474,14 +544,15 @@
//set current tooltip text
oldtooltipLayer.innerHTML = targetElement.intro;
//set the tooltip position
_placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer);
_placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);

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

//show the tooltip
oldtooltipContainer.style.opacity = 1;
oldHelperNumberLayer.style.opacity = 1;
}, 350);

} else {
Expand Down Expand Up @@ -605,7 +676,7 @@
tooltipLayer.appendChild(buttonsLayer);

//set proper position
_placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer);
_placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer);
}

if (this._currentStep == 0 && this._introItems.length > 1) {
Expand Down
7 changes: 7 additions & 0 deletions introjs.css
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,11 @@
}
.introjs-bullets ul li a.active {
background: #999;
}
.introjsFloatingElement {
position: absolute;
height: 0;
width: 0;
left: 50%;
top: 50%;
}
Loading

0 comments on commit be96db0

Please sign in to comment.