nbot

A clone of the eBot by @deStrO fully based on node.js with build in Web Page - WIP
git clone git://archive.git.mtrnord.blog/MTRNord/nbot.git
Log | Files | Refs | README | LICENSE

bootstrap-tour.js (27961B)


      1 /* ========================================================================
      2  * bootstrap-tour - v0.10.1
      3  * http://bootstraptour.com
      4  * ========================================================================
      5  * Copyright 2012-2013 Ulrich Sossou
      6  *
      7  * ========================================================================
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *     http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  * ========================================================================
     20  */
     21 
     22 (function($, window) {
     23   var Tour, document;
     24   document = window.document;
     25   Tour = (function() {
     26     function Tour(options) {
     27       var storage;
     28       try {
     29         storage = window.localStorage;
     30       } catch (_error) {
     31         storage = false;
     32       }
     33       this._options = $.extend({
     34         name: 'tour',
     35         steps: [],
     36         container: 'body',
     37         autoscroll: true,
     38         keyboard: true,
     39         storage: storage,
     40         debug: false,
     41         backdrop: false,
     42         backdropPadding: 0,
     43         redirect: true,
     44         orphan: false,
     45         duration: false,
     46         delay: false,
     47         basePath: '',
     48         template: '<div class="popover" role="tooltip"> <div class="arrow"></div> <h3 class="popover-title"></h3> <div class="popover-content"></div> <div class="popover-navigation"> <div class="btn-group"> <button class="btn btn-sm btn-default" data-role="prev">&laquo; Prev</button> <button class="btn btn-sm btn-default" data-role="next">Next &raquo;</button> <button class="btn btn-sm btn-default" data-role="pause-resume" data-pause-text="Pause" data-resume-text="Resume">Pause</button> </div> <button class="btn btn-sm btn-default" data-role="end">End tour</button> </div> </div>',
     49         afterSetState: function(key, value) {},
     50         afterGetState: function(key, value) {},
     51         afterRemoveState: function(key) {},
     52         onStart: function(tour) {},
     53         onEnd: function(tour) {},
     54         onShow: function(tour) {},
     55         onShown: function(tour) {},
     56         onHide: function(tour) {},
     57         onHidden: function(tour) {},
     58         onNext: function(tour) {},
     59         onPrev: function(tour) {},
     60         onPause: function(tour, duration) {},
     61         onResume: function(tour, duration) {}
     62       }, options);
     63       this._force = false;
     64       this._inited = false;
     65       this.backdrop = {
     66         overlay: null,
     67         $element: null,
     68         $background: null,
     69         backgroundShown: false,
     70         overlayElementShown: false
     71       };
     72       this;
     73     }
     74 
     75     Tour.prototype.addSteps = function(steps) {
     76       var step, _i, _len;
     77       for (_i = 0, _len = steps.length; _i < _len; _i++) {
     78         step = steps[_i];
     79         this.addStep(step);
     80       }
     81       return this;
     82     };
     83 
     84     Tour.prototype.addStep = function(step) {
     85       this._options.steps.push(step);
     86       return this;
     87     };
     88 
     89     Tour.prototype.getStep = function(i) {
     90       if (this._options.steps[i] != null) {
     91         return $.extend({
     92           id: "step-" + i,
     93           path: '',
     94           placement: 'right',
     95           title: '',
     96           content: '<p></p>',
     97           next: i === this._options.steps.length - 1 ? -1 : i + 1,
     98           prev: i - 1,
     99           animation: true,
    100           container: this._options.container,
    101           autoscroll: this._options.autoscroll,
    102           backdrop: this._options.backdrop,
    103           backdropPadding: this._options.backdropPadding,
    104           redirect: this._options.redirect,
    105           orphan: this._options.orphan,
    106           duration: this._options.duration,
    107           delay: this._options.delay,
    108           template: this._options.template,
    109           onShow: this._options.onShow,
    110           onShown: this._options.onShown,
    111           onHide: this._options.onHide,
    112           onHidden: this._options.onHidden,
    113           onNext: this._options.onNext,
    114           onPrev: this._options.onPrev,
    115           onPause: this._options.onPause,
    116           onResume: this._options.onResume
    117         }, this._options.steps[i]);
    118       }
    119     };
    120 
    121     Tour.prototype.init = function(force) {
    122       this._force = force;
    123       if (this.ended()) {
    124         this._debug('Tour ended, init prevented.');
    125         return this;
    126       }
    127       this.setCurrentStep();
    128       this._initMouseNavigation();
    129       this._initKeyboardNavigation();
    130       this._onResize((function(_this) {
    131         return function() {
    132           return _this.showStep(_this._current);
    133         };
    134       })(this));
    135       if (this._current !== null) {
    136         this.showStep(this._current);
    137       }
    138       this._inited = true;
    139       return this;
    140     };
    141 
    142     Tour.prototype.start = function(force) {
    143       var promise;
    144       if (force == null) {
    145         force = false;
    146       }
    147       if (!this._inited) {
    148         this.init(force);
    149       }
    150       if (this._current === null) {
    151         promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
    152         this._callOnPromiseDone(promise, this.showStep, 0);
    153       }
    154       return this;
    155     };
    156 
    157     Tour.prototype.next = function() {
    158       var promise;
    159       promise = this.hideStep(this._current);
    160       return this._callOnPromiseDone(promise, this._showNextStep);
    161     };
    162 
    163     Tour.prototype.prev = function() {
    164       var promise;
    165       promise = this.hideStep(this._current);
    166       return this._callOnPromiseDone(promise, this._showPrevStep);
    167     };
    168 
    169     Tour.prototype.goTo = function(i) {
    170       var promise;
    171       promise = this.hideStep(this._current);
    172       return this._callOnPromiseDone(promise, this.showStep, i);
    173     };
    174 
    175     Tour.prototype.end = function() {
    176       var endHelper, promise;
    177       endHelper = (function(_this) {
    178         return function(e) {
    179           $(document).off("click.tour-" + _this._options.name);
    180           $(document).off("keyup.tour-" + _this._options.name);
    181           $(window).off("resize.tour-" + _this._options.name);
    182           _this._setState('end', 'yes');
    183           _this._inited = false;
    184           _this._force = false;
    185           _this._clearTimer();
    186           if (_this._options.onEnd != null) {
    187             return _this._options.onEnd(_this);
    188           }
    189         };
    190       })(this);
    191       promise = this.hideStep(this._current);
    192       return this._callOnPromiseDone(promise, endHelper);
    193     };
    194 
    195     Tour.prototype.ended = function() {
    196       return !this._force && !!this._getState('end');
    197     };
    198 
    199     Tour.prototype.restart = function() {
    200       this._removeState('current_step');
    201       this._removeState('end');
    202       return this.start();
    203     };
    204 
    205     Tour.prototype.pause = function() {
    206       var step;
    207       step = this.getStep(this._current);
    208       if (!(step && step.duration)) {
    209         return this;
    210       }
    211       this._paused = true;
    212       this._duration -= new Date().getTime() - this._start;
    213       window.clearTimeout(this._timer);
    214       this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
    215       if (step.onPause != null) {
    216         return step.onPause(this, this._duration);
    217       }
    218     };
    219 
    220     Tour.prototype.resume = function() {
    221       var step;
    222       step = this.getStep(this._current);
    223       if (!(step && step.duration)) {
    224         return this;
    225       }
    226       this._paused = false;
    227       this._start = new Date().getTime();
    228       this._duration = this._duration || step.duration;
    229       this._timer = window.setTimeout((function(_this) {
    230         return function() {
    231           if (_this._isLast()) {
    232             return _this.next();
    233           } else {
    234             return _this.end();
    235           }
    236         };
    237       })(this), this._duration);
    238       this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
    239       if ((step.onResume != null) && this._duration !== step.duration) {
    240         return step.onResume(this, this._duration);
    241       }
    242     };
    243 
    244     Tour.prototype.hideStep = function(i) {
    245       var hideStepHelper, promise, step;
    246       step = this.getStep(i);
    247       if (!step) {
    248         return;
    249       }
    250       this._clearTimer();
    251       promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
    252       hideStepHelper = (function(_this) {
    253         return function(e) {
    254           var $element;
    255           $element = $(step.element);
    256           if (!($element.data('bs.popover') || $element.data('popover'))) {
    257             $element = $('body');
    258           }
    259           $element.popover('destroy').removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element");
    260           if (step.reflex) {
    261             $element.removeClass('tour-step-element-reflex').off("" + (_this._reflexEvent(step.reflex)) + ".tour-" + _this._options.name);
    262           }
    263           if (step.backdrop) {
    264             _this._hideBackdrop();
    265           }
    266           if (step.onHidden != null) {
    267             return step.onHidden(_this);
    268           }
    269         };
    270       })(this);
    271       this._callOnPromiseDone(promise, hideStepHelper);
    272       return promise;
    273     };
    274 
    275     Tour.prototype.showStep = function(i) {
    276       var promise, showStepHelper, skipToPrevious, step;
    277       if (this.ended()) {
    278         this._debug('Tour ended, showStep prevented.');
    279         return this;
    280       }
    281       step = this.getStep(i);
    282       if (!step) {
    283         return;
    284       }
    285       skipToPrevious = i < this._current;
    286       promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
    287       showStepHelper = (function(_this) {
    288         return function(e) {
    289           var current_path, path, showPopoverAndOverlay;
    290           _this.setCurrentStep(i);
    291           path = (function() {
    292             switch ({}.toString.call(step.path)) {
    293               case '[object Function]':
    294                 return step.path();
    295               case '[object String]':
    296                 return this._options.basePath + step.path;
    297               default:
    298                 return step.path;
    299             }
    300           }).call(_this);
    301           current_path = [document.location.pathname, document.location.hash].join('');
    302           if (_this._isRedirect(path, current_path)) {
    303             _this._redirect(step, path);
    304             return;
    305           }
    306           if (_this._isOrphan(step)) {
    307             if (!step.orphan) {
    308               _this._debug("Skip the orphan step " + (_this._current + 1) + ".\nOrphan option is false and the element does not exist or is hidden.");
    309               if (skipToPrevious) {
    310                 _this._showPrevStep();
    311               } else {
    312                 _this._showNextStep();
    313               }
    314               return;
    315             }
    316             _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
    317           }
    318           if (step.backdrop) {
    319             _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
    320           }
    321           showPopoverAndOverlay = function() {
    322             if (_this.getCurrentStep() !== i) {
    323               return;
    324             }
    325             if ((step.element != null) && step.backdrop) {
    326               _this._showOverlayElement(step);
    327             }
    328             _this._showPopover(step, i);
    329             if (step.onShown != null) {
    330               step.onShown(_this);
    331             }
    332             return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length);
    333           };
    334           if (step.autoscroll) {
    335             _this._scrollIntoView(step.element, showPopoverAndOverlay);
    336           } else {
    337             showPopoverAndOverlay();
    338           }
    339           if (step.duration) {
    340             return _this.resume();
    341           }
    342         };
    343       })(this);
    344       if (step.delay) {
    345         this._debug("Wait " + step.delay + " milliseconds to show the step " + (this._current + 1));
    346         window.setTimeout((function(_this) {
    347           return function() {
    348             return _this._callOnPromiseDone(promise, showStepHelper);
    349           };
    350         })(this), step.delay);
    351       } else {
    352         this._callOnPromiseDone(promise, showStepHelper);
    353       }
    354       return promise;
    355     };
    356 
    357     Tour.prototype.getCurrentStep = function() {
    358       return this._current;
    359     };
    360 
    361     Tour.prototype.setCurrentStep = function(value) {
    362       if (value != null) {
    363         this._current = value;
    364         this._setState('current_step', value);
    365       } else {
    366         this._current = this._getState('current_step');
    367         this._current = this._current === null ? null : parseInt(this._current, 10);
    368       }
    369       return this;
    370     };
    371 
    372     Tour.prototype._setState = function(key, value) {
    373       var e, keyName;
    374       if (this._options.storage) {
    375         keyName = "" + this._options.name + "_" + key;
    376         try {
    377           this._options.storage.setItem(keyName, value);
    378         } catch (_error) {
    379           e = _error;
    380           if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
    381             this._debug('LocalStorage quota exceeded. State storage failed.');
    382           }
    383         }
    384         return this._options.afterSetState(keyName, value);
    385       } else {
    386         if (this._state == null) {
    387           this._state = {};
    388         }
    389         return this._state[key] = value;
    390       }
    391     };
    392 
    393     Tour.prototype._removeState = function(key) {
    394       var keyName;
    395       if (this._options.storage) {
    396         keyName = "" + this._options.name + "_" + key;
    397         this._options.storage.removeItem(keyName);
    398         return this._options.afterRemoveState(keyName);
    399       } else {
    400         if (this._state != null) {
    401           return delete this._state[key];
    402         }
    403       }
    404     };
    405 
    406     Tour.prototype._getState = function(key) {
    407       var keyName, value;
    408       if (this._options.storage) {
    409         keyName = "" + this._options.name + "_" + key;
    410         value = this._options.storage.getItem(keyName);
    411       } else {
    412         if (this._state != null) {
    413           value = this._state[key];
    414         }
    415       }
    416       if (value === void 0 || value === 'null') {
    417         value = null;
    418       }
    419       this._options.afterGetState(key, value);
    420       return value;
    421     };
    422 
    423     Tour.prototype._showNextStep = function() {
    424       var promise, showNextStepHelper, step;
    425       step = this.getStep(this._current);
    426       showNextStepHelper = (function(_this) {
    427         return function(e) {
    428           return _this.showStep(step.next);
    429         };
    430       })(this);
    431       promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0);
    432       return this._callOnPromiseDone(promise, showNextStepHelper);
    433     };
    434 
    435     Tour.prototype._showPrevStep = function() {
    436       var promise, showPrevStepHelper, step;
    437       step = this.getStep(this._current);
    438       showPrevStepHelper = (function(_this) {
    439         return function(e) {
    440           return _this.showStep(step.prev);
    441         };
    442       })(this);
    443       promise = this._makePromise(step.onPrev != null ? step.onPrev(this) : void 0);
    444       return this._callOnPromiseDone(promise, showPrevStepHelper);
    445     };
    446 
    447     Tour.prototype._debug = function(text) {
    448       if (this._options.debug) {
    449         return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
    450       }
    451     };
    452 
    453     Tour.prototype._isRedirect = function(path, currentPath) {
    454       return (path != null) && path !== '' && (({}.toString.call(path) === '[object RegExp]' && !path.test(currentPath)) || ({}.toString.call(path) === '[object String]' && path.replace(/\?.*$/, '').replace(/\/?$/, '') !== currentPath.replace(/\/?$/, '')));
    455     };
    456 
    457     Tour.prototype._redirect = function(step, path) {
    458       if ($.isFunction(step.redirect)) {
    459         return step.redirect.call(this, path);
    460       } else if (step.redirect === true) {
    461         this._debug("Redirect to " + path);
    462         return document.location.href = path;
    463       }
    464     };
    465 
    466     Tour.prototype._isOrphan = function(step) {
    467       return (step.element == null) || !$(step.element).length || $(step.element).is(':hidden') && ($(step.element)[0].namespaceURI !== 'http://www.w3.org/2000/svg');
    468     };
    469 
    470     Tour.prototype._isLast = function() {
    471       return this._current < this._options.steps.length - 1;
    472     };
    473 
    474     Tour.prototype._showPopover = function(step, i) {
    475       var $element, $tip, isOrphan, options;
    476       $(".tour-" + this._options.name).remove();
    477       options = $.extend({}, this._options);
    478       isOrphan = this._isOrphan(step);
    479       step.template = this._template(step, i);
    480       if (isOrphan) {
    481         step.element = 'body';
    482         step.placement = 'top';
    483       }
    484       $element = $(step.element);
    485       $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
    486       if (step.options) {
    487         $.extend(options, step.options);
    488       }
    489       if (step.reflex && !isOrphan) {
    490         $element.addClass('tour-step-element-reflex');
    491         $element.off("" + (this._reflexEvent(step.reflex)) + ".tour-" + this._options.name);
    492         $element.on("" + (this._reflexEvent(step.reflex)) + ".tour-" + this._options.name, (function(_this) {
    493           return function() {
    494             if (_this._isLast()) {
    495               return _this.next();
    496             } else {
    497               return _this.end();
    498             }
    499           };
    500         })(this));
    501       }
    502       $element.popover({
    503         placement: step.placement,
    504         trigger: 'manual',
    505         title: step.title,
    506         content: step.content,
    507         html: true,
    508         animation: step.animation,
    509         container: step.container,
    510         template: step.template,
    511         selector: step.element
    512       }).popover('show');
    513       $tip = $element.data('bs.popover') ? $element.data('bs.popover').tip() : $element.data('popover').tip();
    514       $tip.attr('id', step.id);
    515       this._reposition($tip, step);
    516       if (isOrphan) {
    517         return this._center($tip);
    518       }
    519     };
    520 
    521     Tour.prototype._template = function(step, i) {
    522       var $navigation, $next, $prev, $resume, $template;
    523       $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
    524       $navigation = $template.find('.popover-navigation');
    525       $prev = $navigation.find('[data-role="prev"]');
    526       $next = $navigation.find('[data-role="next"]');
    527       $resume = $navigation.find('[data-role="pause-resume"]');
    528       if (this._isOrphan(step)) {
    529         $template.addClass('orphan');
    530       }
    531       $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i);
    532       if (step.prev < 0) {
    533         $prev.addClass('disabled');
    534       }
    535       if (step.next < 0) {
    536         $next.addClass('disabled');
    537       }
    538       if (!step.duration) {
    539         $resume.remove();
    540       }
    541       return $template.clone().wrap('<div>').parent().html();
    542     };
    543 
    544     Tour.prototype._reflexEvent = function(reflex) {
    545       if ({}.toString.call(reflex) === '[object Boolean]') {
    546         return 'click';
    547       } else {
    548         return reflex;
    549       }
    550     };
    551 
    552     Tour.prototype._reposition = function($tip, step) {
    553       var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
    554       offsetWidth = $tip[0].offsetWidth;
    555       offsetHeight = $tip[0].offsetHeight;
    556       tipOffset = $tip.offset();
    557       originalLeft = tipOffset.left;
    558       originalTop = tipOffset.top;
    559       offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
    560       if (offsetBottom < 0) {
    561         tipOffset.top = tipOffset.top + offsetBottom;
    562       }
    563       offsetRight = $('html').outerWidth() - tipOffset.left - $tip.outerWidth();
    564       if (offsetRight < 0) {
    565         tipOffset.left = tipOffset.left + offsetRight;
    566       }
    567       if (tipOffset.top < 0) {
    568         tipOffset.top = 0;
    569       }
    570       if (tipOffset.left < 0) {
    571         tipOffset.left = 0;
    572       }
    573       $tip.offset(tipOffset);
    574       if (step.placement === 'bottom' || step.placement === 'top') {
    575         if (originalLeft !== tipOffset.left) {
    576           return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, 'left');
    577         }
    578       } else {
    579         if (originalTop !== tipOffset.top) {
    580           return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, 'top');
    581         }
    582       }
    583     };
    584 
    585     Tour.prototype._center = function($tip) {
    586       return $tip.css('top', $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
    587     };
    588 
    589     Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
    590       return $tip.find('.arrow').css(position, delta ? 50 * (1 - delta / dimension) + '%' : '');
    591     };
    592 
    593     Tour.prototype._scrollIntoView = function(element, callback) {
    594       var $element, $window, counter, offsetTop, scrollTop, windowHeight;
    595       $element = $(element);
    596       if (!$element.length) {
    597         return callback();
    598       }
    599       $window = $(window);
    600       offsetTop = $element.offset().top;
    601       windowHeight = $window.height();
    602       scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
    603       this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
    604       counter = 0;
    605       return $('body, html').stop(true, true).animate({
    606         scrollTop: Math.ceil(scrollTop)
    607       }, (function(_this) {
    608         return function() {
    609           if (++counter === 2) {
    610             callback();
    611             return _this._debug("Scroll into view.\nAnimation end element offset: " + ($element.offset().top) + ".\nWindow height: " + ($window.height()) + ".");
    612           }
    613         };
    614       })(this));
    615     };
    616 
    617     Tour.prototype._onResize = function(callback, timeout) {
    618       return $(window).on("resize.tour-" + this._options.name, function() {
    619         clearTimeout(timeout);
    620         return timeout = setTimeout(callback, 100);
    621       });
    622     };
    623 
    624     Tour.prototype._initMouseNavigation = function() {
    625       var _this;
    626       _this = this;
    627       return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']", (function(_this) {
    628         return function(e) {
    629           e.preventDefault();
    630           return _this.next();
    631         };
    632       })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']", (function(_this) {
    633         return function(e) {
    634           e.preventDefault();
    635           return _this.prev();
    636         };
    637       })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) {
    638         return function(e) {
    639           e.preventDefault();
    640           return _this.end();
    641         };
    642       })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) {
    643         var $this;
    644         e.preventDefault();
    645         $this = $(this);
    646         $this.text(_this._paused ? $this.data('pause-text') : $this.data('resume-text'));
    647         if (_this._paused) {
    648           return _this.resume();
    649         } else {
    650           return _this.pause();
    651         }
    652       });
    653     };
    654 
    655     Tour.prototype._initKeyboardNavigation = function() {
    656       if (!this._options.keyboard) {
    657         return;
    658       }
    659       return $(document).on("keyup.tour-" + this._options.name, (function(_this) {
    660         return function(e) {
    661           if (!e.which) {
    662             return;
    663           }
    664           switch (e.which) {
    665             case 39:
    666               e.preventDefault();
    667               if (_this._isLast()) {
    668                 return _this.next();
    669               } else {
    670                 return _this.end();
    671               }
    672               break;
    673             case 37:
    674               e.preventDefault();
    675               if (_this._current > 0) {
    676                 return _this.prev();
    677               }
    678               break;
    679             case 27:
    680               e.preventDefault();
    681               return _this.end();
    682           }
    683         };
    684       })(this));
    685     };
    686 
    687     Tour.prototype._makePromise = function(result) {
    688       if (result && $.isFunction(result.then)) {
    689         return result;
    690       } else {
    691         return null;
    692       }
    693     };
    694 
    695     Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
    696       if (promise) {
    697         return promise.then((function(_this) {
    698           return function(e) {
    699             return cb.call(_this, arg);
    700           };
    701         })(this));
    702       } else {
    703         return cb.call(this, arg);
    704       }
    705     };
    706 
    707     Tour.prototype._showBackdrop = function(element) {
    708       if (this.backdrop.backgroundShown) {
    709         return;
    710       }
    711       this.backdrop = $('<div>', {
    712         "class": 'tour-backdrop'
    713       });
    714       this.backdrop.backgroundShown = true;
    715       return $('body').append(this.backdrop);
    716     };
    717 
    718     Tour.prototype._hideBackdrop = function() {
    719       this._hideOverlayElement();
    720       return this._hideBackground();
    721     };
    722 
    723     Tour.prototype._hideBackground = function() {
    724       if (this.backdrop) {
    725         this.backdrop.remove();
    726         this.backdrop.overlay = null;
    727         return this.backdrop.backgroundShown = false;
    728       }
    729     };
    730 
    731     Tour.prototype._showOverlayElement = function(step) {
    732       var $element, elementData;
    733       $element = $(step.element);
    734       if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) {
    735         return;
    736       }
    737       this.backdrop.overlayElementShown = true;
    738       this.backdrop.$element = $element.addClass('tour-step-backdrop');
    739       this.backdrop.$background = $('<div>', {
    740         "class": 'tour-step-background'
    741       });
    742       elementData = {
    743         width: $element.innerWidth(),
    744         height: $element.innerHeight(),
    745         offset: $element.offset()
    746       };
    747       this.backdrop.$background.appendTo('body');
    748       if (step.backdropPadding) {
    749         elementData = this._applyBackdropPadding(step.backdropPadding, elementData);
    750       }
    751       return this.backdrop.$background.width(elementData.width).height(elementData.height).offset(elementData.offset);
    752     };
    753 
    754     Tour.prototype._hideOverlayElement = function() {
    755       if (!this.backdrop.overlayElementShown) {
    756         return;
    757       }
    758       this.backdrop.$element.removeClass('tour-step-backdrop');
    759       this.backdrop.$background.remove();
    760       this.backdrop.$element = null;
    761       this.backdrop.$background = null;
    762       return this.backdrop.overlayElementShown = false;
    763     };
    764 
    765     Tour.prototype._applyBackdropPadding = function(padding, data) {
    766       if (typeof padding === 'object') {
    767         if (padding.top == null) {
    768           padding.top = 0;
    769         }
    770         if (padding.right == null) {
    771           padding.right = 0;
    772         }
    773         if (padding.bottom == null) {
    774           padding.bottom = 0;
    775         }
    776         if (padding.left == null) {
    777           padding.left = 0;
    778         }
    779         data.offset.top = data.offset.top - padding.top;
    780         data.offset.left = data.offset.left - padding.left;
    781         data.width = data.width + padding.left + padding.right;
    782         data.height = data.height + padding.top + padding.bottom;
    783       } else {
    784         data.offset.top = data.offset.top - padding;
    785         data.offset.left = data.offset.left - padding;
    786         data.width = data.width + (padding * 2);
    787         data.height = data.height + (padding * 2);
    788       }
    789       return data;
    790     };
    791 
    792     Tour.prototype._clearTimer = function() {
    793       window.clearTimeout(this._timer);
    794       this._timer = null;
    795       return this._duration = null;
    796     };
    797 
    798     return Tour;
    799 
    800   })();
    801   return window.Tour = Tour;
    802 })(jQuery, window);