kamranahmedse / driver.js

A light-weight, no-dependency, vanilla JavaScript engine to drive the user's focus across the page

Home Page:https://driverjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature Request] Lifecycle events

lonix1 opened this issue · comments

There are various events, e.g. for the tour: onDestroyed, and for steps: onNextClick, onPrevClick, onCloseClick.

But they're not useful for a reasonably complex page. I needed events like these:

  • onTourStarting
  • onTourStopping
  • onStepActivating
  • onStepDeactivating

Those would be more robust and cover the important cases: before/after the tour and before/after each step. That would also work well with async use cases.

Here is my workaround until (hopefully) such events would be natively supported. The trick is to repurpose the onPrevClick, onNextClick, onCloseClick and onDestroyed events.

const driver = window.driver.js.driver;
const driverObj = driver({

  onPrevClick: function(element, step, options) {
    let callback = function() { if (driverObj.hasPreviousStep() !== undefined) driverObj.movePrevious(); else driverObj.destroy(); };  // workaround for bug https://github.com/kamranahmedse/driver.js/issues/492
    if (typeof onStepDeactivating !== 'undefined') {
      onStepDeactivating(driverObj.getActiveIndex(), function () {
        if (typeof onStepActivating !== 'undefined' && !driverObj.isFirstStep()) {
          onStepActivating(driverObj.getActiveIndex() - 1, callback);
        }
        else {
          callback();
        }
      });
    }
    else if (typeof onStepActivating !== 'undefined' && !driverObj.isFirstStep()) {
      onStepActivating(driverObj.getActiveIndex() - 1, callback);
    }
    else {
      callback();
    }
  },

  onNextClick: function(element, step, options) {
    let callback = function() { if (driverObj.hasNextStep() !== undefined) driverObj.moveNext(); else driverObj.destroy(); };  // workaround for bug https://github.com/kamranahmedse/driver.js/issues/492
    if (typeof onStepDeactivating !== 'undefined') {
      onStepDeactivating(driverObj.getActiveIndex(), function () {
        if (typeof onStepActivating !== 'undefined' && !driverObj.isLastStep()) {
          onStepActivating(driverObj.getActiveIndex() + 1, callback);
        }
        else {
          callback();
        }
      });
    }
    else if (typeof onStepActivating !== 'undefined' && !driverObj.isLastStep()) {
      onStepActivating(driverObj.getActiveIndex() + 1, callback);
    }
    else {
      callback();
    }
  },

  onCloseClick: function (element, step, options) {
    let callback = function() { driverObj.destroy(); };
    if (typeof onStepDeactivating !== 'undefined') {
      onStepDeactivating(driverObj.getActiveIndex(), callback);
    }
    else {
      callback();
    }
  },

  onDestroyed: function(element, step, options) {
    if (typeof onTourStopped !== 'undefined') {
      onTourStopped();
    }
  },

});


let callbackTourStarting = function() { driverObj.drive(); };
if (typeof onTourStarting !== 'undefined') {
  onTourStarting(callbackTourStarting);
}
else {
  callbackTourStarting();
}

I use the CDN scripts on a server-rendered site, so I use the workaround like so:

<script>
  function onTourStarting(callback) {
    callback();
  }

  function onStepActivating(activeIndex, callback) {
    if (activeIndex === 3) {
      loadSomething();
      callback();
    }
    else if (activeIndex === 7) {
      doAsyncFoo(function() {
        callback();
      });
    }
    else {
      callback();
    }
  }

  function onStepDeactivating(activeIndex, callback) {
    if (activeIndex === 3) {
      reset();
    }
    callback();
  }

  function onTourStopped() {
    cleanup();
  }
</script>

That works really well, and as you can see in the second code block it exposes a very friendly API for callers.

But it would be nice if such events would be exposed natively by the library.

(If someone has a neater workaround, please post it below.)