Skip to content

Commit 8ae5227

Browse files
committed
first commit - hint feature
1 parent 49e98bb commit 8ae5227

File tree

3 files changed

+348
-6
lines changed

3 files changed

+348
-6
lines changed

example/hint/index.html

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Hints</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 class="nav nav-pills pull-right" data-hint="Get it, use it." data-hintPosition="top-middle" data-position="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 data-hint="This is a tooltip!" data-hintPosition="top-middle">Hints</h1>
37+
<p class="lead">Add hints using <code>data-hint</code> attribute.</p>
38+
<a class="btn btn-large btn-success" href="javascript:void(0);" onclick="javascript:introJs().addHints();">Add hints</a>
39+
</div>
40+
41+
<hr>
42+
43+
<div class="row-fluid marketing">
44+
<div 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 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+
<h4>Section Five</h4>
60+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
61+
62+
<h4>Section Six</h4>
63+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis mollis augue a neque cursus ac blandit orci faucibus. Phasellus nec metus purus.</p>
64+
65+
</div>
66+
</div>
67+
68+
<hr>
69+
</div>
70+
<script type="text/javascript" src="../../intro.js"></script>
71+
</body>
72+
</html>

intro.js

Lines changed: 183 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
*/
2929
function IntroJs(obj) {
3030
this._targetElement = obj;
31+
this._introItems = [];
3132

3233
this._options = {
3334
/* Next button label in tooltip box */
@@ -65,7 +66,11 @@
6566
/* Precedence of positions, when auto is enabled */
6667
positionPrecedence: ["bottom", "top", "right", "left"],
6768
/* Disable an interaction with element? */
68-
disableInteraction: false
69+
disableInteraction: false,
70+
/* Default hint position */
71+
hintPosition: 'top',
72+
/* Hint button label */
73+
hintButtonLabel: 'Got it',
6974
};
7075
}
7176

