diff --git a/build/js/bootstrap-tour.js b/build/js/bootstrap-tour.js
index 7be53ed7..61682ad9 100644
--- a/build/js/bootstrap-tour.js
+++ b/build/js/bootstrap-tour.js
@@ -67,6 +67,10 @@ var bind = function (fn, me) {
delay: false,
basePath: '',
template: '
',
+ showProgressBar: true,
+ showProgressText: true,
+ getProgressBarHTML: null,//function(percent) {},
+ getProgressTextHTML: null,//function(stepNumber, percent, stepCount) {},
afterSetState: function (key, value) {},
afterGetState: function (key, value) {},
afterRemoveState: function (key) {},
@@ -80,7 +84,8 @@ var bind = function (fn, me) {
onPrev: function (tour) {},
onPause: function (tour, duration) {},
onResume: function (tour, duration) {},
- onRedirectError: function (tour) {}
+ onRedirectError: function (tour) {},
+ onElementUnavailable: function (tour, stepNumber) {}
}, options);
this._force = false;
this._inited = false;
@@ -104,6 +109,10 @@ var bind = function (fn, me) {
this._options.steps.push(step);
return this;
};
+
+ Tour.prototype.getStepCount = function() {
+ return this._options.steps.length;
+ }
Tour.prototype.getStep = function (i) {
if (this._options.steps[i] != null) {
@@ -133,6 +142,10 @@ var bind = function (fn, me) {
duration: this._options.duration,
delay: this._options.delay,
template: this._options.template,
+ showProgressBar: this._options.showProgressBar,
+ showProgressText: this._options.showProgressText,
+ getProgressBarHTML: this._options.getProgressBarHTML,
+ getProgressTextHTML: this._options.getProgressTextHTML,
onShow: this._options.onShow,
onShown: this._options.onShown,
onHide: this._options.onHide,
@@ -141,7 +154,8 @@ var bind = function (fn, me) {
onPrev: this._options.onPrev,
onPause: this._options.onPause,
onResume: this._options.onResume,
- onRedirectError: this._options.onRedirectError
+ onRedirectError: this._options.onRedirectError,
+ onElementUnavailable: this._options.onElementUnavailable
}, this._options.steps[i]);
}
};
@@ -165,10 +179,13 @@ var bind = function (fn, me) {
return _this._showPopoverAndOverlay(_this._current);
};
})(this));
- if (this._current !== null) {
+/*
+ // Removed - .init is an unnecessary call, .start force calls .init if tour is not initialized. This code creates conflict
+ // where page has hidden elements, page is reloaded, tour is then forced to start on step N when hidden element is not shown yet
+ if (this._current !== null) {
this.showStep(this._current);
}
- this._inited = true;
+ */ this._inited = true;
return this;
};
@@ -180,10 +197,13 @@ var bind = function (fn, me) {
if (!this._inited) {
this.init(force);
}
- if (this._current === null) {
+
+ // removed if condition - tour should always start when .start is called. Original flow prevented tour from start if _current step index was set (tour already started)
+ //if (this._current === null) {
promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
this._callOnPromiseDone(promise, this.showStep, 0);
- }
+ // }
+
return this;
};
@@ -364,8 +384,15 @@ var bind = function (fn, me) {
showStepHelper = (function (_this) {
return function (e) {
if (_this._isOrphan(step)) {
- if (step.orphan === false) {
+ if (step.orphan === false)
+ {
_this._debug("Skip the orphan step " + (_this._current + 1) + ".\nOrphan option is false and the element does not exist or is hidden.");
+
+ if(typeof(step.onElementUnavailable) == "function")
+ {
+ step.onElementUnavailable(_this, _this._current + 1);
+ }
+
if (skipToPrevious) {
_this._showPrevStep();
} else {
@@ -621,7 +648,7 @@ var bind = function (fn, me) {
if (step.onShown != null) {
step.onShown(this);
}
- return this._debug("Step " + (this._current + 1) + " of " + this._options.steps.length);
+ return this;
};
Tour.prototype._showPopover = function (step, i) {
@@ -629,55 +656,106 @@ var bind = function (fn, me) {
$tip,
isOrphan,
options,
- shouldAddSmart;
- $(".tour-" + this._options.name).remove();
- options = $.extend({}, this._options);
- isOrphan = this._isOrphan(step);
- step.template = this._template(step, i);
- if (isOrphan) {
- step.element = 'body';
- step.placement = 'top';
- }
- $element = $(step.element);
- $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
- if (step.options) {
- $.extend(options, step.options);
- }
- if (step.reflex && !isOrphan) {
- $(step.reflexElement).addClass('tour-step-element-reflex').off((this._reflexEvent(step.reflex)) + ".tour-" + this._options.name).on((this._reflexEvent(step.reflex)) + ".tour-" + this._options.name, (function (_this) {
- return function () {
- if (_this._isLast()) {
- return _this.next();
- } else {
- return _this.end();
- }
- };
- })(this));
+ shouldAddSmart,
+ title,
+ content,
+ percentProgress;
+
+ if($(document).find(".popover.tour-" + this._options.name + ".tour-" + this._options.name + "-" + i).length == 0)
+ {
+ $(".tour-" + this._options.name).remove();
+ options = $.extend({}, this._options);
+ isOrphan = this._isOrphan(step);
+ step.template = this._template(step, i);
+ if (isOrphan) {
+ step.element = 'body';
+ step.placement = 'top';
+ }
+ $element = $(step.element);
+ $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
+ if (step.options) {
+ $.extend(options, step.options);
+ }
+ if (step.reflex && !isOrphan) {
+ $(step.reflexElement).addClass('tour-step-element-reflex').off((this._reflexEvent(step.reflex)) + ".tour-" + this._options.name).on((this._reflexEvent(step.reflex)) + ".tour-" + this._options.name, (function (_this) {
+ return function () {
+ if (_this._isLast()) {
+ return _this.next();
+ } else {
+ return _this.end();
+ }
+ };
+ })(this));
+ }
+
+ shouldAddSmart = step.smartPlacement === true && step.placement.search(/auto/i) === -1;
+
+ title = step.title;
+ content = step.content;
+ percentProgress = parseInt(((i + 1) / this.getStepCount()) * 100);
+
+ if(step.showProgressBar)
+ {
+ if(typeof(step.getProgressBarHTML) == "function")
+ {
+ content = step.getProgressBarHTML(percentProgress) + content;
+ }
+ else
+ {
+ content = '' + content;
+ }
+ }
+
+ if(step.showProgressText)
+ {
+ if(typeof(step.getProgressTextHTML) == "function")
+ {
+ title += step.getProgressTextHTML(i, percentProgress, this.getStepCount());
+ }
+ else
+ {
+ title += '' + (i + 1) + '/' + this.getStepCount() + '';
+ }
+ }
+
+ $element.popover({
+ placement: shouldAddSmart ? "auto " + step.placement : step.placement,
+ trigger: 'manual',
+ title: title,
+ content: content,
+ html: true,
+ animation: step.animation,
+ container: step.container,
+ template: step.template,
+ selector: step.element
+ }).popover('show');
+
+ $tip = $element.data('bs.popover') ? $element.data('bs.popover').tip() : $element.data('popover').tip();
+ $tip.attr('id', step.id);
+ if ($element.css('position') === 'fixed') {
+ $tip.css('position', 'fixed');
+ }
+
+ this._debug("Step " + (this._current + 1) + " of " + this._options.steps.length);
}
+ else
+ {
+ if (this._isOrphan(step)) {
+ step.element = 'body';
+ step.placement = 'top';
+ }
- shouldAddSmart = step.smartPlacement === true && step.placement.search(/auto/i) === -1;
-
- $element.popover({
- placement: shouldAddSmart ? "auto " + step.placement : step.placement,
- trigger: 'manual',
- title: step.title,
- content: step.content,
- html: true,
- animation: step.animation,
- container: step.container,
- template: step.template,
- selector: step.element
- }).popover('show');
-
- $tip = $element.data('bs.popover') ? $element.data('bs.popover').tip() : $element.data('popover').tip();
- $tip.attr('id', step.id);
- if ($element.css('position') === 'fixed') {
- $tip.css('position', 'fixed');
+ $element = $(step.element);
+ $tip = $element.data('bs.popover') ? $element.data('bs.popover').tip() : $element.data('popover').tip();
}
- this._reposition($tip, step);
+
if (isOrphan) {
return this._center($tip);
}
+ else
+ {
+ return this._reposition($tip, step);
+ }
};
Tour.prototype._template = function (step, i) {
@@ -738,13 +816,16 @@ var bind = function (fn, me) {
tipOffset;
offsetWidth = $tip[0].offsetWidth;
offsetHeight = $tip[0].offsetHeight;
+
tipOffset = $tip.offset();
originalLeft = tipOffset.left;
originalTop = tipOffset.top;
- offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+
+ offsetBottom = $(document).height() - tipOffset.top - $tip.outerHeight();
if (offsetBottom < 0) {
tipOffset.top = tipOffset.top + offsetBottom;
}
+
offsetRight = $('html').outerWidth() - tipOffset.left - $tip.outerWidth();
if (offsetRight < 0) {
tipOffset.left = tipOffset.left + offsetRight;
@@ -755,7 +836,9 @@ var bind = function (fn, me) {
if (tipOffset.left < 0) {
tipOffset.left = 0;
}
+
$tip.offset(tipOffset);
+
if (step.placement === 'bottom' || step.placement === 'top') {
if (originalLeft !== tipOffset.left) {
return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, 'left');