Skip to content
This repository has been archived by the owner on Feb 17, 2021. It is now read-only.

Commit

Permalink
Added container tour option, instead of always using document.body
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin-Dobell committed Jan 19, 2017
1 parent dc747f0 commit 0d5a54d
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 21 deletions.
65 changes: 45 additions & 20 deletions src/js/hopscotch.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@
},

/**
* Helper function to get a single target DOM element. We will try to
* Helper function to find a DOM element with an identifier. We will try to
* locate the DOM element through several ways, in the following order:
*
* 1) Passing the string into document.querySelector
Expand All @@ -359,7 +359,7 @@
*
* @private
*/
getStepTargetHelper: function(target){
getElementByIdentifier: function(target) {
var result = document.getElementById(target);

//Backwards compatibility: assume the string is an id
Expand Down Expand Up @@ -388,6 +388,23 @@
return null;
},

/**
* Returns the container DOM element where bubble elements will be added
* as children. The container element can be specified by tourOpt.container
* as either a string identifier (ID/selector) or directly as a JavaScript
* DOM element. By default, or if the specified string identifier does not
* match an element, the document's body is used.
*
* @private
*/
getContainer: function(tourOpt) {
if (tourOpt.container) {
return typeof tourOpt.container === 'string' ? utils.getElementByIdentifier(tourOpt.container) || document.body : tourOpt.container;
}

return document.body;
},

/**
* Given a step, returns the target DOM element associated with it. It is
* recommended to only assign one target per step. However, there are
Expand All @@ -407,7 +424,7 @@

if (typeof step.target === 'string') {
//Just one target to test. Check and return its results.
return utils.getStepTargetHelper(step.target);
return utils.getElementByIdentifier(step.target);
}
else if (Array.isArray(step.target)) {
// Multiple items to check. Check each and return the first success.
Expand All @@ -417,7 +434,7 @@

for (i = 0, len = step.target.length; i < len; i++){
if (typeof step.target[i] === 'string') {
queriedTarget = utils.getStepTargetHelper(step.target[i]);
queriedTarget = utils.getElementByIdentifier(step.target[i]);

if (queriedTarget) {
return queriedTarget;
Expand Down Expand Up @@ -614,6 +631,8 @@
left,
arrowOffset,
verticalLeftPosition,
containerBoundingRect,
containerEl = utils.getContainer(this.opt),
targetEl = utils.getStepTarget(step),
el = this.element,
arrowEl = this.arrowEl,
Expand All @@ -628,6 +647,7 @@

// SET POSITION
boundingRect = targetEl.getBoundingClientRect();
containerBoundingRect = containerEl.getBoundingClientRect();

verticalLeftPosition = step.isRtl ? boundingRect.right - bubbleBoundingWidth : boundingRect.left;

Expand Down Expand Up @@ -690,6 +710,7 @@
else {
left += utils.getPixelValue(step.xOffset);
}

// VERTICAL OFFSET
if (step.yOffset === 'center') {
top = (boundingRect.top + targetEl.offsetHeight/2) - (bubbleBoundingHeight / 2);
Expand All @@ -704,6 +725,10 @@
left += utils.getScrollLeft();
}

// CONVERT TO CONTAINER COORDINATES
top -= containerBoundingRect.top;
left -= containerBoundingRect.left;

// ACCOUNT FOR FIXED POSITION ELEMENTS
el.style.position = (step.fixedElement ? 'fixed' : 'absolute');

Expand Down Expand Up @@ -1065,7 +1090,7 @@
self = this,
resizeCooldown = false, // for updating after window resize
onWinResize,
appendToBody,
appendToContainer,
children,
numChildren,
node,
Expand Down Expand Up @@ -1134,35 +1159,35 @@
//Hide the bubble by default
this.hide();

//Finally, append our new bubble to body once the DOM is ready.
// Finally, append our new bubble to the container once the DOM is ready.

if (utils.documentIsReady()) {
document.body.appendChild(el);
utils.getContainer(opt).appendChild(el);
}
else {
// Moz, webkit, Opera
if (document.addEventListener) {
appendToBody = function() {
document.removeEventListener('DOMContentLoaded', appendToBody);
window.removeEventListener('load', appendToBody);

document.body.appendChild(el);
appendToContainer = function() {
document.removeEventListener('DOMContentLoaded', appendToContainer);
window.removeEventListener('load', appendToContainer);
utils.getContainer(opt).appendChild(el);
};

document.addEventListener('DOMContentLoaded', appendToBody, false);
document.addEventListener('DOMContentLoaded', appendToContainer, false);
}
// IE
else {
appendToBody = function() {
appendToContainer = function() {
if (document.readyState === 'complete') {
document.detachEvent('onreadystatechange', appendToBody);
window.detachEvent('onload', appendToBody);
document.body.appendChild(el);
document.detachEvent('onreadystatechange', appendToContainer);
window.detachEvent('onload', appendToContainer);
utils.getContainer(opt).appendChild(el);
}
};

document.attachEvent('onreadystatechange', appendToBody);
document.attachEvent('onreadystatechange', appendToContainer);
}
utils.addEvtListener(window, 'load', appendToBody);
utils.addEvtListener(window, 'load', appendToContainer);
}
}
};
Expand Down Expand Up @@ -1856,7 +1881,7 @@
// loadTour if we are calling startTour directly. (When we call startTour
// from window onLoad handler, we'll use currTour)
if (!currTour) {

// Sanity check! Is there a tour?
if(!tour){
throw new Error('Tour data is required for startTour.');
Expand Down
58 changes: 57 additions & 1 deletion test/js/test.hopscotch.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,62 @@ describe('Hopscotch', function() {
hopscotch.endTour();
});

it('should create a div for the HopscotchBubble and append to the specified container element', function() {
var containerEl = document.createElement('div');
document.body.appendChild(containerEl);
hopscotch.startTour({
id: 'hopscotch-test-tour',
steps: [
{
target: 'shopping-list',
placement: 'left',
title: 'Shopping List',
content: 'It\'s a shopping list'
}
],
container: containerEl
});
expect(document.querySelector('.hopscotch-bubble').parentElement).toEqual(containerEl);
hopscotch.endTour();
});

it('should create a div for the HopscotchBubble and append to the container element specified by ID', function() {
var containerEl = document.createElement('div');
containerEl.id = 'container-element';
document.body.appendChild(containerEl);
hopscotch.startTour({
id: 'hopscotch-test-tour',
steps: [
{
target: 'shopping-list',
placement: 'left',
title: 'Shopping List',
content: 'It\'s a shopping list'
}
],
container: 'container-element'
});
expect(document.querySelector('.hopscotch-bubble').parentElement).toEqual(containerEl);
hopscotch.endTour();
});

it('should create a div for the HopscotchBubble and append to body, as the specified container element does not exist', function() {
hopscotch.startTour({
id: 'hopscotch-test-tour',
steps: [
{
target: 'shopping-list',
placement: 'left',
title: 'Shopping List',
content: 'It\'s a shopping list'
}
],
container: 'no-element'
});
expect(document.querySelector('.hopscotch-bubble').parentElement).toEqual(document.body);
hopscotch.endTour();
});

it('should start the tour at the specified step when a step number is supplied as an argument', function() {
hopscotch.startTour({
id: 'hopscotch-test-tour',
Expand Down Expand Up @@ -211,7 +267,7 @@ describe('Hopscotch', function() {
placement: 'left',
title: 'Dynamic target',
content: 'It comes and goes, talking of Michelangelo'
},
}
]
};

Expand Down

0 comments on commit 0d5a54d

Please sign in to comment.