@@ -694,7 +699,7 @@
694699
* @api private
695700
* @method _disableInteraction
696701
*/
697-
function _disableInteraction () {
702+
function _disableInteraction() {
698703
var disableInteractionLayer = document.querySelector('.introjs-disableInteraction');
699704
if (disableInteractionLayer === null) {
700705
disableInteractionLayer = document.createElement('div');
@@ -1132,7 +1137,175 @@
11321137
}, 10);
11331138

11341139
return true;
1135-
}
1140+
};
1141+
1142+
1143+
/**
1144+
* Start parsing hint items
1145+
*
1146+
* @api private
1147+
* @param {Object} targetElm
1148+
* @method _startHint
1149+
*/
1150+
function _populateHints(targetElm) {
1151+
var self = this;
1152+
1153+
if (this._options.hints) {
1154+
for (var i = 0, l = this._options.hints.length; i < l; i++) {
1155+
var currentItem = _cloneObject(this._options.hints[i]);
1156+
1157+
if (typeof(currentItem.element) === 'string') {
1158+
//grab the element with given selector from the page
1159+
currentItem.element = document.querySelector(currentItem.element);
1160+
}
1161+
1162+
if (currentItem.element != null) {
1163+
this._introItems.push(currentItem);
1164+
}
1165+
}
1166+
} else {
1167+
var hints = targetElm.querySelectorAll('*[data-hint]');
1168+
1169+
if (hints.length < 1) {
1170+
return false;
1171+
}
1172+
1173+
//first add intro items with data-step
1174+
for (var i = 0, l = hints.length; i < l; i++) {
1175+
var currentElement = hints[i];
1176+
1177+
this._introItems.push({
1178+
element: currentElement,
1179+
hint: currentElement.getAttribute('data-hint'),
1180+
hintPosition: currentElement.getAttribute('data-hintPosition') || this._options.hintPosition,
1181+
position: currentElement.getAttribute('data-position') || this._options.tooltipPosition
1182+
});
1183+
}
1184+
}
1185+
1186+
_addHints.call(this);
1187+
};
1188+
1189+
/**
1190+
* Add all available hints to the page
1191+
*
1192+
* @api private
1193+
* @method _addHints
1194+
*/
1195+
function _addHints() {
1196+
var hintsWrapper = document.createElement('div');
1197+
hintsWrapper.className = 'introjs-hints';
1198+
1199+
for (var i = 0, l = this._introItems.length; i < l; i++) {
1200+
var item = this._introItems[i];
1201+
1202+
var hint = document.createElement('a');
1203+
hint.href = "javascript:void(0);";
1204+
1205+
// when user clicks on the hint element
1206+
hint.onclick = _hintClick.bind(this, hint, item);
1207+
1208+
hint.className = 'introjs-hint';
1209+
var hintDot = document.createElement('div');
1210+
hintDot.className = 'introjs-hint-dot';
1211+
var hintPulse = document.createElement('div');
1212+
hintPulse.className = 'introjs-hint-pulse';
1213+
1214+
hint.appendChild(hintDot);
1215+
hint.appendChild(hintPulse);
1216+
hint.setAttribute('data-step', i);
1217+
1218+
// get/calculate offset of target element
1219+
var offset = _getOffset.call(this, item.element);
1220+
1221+
// we swap the hint element with target element
1222+
// because _setHelperLayerPosition uses `element` property
1223+
item.targetElement = item.element;
1224+
item.element = hint;
1225+
1226+
// align the hint element
1227+
switch (item.hintPosition) {
1228+
default:
1229+
case 'top-left':
1230+
hint.style.left = offset.left + 'px';
1231+
hint.style.top = offset.top + 'px';
1232+
break;
1233+
case 'top-right':
1234+
hint.style.left = (offset.left + offset.width) + 'px';
1235+
hint.style.top = offset.top + 'px';
1236+
break;
1237+
case 'bottom-left':
1238+
hint.style.left = offset.left + 'px';
1239+
hint.style.top = (offset.top + offset.height) + 'px';
1240+
break;
1241+
case 'bottom-right':
1242+
hint.style.left = (offset.left + offset.width) + 'px';
1243+
hint.style.top = (offset.top + offset.height) + 'px';
1244+
break;
1245+
case 'bottom-middle':
1246+
hint.style.left = (offset.left + (offset.width / 2)) + 'px';
1247+
hint.style.top = (offset.top + offset.height) + 'px';
1248+
break;
1249+
case 'top-middle':
1250+
hint.style.left = (offset.left + (offset.width / 2)) + 'px';
1251+
hint.style.top = offset.top + 'px';
1252+
break;
1253+
}
1254+
1255+
hintsWrapper.appendChild(hint);
1256+
}
1257+
1258+
// adding the hints wrapper
1259+
document.body.appendChild(hintsWrapper);
1260+
};
1261+
1262+
/**
1263+
* Triggers when user clicks on the hint element
1264+
*
1265+
* @api private
1266+
* @method _hintClick
1267+
* @param {Object} hintElement
1268+
* @param {Object} item
1269+
*/
1270+
function _hintClick(hintElement, item) {
1271+
var tooltipLayer = document.createElement('div');
1272+
var tooltipTextLayer = document.createElement('div');
1273+
var arrowLayer = document.createElement('div');
1274+
var referenceLayer = document.createElement('div');
1275+
1276+
tooltipLayer.className = 'introjs-tooltip';
1277+
1278+
tooltipTextLayer.className = 'introjs-tooltiptext';
1279+
1280+
var tooltipWrapper = document.createElement('p');
1281+
tooltipWrapper.innerHTML = item.hint;
1282+
1283+
var closeButton = document.createElement('a');
1284+
closeButton.className = 'introjs-button';
1285+
closeButton.innerHTML = this._options.hintButtonLabel;
1286+
1287+
tooltipTextLayer.appendChild(tooltipWrapper);
1288+
tooltipTextLayer.appendChild(closeButton);
1289+
1290+
arrowLayer.className = 'introjs-arrow';
1291+
tooltipLayer.appendChild(arrowLayer);
1292+
1293+
tooltipLayer.appendChild(tooltipTextLayer);
1294+
1295+
// set current step for _placeTooltip function
1296+
this._currentStep = hintElement.getAttribute('data-step');
1297+
1298+
// align reference layer position
1299+
referenceLayer.className = 'introjs-tooltipReferenceLayer introjs-hintTooltip';
1300+
referenceLayer.setAttribute('data-step', hintElement.getAttribute('data-step'));
1301+
_setHelperLayerPosition.call(this, referenceLayer);
1302+
1303+
referenceLayer.appendChild(tooltipLayer);
1304+
document.body.appendChild(referenceLayer);
1305+
1306+
//set proper position
1307+
_placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer);
1308+
};
11361309

11371310
/**
11381311
* Get an element position on the page
@@ -1166,7 +1339,7 @@
11661339
elementPosition.left = _x;
11671340

11681341
return elementPosition;
1169-
}
1342+
};
11701343

11711344
/**
11721345
* Gets the current progress percentage
@@ -1179,7 +1352,7 @@
11791352
// Steps are 0 indexed
11801353
var currentStep = parseInt((this._currentStep + 1), 10);
11811354
return ((currentStep / this._introItems.length) * 100);
1182-
}
1355+
};
11831356

11841357
/**
11851358
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
@@ -1194,7 +1367,7 @@
11941367
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
11951368
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
11961369
return obj3;
1197-
}
1370+
};
11981371

11991372
var introJs = function (targetElm) {
12001373
if (typeof (targetElm) === 'object') {
@@ -1300,6 +1473,10 @@
13001473
throw new Error('Provided callback for onexit was not a function.');
13011474
}
13021475
return this;
1476+
},
1477+
addHints: function() {
1478+
_populateHints.call(this, this._targetElement);
1479+
return this;
13031480
}
13041481
};
13051482

0 commit comments

Comments
 (0)