How to Get Bootstrap Tour to Work with a Jquery Dialog

How do I get Bootstrap Tour to work with a jQuery dialog?

The problem rests in the fact that the jQuery-UI Dialog has created a new stacking context and so changes to the z-index of the #content element will only show up relative to it's current stacking context.

For proof, add the following css, and you'll still see the #content div display above the dialog, which has a z-index of 100. --> i.e. Z-indexes are not absolute! ... jsFiddle

#content { z-index: 0 !important; }

From What No One Told You About Z-Index:

Every stacking context has a single HTML element as its root element. When a new stacking context is formed on an element, that stacking context confines all of its child elements to a particular place in the stacking order. That means that if an element is contained in a stacking context at the bottom of the stacking order, there is no way to get it to appear in front of another element in a different stacking context that is higher in the stacking order, even with a z-index of a billion!

New stacking contexts can be formed on an element in one of three ways:

  • When an element is the root element of a document (the element)
  • When an element has a position value other than static and a z-index value other than auto
  • When an element has an opacity value less than 1

The problem is Bootstrap Tour doesn't really have a good way of identifying this. When they start a tour on an element, they apply:

  • A full screen black tour-backdrop with a z-index of 1009,
  • A white tour-step-background behind the object with a z-index of 1010
  • and apply a z-index to the current tour element of 1011

...but the last z-index has no effect since our object is already in a stacking context. It is just positioned higher than any of the other elements within that stack (which it already was). Incidentally, that's why removing the z-index from ui-front results in the proper appearance because it frees the element from its current stack.


Here's what Bootstrap Tours should be doing, and we'll do manually with DOM manipulation.

The problem is that they are trying to position the elements relative to one another with z-indexes, but anytime the tour object is in a stacking context different from the .tour-step-background and .tour-backdrop, this will fail.

Solution? Place the elements you're generating inside the same stacking context!

Here's a simplified markup tree

  • Body
    • Tour background (normally goes here)
    • New stacking context
      • Tour object
      • Tour background (should go here)

To override this, we'll plugin to the tours onShown method and move the backdrops ourselves:

In JavaScript, when creating a tour, we'll do the following:

var t = new Tour({
backdrop: true,
onShown: function(tour) {
var stepElement = getTourElement(tour);
$(stepElement).after($('.tour-step-background'));
$(stepElement).after($('.tour-backdrop'));
}
});

function getTourElement(tour){
return tour._steps[tour._current].element
}

This uses jQuery's .after() DOM manipulation to move the backdrop to the same stacking context as our tour object.

Also, we'll need to position both our tour backdrop elements as fixed instead of absolute, so they don't try to squeeze inside of our dialog. We can do that with the following CSS:

.tour-step-background, 
.tour-backdrop {
position: fixed;
}

Working Demo in Fiddle

Which should look like this:

demo

Make Bootstrap Tour dialogs draggable

I must have been using draggable on the wrong element because I got it to work in a jsfiddle first and ported that to my real code and it worked:

https://jsfiddle.net/shovas/jzs1uz0d/19/

var tour = new Tour({
element: '#step1',
name: 'tour',
template: function ( stepIndex, step ) {
return "" +
"<div class='popover tour'>" +
" <div class='arrow'></div>" +
" <div class='popover-header'>" +
" <h3 class='popover-title'></h3>" +
" </div>" +
" <div class='popover-content'></div>" +
" <div class='popover-navigation'>" +
" <button class='btn btn-default' data-role='prev'>« Prev</button>" +
" <span data-role='separator'>|</span>" +
" <button class='btn btn-default' data-role='next'>Next »</button>" +
" </div>" +
" <button class='btn btn-default' data-role='end'>End tour</button>" +
"</div>";
},
onShown: function ( tour ) {
console.log('onShown()')
var curStepIndex = tour.getCurrentStep();
var curStep = tour.getStep(curStepIndex);
var targetElementSelector = tour._options.steps[curStepIndex].element;
var targetElement = $(targetElementSelector).get(0);
//$(targetElement).draggable();
$('.popover.tour').draggable({
handle: '.popover-header'
});
},
steps: [
{
element: '#step1',
title: 'Step #1',
content: 'Lorem ipsum dolar sit amet Lorem ipsum dolar sit amet Lorem ipsum dolar sit amet Lorem ipsum dolar sit amet Lorem ipsum dolar sit amet Lorem ipsum dolar sit amet Lorem ipsum dolar sit amet.'
}
]
});
tour.init();
tour.start();

...snip...

How to start bootstrap tour on click? (on wordpress)

I found the problem. A jQuery file from my theme's plugin is conflicting with the bootstrap tour.

Bootstrap Tour Unable to work on dropdown

If you want to add the tour functions to your boostrap dropdown:

  • remove onHidden: function() { ... onShow....
  • add the Bootstrap Tour Methods as action to your dropdown options

If, instead, your problem is to open programmatically from tour action the dropdown you are experiencing a problem: when you hide the third element and show the fourth element you call open and close dropdown concurrently (one after another).

I suggest you to act differently.

Indeed, if the problem consist in opening the dropdown at the end of the tour, you can add at the end of tour creation:

onShow: function(tour) {
var cs = tour.getCurrentStep();
if (cs == 2) { // if last tour step...open the dropdown
setTimeout(function() {
$("#dropdown").addClass("open");
}, 100)
}
}

The snippet (your updated jsfiddle):

//// selecting an option of dropdown do the action....//$('#step4').on('click', function(e) {  switch (e.target.textContent) {    case 'Action':      var cs = tour.getCurrentStep();      if (cs == 3 || tour.ended()) {        tour.end();        tour.restart();      } else {        tour.next();      }      break;    case 'Another action':      // do stuff      break;  }})// Instance the tourvar tour = new Tour({  debug: true,  storage: false,  steps: [{    element: "#step1",    title: "Settings",    content: "Content of settings",    placement: "bottom"  }, {    element: "#step2",    title: "Title of my step",    content: "Content of my step",    placement: "bottom"
}, { element: "#step3", title: "Title of my step", content: "Content of my step", placement: "bottom" }, { element: "#step4", title: "Title of my step1111", content: "Content of my step", placement: "bottom" }], onShow: function(tour) { var cs = tour.getCurrentStep(); if (cs == 2) { setTimeout(function() { $("#dropdown").addClass("open"); }, 100) } }});if (tour.ended() == true) { tour.restart();} else { tour.init(); tour.start();}
ul.nav {  border: 1px solid black;  margin-left: 5px;  display: inline-block;}
#step1 { height: 200px; width: 200px; margin: 10px; background-color: #eeeeee; position: absolute; left: 0; top: 150px;}
#step2 { height: 200px; width: 200px; margin: 10px; background-color: #666666; position: absolute; left: 210px; top: 150px;}
#step3 { height: 200px; width: 200px; margin: 10px; background-color: #1c90f3; position: absolute; left: 420px; top: 150px;}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"><script src="https://code.jquery.com/jquery-2.1.1.min.js"></script><script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/css/bootstrap-tour.min.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-tour/0.11.0/js/bootstrap-tour.min.js"></script>

<div id="dropdown" class="dropdown"> <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> Dropdown <span class="caret"></span> </button> <ul id="step4" class="dropdown-menu" aria-labelledby="dropdownMenu1"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul></div>
<div id=step1></div><div id=step2></div><div id=step3></div>


Related Topics



Leave a reply



Submit