MDL-62497 admin_tool: change user tours from third party lib to core
authorRyan Wyllie <ryan@ryanwyllie.com>
Fri, 13 Jul 2018 02:29:15 +0000 (10:29 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Fri, 19 Jul 2019 06:12:49 +0000 (14:12 +0800)
.eslintignore
.stylelintignore
admin/tool/usertours/amd/build/tour.min.js
admin/tool/usertours/amd/build/tour.min.js.map
admin/tool/usertours/amd/readme_moodle.txt [deleted file]
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/thirdpartylibs.xml [deleted file]

index 4311869..e645472 100644 (file)
@@ -4,7 +4,6 @@
 node_modules/
 vendor/
 admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
-admin/tool/usertours/amd/src/tour.js
 auth/cas/CAS/
 cache/stores/mongodb/MongoDB/
 enrol/lti/ims-blti/
index 218b965..e0b754e 100644 (file)
@@ -5,7 +5,6 @@ theme/classic/style/moodle.css
 node_modules/
 vendor/
 admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
-admin/tool/usertours/amd/src/tour.js
 auth/cas/CAS/
 cache/stores/mongodb/MongoDB/
 enrol/lti/ims-blti/
index 5f96755..dcf72ce 100644 (file)
Binary files a/admin/tool/usertours/amd/build/tour.min.js and b/admin/tool/usertours/amd/build/tour.min.js differ
index 1ff8ed8..9ebad30 100644 (file)
Binary files a/admin/tool/usertours/amd/build/tour.min.js.map and b/admin/tool/usertours/amd/build/tour.min.js.map differ
diff --git a/admin/tool/usertours/amd/readme_moodle.txt b/admin/tool/usertours/amd/readme_moodle.txt
deleted file mode 100644 (file)
index 1fb69a3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-Description of External library imports into Moodle
-
-Flexitour Instructions
-----------------------
-1. Clone https://github.com/andrewnicols/flexitour into an unrelated directory
-2. Copy /build/tour.js to amd/src/tour.js
-3. Open the amd/src/tour.js file and find the AMD module define.
-4. Change the "popper" inclusion to "core/popper"
-5. Update thirdpartylibs.xml
-6. Run `grunt amd`
index 65e48a7..0f9ad94 100644 (file)
-// jshint ignore: start
-(function (root, factory) {
-  if (typeof define === 'function' && define.amd) {
-    // AMD. Register as an anonymous module unless amdModuleId is set
-    define(["jquery","core/popper"], function (a0,b1) {
-      return (root['Tour'] = factory(a0,b1));
-    });
-  } else if (typeof module === 'object' && module.exports) {
-    // Node. Does not work with strict CommonJS, but
-    // only CommonJS-like environments that support module.exports,
-    // like Node.
-    module.exports = factory(require("jquery"),require("popper.js"));
-  } else {
-    root['Tour'] = factory(root["$"],root["Popper"]);
-  }
-}(this, function ($, Popper) {
-
-"use strict";
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * A Tour.
- *
- * @class   Tour
- * @param   {object}    config  The configuration object.
- */
-
-var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
-
-function Tour(config) {
-    this.init(config);
-}
-
-/**
- * The name of the tour.
+ * Manage user tours in Moodle.
  *
- * @property    {String}    tourName
+ * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-Tour.prototype.tourName;
 
-/**
- * The name of the tour storage key.
- *
- * @property    {String}    storageKey
- */
-Tour.prototype.storageKey;
-
-/**
- * The session storage object
- *
- * @property    {Storage}   storage
- */
-Tour.prototype.storage;
+import $ from 'jquery';
+import Popper from 'core/popper';
 
 /**
- * The original configuration as passed into the constructor.
+ * A Tour.
  *
- * @property    {Object}    originalConfiguration
+ * @class Tour
  */
-Tour.prototype.originalConfiguration;
+export default class Tour {
+    /**
+     * @param   {object}    config  The configuration object.
+     */
+    constructor(config) {
+        this.init(config);
+    }
 
-/**
- * The list of step listeners.
- *
- * @property    {Array}     listeners
- */
-Tour.prototype.listeners;
+    /**
+     * Initialise the tour.
+     *
+     * @method  init
+     * @param   {Object}    config  The configuration object.
+     * @chainable
+     * @return {Object} this.
+     */
+    init(config) {
+        // Unset all handlers.
+        this.eventHandlers = {};
 
-/**
- * The list of event handlers.
- *
- * @property    {Object}    eventHandlers
- */
-Tour.prototype.eventHandlers;
+        // Reset the current tour states.
+        this.reset();
 
-/**
- * The list of steps.
- *
- * @property    {Object[]}      steps
- */
-Tour.prototype.steps;
+        // Store the initial configuration.
+        this.originalConfiguration = config || {};
 
-/**
- * The current step node.
- *
- * @property    {jQuery}        currentStepNode
- */
-Tour.prototype.currentStepNode;
+        // Apply configuration.
+        this.configure.apply(this, arguments);
 
-/**
- * The current step number.
- *
- * @property    {Number}        currentStepNumber
- */
-Tour.prototype.currentStepNumber;
+        try {
+            this.storage = window.sessionStorage;
+            this.storageKey = 'tourstate_' + this.tourName;
+        } catch (e) {
+            this.storage = false;
+            this.storageKey = '';
+        }
 
-/**
- * The popper for the current step.
- *
- * @property    {Popper}        currentStepPopper
- */
-Tour.prototype.currentStepPopper;
+        return this;
+    }
 
-/**
- * The config for the current step.
- *
- * @property    {Object}        currentStepConfig
- */
-Tour.prototype.currentStepConfig;
+    /**
+     * Reset the current tour state.
+     *
+     * @method  reset
+     * @chainable
+     * @return {Object} this.
+     */
+    reset() {
+        // Hide the current step.
+        this.hide();
 
-/**
- * The template content.
- *
- * @property    {String}        templateContent
- */
-Tour.prototype.templateContent;
+        // Unset all handlers.
+        this.eventHandlers = [];
 
-/**
- * Initialise the tour.
- *
- * @method  init
- * @param   {Object}    config  The configuration object.
- * @chainable
- */
-Tour.prototype.init = function (config) {
-    // Unset all handlers.
-    this.eventHandlers = {};
+        // Unset all listeners.
+        this.resetStepListeners();
 
-    // Reset the current tour states.
-    this.reset();
+        // Unset the original configuration.
+        this.originalConfiguration = {};
 
-    // Store the initial configuration.
-    this.originalConfiguration = config || {};
+        // Reset the current step number and list of steps.
+        this.steps = [];
 
-    // Apply configuration.
-    this.configure.apply(this, arguments);
+        // Reset the current step number.
+        this.currentStepNumber = 0;
 
-    try {
-        this.storage = window.sessionStorage;
-        this.storageKey = 'tourstate_' + this.tourName;
-    } catch (e) {
-        this.storage = false;
-        this.storageKey = '';
+        return this;
     }
 
-    return this;
-};
-
-/**
- * Reset the current tour state.
- *
- * @method  reset
- * @chainable
- */
-Tour.prototype.reset = function () {
-    // Hide the current step.
-    this.hide();
-
-    // Unset all handlers.
-    this.eventHandlers = [];
-
-    // Unset all listeners.
-    this.resetStepListeners();
-
-    // Unset the original configuration.
-    this.originalConfiguration = {};
-
-    // Reset the current step number and list of steps.
-    this.steps = [];
+    /**
+     * Prepare tour configuration.
+     *
+     * @method  configure
+     * @param {Object} config The configuration object.
+     * @chainable
+     * @return {Object} this.
+     */
+    configure(config) {
+        if (typeof config === 'object') {
+            // Tour name.
+            if (typeof config.tourName !== 'undefined') {
+                this.tourName = config.tourName;
+            }
 
-    // Reset the current step number.
-    this.currentStepNumber = 0;
+            // Set up eventHandlers.
+            if (config.eventHandlers) {
+                for (let eventName in config.eventHandlers) {
+                    config.eventHandlers[eventName].forEach(function(handler) {
+                        this.addEventHandler(eventName, handler);
+                    }, this);
+                }
+            }
 
-    return this;
-};
+            // Reset the step configuration.
+            this.resetStepDefaults(true);
 
-/**
- * Prepare tour configuration.
- *
- * @method  configure
- * @chainable
- */
-Tour.prototype.configure = function (config) {
-    var _this = this;
+            // Configure the steps.
+            if (typeof config.steps === 'object') {
+                this.steps = config.steps;
+            }
 
-    if ((typeof config === 'undefined' ? 'undefined' : _typeof(config)) === 'object') {
-        // Tour name.
-        if (typeof config.tourName !== 'undefined') {
-            this.tourName = config.tourName;
+            if (typeof config.template !== 'undefined') {
+                this.templateContent = config.template;
+            }
         }
 
-        // Set up eventHandlers.
-        if (config.eventHandlers) {
-            (function () {
-                var eventName = void 0;
-                for (eventName in config.eventHandlers) {
-                    config.eventHandlers[eventName].forEach(function (handler) {
-                        this.addEventHandler(eventName, handler);
-                    }, _this);
-                }
-            })();
-        }
+        // Check that we have enough to start the tour.
+        this.checkMinimumRequirements();
 
-        // Reset the step configuration.
-        this.resetStepDefaults(true);
+        return this;
+    }
 
-        // Configure the steps.
-        if (_typeof(config.steps) === 'object') {
-            this.steps = config.steps;
+    /**
+     * Check that the configuration meets the minimum requirements.
+     *
+     * @method  checkMinimumRequirements
+     */
+    checkMinimumRequirements() {
+        // Need a tourName.
+        if (!this.tourName) {
+            throw new Error("Tour Name required");
         }
 
-        if (typeof config.template !== 'undefined') {
-            this.templateContent = config.template;
+        // Need a minimum of one step.
+        if (!this.steps || !this.steps.length) {
+            throw new Error("Steps must be specified");
         }
     }
 
-    // Check that we have enough to start the tour.
-    this.checkMinimumRequirements();
+    /**
+     * Reset step default configuration.
+     *
+     * @method  resetStepDefaults
+     * @param   {Boolean}   loadOriginalConfiguration   Whether to load the original configuration supplied with the Tour.
+     * @chainable
+     * @return {Object} this.
+     */
+    resetStepDefaults(loadOriginalConfiguration) {
+        if (typeof loadOriginalConfiguration === 'undefined') {
+            loadOriginalConfiguration = true;
+        }
 
-    return this;
-};
+        this.stepDefaults = {};
+        if (!loadOriginalConfiguration || typeof this.originalConfiguration.stepDefaults === 'undefined') {
+            this.setStepDefaults({});
+        } else {
+            this.setStepDefaults(this.originalConfiguration.stepDefaults);
+        }
 
-/**
- * Check that the configuration meets the minimum requirements.
- *
- * @method  checkMinimumRequirements
- * @chainable
- */
-Tour.prototype.checkMinimumRequirements = function () {
-    // Need a tourName.
-    if (!this.tourName) {
-        throw new Error("Tour Name required");
+        return this;
     }
 
-    // Need a minimum of one step.
-    if (!this.steps || !this.steps.length) {
-        throw new Error("Steps must be specified");
-    }
-};
+    /**
+     * Set the step defaults.
+     *
+     * @method  setStepDefaults
+     * @param   {Object}    stepDefaults                The step defaults to apply to all steps
+     * @chainable
+     * @return {Object} this.
+     */
+    setStepDefaults(stepDefaults) {
+        if (!this.stepDefaults) {
+            this.stepDefaults = {};
+        }
+        $.extend(
+            this.stepDefaults,
+            {
+                element:        '',
+                placement:      'top',
+                delay:          0,
+                moveOnClick:    false,
+                moveAfterTime:  0,
+                orphan:         false,
+                direction:      1,
+            },
+            stepDefaults
+        );
 
-/**
- * Reset step default configuration.
- *
- * @method  resetStepDefaults
- * @param   {Boolean}   loadOriginalConfiguration   Whether to load the original configuration supplied with the Tour.
- * @chainable
- */
-Tour.prototype.resetStepDefaults = function (loadOriginalConfiguration) {
-    if (typeof loadOriginalConfiguration === 'undefined') {
-        loadOriginalConfiguration = true;
+        return this;
     }
 
-    this.stepDefaults = {};
-    if (!loadOriginalConfiguration || typeof this.originalConfiguration.stepDefaults === 'undefined') {
-        this.setStepDefaults({});
-    } else {
-        this.setStepDefaults(this.originalConfiguration.stepDefaults);
+    /**
+     * Retrieve the current step number.
+     *
+     * @method  getCurrentStepNumber
+     * @return  {Integer}                   The current step number
+     */
+    getCurrentStepNumber() {
+        return parseInt(this.currentStepNumber, 10);
     }
 
-    return this;
-};
-
-/**
- * Set the step defaults.
- *
- * @method  setStepDefaults
- * @param   {Object}    stepDefaults                The step defaults to apply to all steps
- * @chainable
- */
-Tour.prototype.setStepDefaults = function (stepDefaults) {
-    if (!this.stepDefaults) {
-        this.stepDefaults = {};
+    /**
+     * Store the current step number.
+     *
+     * @method  setCurrentStepNumber
+     * @param   {Integer}   stepNumber      The current step number
+     * @chainable
+     */
+    setCurrentStepNumber(stepNumber) {
+        this.currentStepNumber = stepNumber;
+        if (this.storage) {
+            try {
+                this.storage.setItem(this.storageKey, stepNumber);
+            } catch (e) {
+                if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+                    this.storage.removeItem(this.storageKey);
+                }
+            }
+        }
     }
-    $.extend(this.stepDefaults, {
-        element: '',
-        placement: 'top',
-        delay: 0,
-        moveOnClick: false,
-        moveAfterTime: 0,
-        orphan: false,
-        direction: 1
-    }, stepDefaults);
-
-    return this;
-};
 
-/**
- * Retrieve the current step number.
- *
- * @method  getCurrentStepNumber
- * @return  {Integer}                   The current step number
- */
-Tour.prototype.getCurrentStepNumber = function () {
-    return parseInt(this.currentStepNumber, 10);
-};
+    /**
+     * Get the next step number after the currently displayed step.
+     *
+     * @method  getNextStepNumber
+     * @param   {Integer}   stepNumber      The current step number
+     * @return  {Integer}    The next step number to display
+     */
+    getNextStepNumber(stepNumber) {
+        if (typeof stepNumber === 'undefined') {
+            stepNumber = this.getCurrentStepNumber();
+        }
+        let nextStepNumber = stepNumber + 1;
 
-/**
- * Store the current step number.
- *
- * @method  setCurrentStepNumber
- * @param   {Integer}   stepNumber      The current step number
- * @chainable
- */
-Tour.prototype.setCurrentStepNumber = function (stepNumber) {
-    this.currentStepNumber = stepNumber;
-    if (this.storage) {
-        try {
-            this.storage.setItem(this.storageKey, stepNumber);
-        } catch (e) {
-            if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
-                this.storage.removeItem(this.storageKey);
+        // Keep checking the remaining steps.
+        while (nextStepNumber <= this.steps.length) {
+            if (this.isStepPotentiallyVisible(this.getStepConfig(nextStepNumber))) {
+                return nextStepNumber;
             }
+            nextStepNumber++;
         }
-    }
-};
 
-/**
- * Get the next step number after the currently displayed step.
- *
- * @method  getNextStepNumber
- * @return  {Integer}    The next step number to display
- */
-Tour.prototype.getNextStepNumber = function (stepNumber) {
-    if (typeof stepNumber === 'undefined') {
-        stepNumber = this.getCurrentStepNumber();
+        return null;
     }
-    var nextStepNumber = stepNumber + 1;
 
-    // Keep checking the remaining steps.
-    while (nextStepNumber <= this.steps.length) {
-        if (this.isStepPotentiallyVisible(this.getStepConfig(nextStepNumber))) {
-            return nextStepNumber;
+    /**
+     * Get the previous step number before the currently displayed step.
+     *
+     * @method  getPreviousStepNumber
+     * @param   {Integer}   stepNumber      The current step number
+     * @return  {Integer}    The previous step number to display
+     */
+    getPreviousStepNumber(stepNumber) {
+        if (typeof stepNumber === 'undefined') {
+            stepNumber = this.getCurrentStepNumber();
         }
-        nextStepNumber++;
-    }
+        let previousStepNumber = stepNumber - 1;
 
-    return null;
-};
+        // Keep checking the remaining steps.
+        while (previousStepNumber >= 0) {
+            if (this.isStepPotentiallyVisible(this.getStepConfig(previousStepNumber))) {
+                return previousStepNumber;
+            }
+            previousStepNumber--;
+        }
 
-/**
- * Get the previous step number before the currently displayed step.
- *
- * @method  getPreviousStepNumber
- * @return  {Integer}    The previous step number to display
- */
-Tour.prototype.getPreviousStepNumber = function (stepNumber) {
-    if (typeof stepNumber === 'undefined') {
-        stepNumber = this.getCurrentStepNumber();
+        return null;
     }
-    var previousStepNumber = stepNumber - 1;
 
-    // Keep checking the remaining steps.
-    while (previousStepNumber >= 0) {
-        if (this.isStepPotentiallyVisible(this.getStepConfig(previousStepNumber))) {
-            return previousStepNumber;
-        }
-        previousStepNumber--;
+    /**
+     * Is the step the final step number?
+     *
+     * @method  isLastStep
+     * @param   {Integer}   stepNumber  Step number to test
+     * @return  {Boolean}               Whether the step is the final step
+     */
+    isLastStep(stepNumber) {
+        let nextStepNumber = this.getNextStepNumber(stepNumber);
+
+        return nextStepNumber === null;
     }
 
-    return null;
-};
+    /**
+     * Is the step the first step number?
+     *
+     * @method  isFirstStep
+     * @param   {Integer}   stepNumber  Step number to test
+     * @return  {Boolean}               Whether the step is the first step
+     */
+    isFirstStep(stepNumber) {
+        let previousStepNumber = this.getPreviousStepNumber(stepNumber);
+
+        return previousStepNumber === null;
+    }
 
-/**
- * Is the step the final step number?
- *
- * @method  isLastStep
- * @param   {Integer}   stepNumber  Step number to test
- * @return  {Boolean}               Whether the step is the final step
- */
-Tour.prototype.isLastStep = function (stepNumber) {
-    var nextStepNumber = this.getNextStepNumber(stepNumber);
+    /**
+     * Is this step potentially visible?
+     *
+     * @method  isStepPotentiallyVisible
+     * @param   {Object}    stepConfig      The step configuration to normalise
+     * @return  {Boolean}               Whether the step is the potentially visible
+     */
+    isStepPotentiallyVisible(stepConfig) {
+        if (!stepConfig) {
+            // Without step config, there can be no step.
+            return false;
+        }
 
-    return nextStepNumber === null;
-};
+        if (this.isStepActuallyVisible(stepConfig)) {
+            // If it is actually visible, it is already potentially visible.
+            return true;
+        }
 
-/**
- * Is the step the first step number?
- *
- * @method  isFirstStep
- * @param   {Integer}   stepNumber  Step number to test
- * @return  {Boolean}               Whether the step is the first step
- */
-Tour.prototype.isFirstStep = function (stepNumber) {
-    var previousStepNumber = this.getPreviousStepNumber(stepNumber);
+        if (typeof stepConfig.orphan !== 'undefined' && stepConfig.orphan) {
+            // Orphan steps have no target. They are always visible.
+            return true;
+        }
 
-    return previousStepNumber === null;
-};
+        if (typeof stepConfig.delay !== 'undefined' && stepConfig.delay) {
+            // Only return true if the activated has not been used yet.
+            return true;
+        }
 
-/**
- * Is this step potentially visible?
- *
- * @method  isStepPotentiallyVisible
- * @param   {Integer}   stepNumber  Step number to test
- * @return  {Boolean}               Whether the step is the potentially visible
- */
-Tour.prototype.isStepPotentiallyVisible = function (stepConfig) {
-    if (!stepConfig) {
-        // Without step config, there can be no step.
+        // Not theoretically, or actually visible.
         return false;
     }
 
-    if (this.isStepActuallyVisible(stepConfig)) {
-        // If it is actually visible, it is already potentially visible.
-        return true;
-    }
-
-    if (typeof stepConfig.orphan !== 'undefined' && stepConfig.orphan) {
-        // Orphan steps have no target. They are always visible.
-        return true;
-    }
-
-    if (typeof stepConfig.delay !== 'undefined' && stepConfig.delay) {
-        // Only return true if the activated has not been used yet.
-        return true;
-    }
+    /**
+     * Is this step actually visible?
+     *
+     * @method  isStepActuallyVisible
+     * @param   {Object}    stepConfig      The step configuration to normalise
+     * @return  {Boolean}               Whether the step is actually visible
+     */
+    isStepActuallyVisible(stepConfig) {
+        if (!stepConfig) {
+            // Without step config, there can be no step.
+            return false;
+        }
 
-    // Not theoretically, or actually visible.
-    return false;
-};
+        let target = this.getStepTarget(stepConfig);
+        if (target && target.length && target.is(':visible')) {
+            // Without a target, there can be no step.
+            return !!target.length;
+        }
 
-/**
- * Is this step actually visible?
- *
- * @method  isStepActuallyVisible
- * @param   {Integer}   stepNumber  Step number to test
- * @return  {Boolean}               Whether the step is actually visible
- */
-Tour.prototype.isStepActuallyVisible = function (stepConfig) {
-    if (!stepConfig) {
-        // Without step config, there can be no step.
         return false;
     }
 
-    var target = this.getStepTarget(stepConfig);
-    if (target && target.length && target.is(':visible')) {
-        // Without a target, there can be no step.
-        return !!target.length;
+    /**
+     * Go to the next step in the tour.
+     *
+     * @method  next
+     * @chainable
+     * @return {Object} this.
+     */
+    next() {
+        return this.gotoStep(this.getNextStepNumber());
     }
 
-    return false;
-};
+    /**
+     * Go to the previous step in the tour.
+     *
+     * @method  previous
+     * @chainable
+     * @return {Object} this.
+     */
+    previous() {
+        return this.gotoStep(this.getPreviousStepNumber(), -1);
+    }
 
-/**
- * Go to the next step in the tour.
- *
- * @method  next
- * @chainable
- */
-Tour.prototype.next = function () {
-    return this.gotoStep(this.getNextStepNumber());
-};
+    /**
+     * Go to the specified step in the tour.
+     *
+     * @method  gotoStep
+     * @param   {Integer}   stepNumber     The step number to display
+     * @param   {Integer}   direction      Next or previous step
+     * @chainable
+     * @return {Object} this.
+     */
+    gotoStep(stepNumber, direction) {
+        if (stepNumber < 0) {
+            return this.endTour();
+        }
 
-/**
- * Go to the previous step in the tour.
- *
- * @method  previous
- * @chainable
- */
-Tour.prototype.previous = function () {
-    return this.gotoStep(this.getPreviousStepNumber(), -1);
-};
+        let stepConfig = this.getStepConfig(stepNumber);
+        if (stepConfig === null) {
+            return this.endTour();
+        }
 
-/**
- * Go to the specified step in the tour.
- *
- * @method  gotoStep
- * @param   {Integer}   stepNumber      The step number to display
- * @chainable
- */
-Tour.prototype.gotoStep = function (stepNumber, direction) {
-    if (stepNumber < 0) {
-        return this.endTour();
+        return this._gotoStep(stepConfig, direction);
     }
 
-    var stepConfig = this.getStepConfig(stepNumber);
-    if (stepConfig === null) {
-        return this.endTour();
-    }
+    _gotoStep(stepConfig, direction) {
+        if (!stepConfig) {
+            return this.endTour();
+        }
 
-    return this._gotoStep(stepConfig, direction);
-};
+        if (typeof stepConfig.delay !== 'undefined' && stepConfig.delay && !stepConfig.delayed) {
+            stepConfig.delayed = true;
+            window.setTimeout(this._gotoStep.bind(this), stepConfig.delay, stepConfig, direction);
 
-Tour.prototype._gotoStep = function (stepConfig, direction) {
-    if (!stepConfig) {
-        return this.endTour();
-    }
+            return this;
+        } else if (!stepConfig.orphan && !this.isStepActuallyVisible(stepConfig)) {
+            let fn = direction == -1 ? 'getPreviousStepNumber' : 'getNextStepNumber';
+            return this.gotoStep(this[fn](stepConfig.stepNumber), direction);
+        }
 
-    if (typeof stepConfig.delay !== 'undefined' && stepConfig.delay && !stepConfig.delayed) {
-        stepConfig.delayed = true;
-        window.setTimeout(this._gotoStep.bind(this), stepConfig.delay, stepConfig, direction);
+        this.hide();
+
+        this.fireEventHandlers('beforeRender', stepConfig);
+        this.renderStep(stepConfig);
+        this.fireEventHandlers('afterRender', stepConfig);
 
         return this;
-    } else if (!stepConfig.orphan && !this.isStepActuallyVisible(stepConfig)) {
-        var fn = direction == -1 ? 'getPreviousStepNumber' : 'getNextStepNumber';
-        return this.gotoStep(this[fn](stepConfig.stepNumber), direction);
     }
 
-    this.hide();
+    /**
+     * Fetch the normalised step configuration for the specified step number.
+     *
+     * @method  getStepConfig
+     * @param   {Integer}   stepNumber      The step number to fetch configuration for
+     * @return  {Object}                    The step configuration
+     */
+    getStepConfig(stepNumber) {
+        if (stepNumber === null || stepNumber < 0 || stepNumber >= this.steps.length) {
+            return null;
+        }
 
-    this.fireEventHandlers('beforeRender', stepConfig);
-    this.renderStep(stepConfig);
-    this.fireEventHandlers('afterRender', stepConfig);
+        // Normalise the step configuration.
+        let stepConfig = this.normalizeStepConfig(this.steps[stepNumber]);
 
-    return this;
-};
+        // Add the stepNumber to the stepConfig.
+        stepConfig = $.extend(stepConfig, {stepNumber: stepNumber});
 
-/**
- * Fetch the normalised step configuration for the specified step number.
- *
- * @method  getStepConfig
- * @param   {Integer}   stepNumber      The step number to fetch configuration for
- * @return  {Object}                    The step configuration
- */
-Tour.prototype.getStepConfig = function (stepNumber) {
-    if (stepNumber === null || stepNumber < 0 || stepNumber >= this.steps.length) {
-        return null;
+        return stepConfig;
     }
 
-    // Normalise the step configuration.
-    var stepConfig = this.normalizeStepConfig(this.steps[stepNumber]);
+    /**
+     * Normalise the supplied step configuration.
+     *
+     * @method  normalizeStepConfig
+     * @param   {Object}    stepConfig      The step configuration to normalise
+     * @return  {Object}                    The normalised step configuration
+     */
+    normalizeStepConfig(stepConfig) {
+
+        if (typeof stepConfig.reflex !== 'undefined' && typeof stepConfig.moveAfterClick === 'undefined') {
+            stepConfig.moveAfterClick = stepConfig.reflex;
+        }
 
-    // Add the stepNumber to the stepConfig.
-    stepConfig = $.extend(stepConfig, { stepNumber: stepNumber });
+        if (typeof stepConfig.element !== 'undefined' && typeof stepConfig.target === 'undefined') {
+            stepConfig.target = stepConfig.element;
+        }
 
-    return stepConfig;
-};
+        if (typeof stepConfig.content !== 'undefined' && typeof stepConfig.body === 'undefined') {
+            stepConfig.body = stepConfig.content;
+        }
 
-/**
- * Normalise the supplied step configuration.
- *
- * @method  normalizeStepConfig
- * @param   {Object}    stepConfig      The step configuration to normalise
- * @return  {Object}                    The normalised step configuration
- */
-Tour.prototype.normalizeStepConfig = function (stepConfig) {
+        stepConfig = $.extend({}, this.stepDefaults, stepConfig);
 
-    if (typeof stepConfig.reflex !== 'undefined' && typeof stepConfig.moveAfterClick === 'undefined') {
-        stepConfig.moveAfterClick = stepConfig.reflex;
-    }
+        stepConfig = $.extend({}, {
+            attachTo: stepConfig.target,
+            attachPoint: 'after',
+        }, stepConfig);
 
-    if (typeof stepConfig.element !== 'undefined' && typeof stepConfig.target === 'undefined') {
-        stepConfig.target = stepConfig.element;
-    }
+        if (stepConfig.attachTo) {
+            stepConfig.attachTo = $(stepConfig.attachTo).first();
+        }
 
-    if (typeof stepConfig.content !== 'undefined' && typeof stepConfig.body === 'undefined') {
-        stepConfig.body = stepConfig.content;
+        return stepConfig;
     }
 
-    stepConfig = $.extend({}, this.stepDefaults, stepConfig);
-
-    stepConfig = $.extend({}, {
-        attachTo: stepConfig.target,
-        attachPoint: 'after'
-    }, stepConfig);
+    /**
+     * Fetch the actual step target from the selector.
+     *
+     * This should not be called until after any delay has completed.
+     *
+     * @method  getStepTarget
+     * @param   {Object}    stepConfig      The step configuration
+     * @return  {$}
+     */
+    getStepTarget(stepConfig) {
+        if (stepConfig.target) {
+            return $(stepConfig.target);
+        }
 
-    if (stepConfig.attachTo) {
-        stepConfig.attachTo = $(stepConfig.attachTo).first();
+        return null;
     }
 
-    return stepConfig;
-};
-
-/**
- * Fetch the actual step target from the selector.
- *
- * This should not be called until after any delay has completed.
- *
- * @method  getStepTarget
- * @param   {Object}    stepConfig      The step configuration
- * @return  {$}
- */
-Tour.prototype.getStepTarget = function (stepConfig) {
-    if (stepConfig.target) {
-        return $(stepConfig.target);
-    }
+    /**
+     * Fire any event handlers for the specified event.
+     *
+     * @param   {String}    eventName       The name of the event to handle
+     * @param   {Object}    data            Any data to pass to the event
+     * @chainable
+     * @return {Object} this.
+     */
+    fireEventHandlers(eventName, data) {
+        if (typeof this.eventHandlers[eventName] === 'undefined') {
+            return this;
+        }
 
-    return null;
-};
+        this.eventHandlers[eventName].forEach(function(thisEvent) {
+            thisEvent.call(this, data);
+        }, this);
 
-/**
- * Fire any event handlers for the specified event.
- *
- * @param   {String}    eventName       The name of the event to handle
- * @param   {Object}    data            Any data to pass to the event
- * @chainable
- */
-Tour.prototype.fireEventHandlers = function (eventName, data) {
-    if (typeof this.eventHandlers[eventName] === 'undefined') {
         return this;
     }
 
-    this.eventHandlers[eventName].forEach(function (thisEvent) {
-        thisEvent.call(this, data);
-    }, this);
+    /**
+     * @method addEventHandler
+     * @param  {string}      eventName       The name of the event to listen for
+     * @param  {function}    handler         The event handler to call
+     * @return {Object} this.
+     */
+    addEventHandler(eventName, handler) {
+        if (typeof this.eventHandlers[eventName] === 'undefined') {
+            this.eventHandlers[eventName] = [];
+        }
 
-    return this;
-};
+        this.eventHandlers[eventName].push(handler);
 
-/**
- * @method  addEventHandler
- * @param   string      eventName       The name of the event to listen for
- * @param   function    handler         The event handler to call
- */
-Tour.prototype.addEventHandler = function (eventName, handler) {
-    if (typeof this.eventHandlers[eventName] === 'undefined') {
-        this.eventHandlers[eventName] = [];
+        return this;
     }
 
-    this.eventHandlers[eventName].push(handler);
+    /**
+     * Process listeners for the step being shown.
+     *
+     * @method  processStepListeners
+     * @param   {object}    stepConfig      The configuration for the step
+     * @chainable
+     * @return {Object} this.
+     */
+    processStepListeners(stepConfig) {
+        this.listeners.push(
+        // Next/Previous buttons.
+        {
+            node: this.currentStepNode,
+            args: ['click', '[data-role="next"]', $.proxy(this.next, this)]
+        }, {
+            node: this.currentStepNode,
+            args: ['click', '[data-role="previous"]', $.proxy(this.previous, this)]
+        },
 
-    return this;
-};
+        // Close and end tour buttons.
+        {
+            node: this.currentStepNode,
+            args: ['click', '[data-role="end"]', $.proxy(this.endTour, this)]
+        },
 
-/**
- * Process listeners for the step being shown.
- *
- * @method  processStepListeners
- * @param   {object}    stepConfig      The configuration for the step
- * @chainable
- */
-Tour.prototype.processStepListeners = function (stepConfig) {
-    this.listeners.push(
-    // Next/Previous buttons.
-    {
-        node: this.currentStepNode,
-        args: ['click', '[data-role="next"]', $.proxy(this.next, this)]
-    }, {
-        node: this.currentStepNode,
-        args: ['click', '[data-role="previous"]', $.proxy(this.previous, this)]
-    },
-
-    // Close and end tour buttons.
-    {
-        node: this.currentStepNode,
-        args: ['click', '[data-role="end"]', $.proxy(this.endTour, this)]
-    },
-
-    // Click backdrop and hide tour.
-    {
-        node: $('[data-flexitour="backdrop"]'),
-        args: ['click', $.proxy(this.hide, this)]
-    },
-
-    // Keypresses.
-    {
-        node: $('body'),
-        args: ['keydown', $.proxy(this.handleKeyDown, this)]
-    });
-
-    if (stepConfig.moveOnClick) {
-        var targetNode = this.getStepTarget(stepConfig);
-        this.listeners.push({
-            node: targetNode,
-            args: ['click', $.proxy(function (e) {
-                if ($(e.target).parents('[data-flexitour="container"]').length === 0) {
-                    // Ignore clicks when they are in the flexitour.
-                    window.setTimeout($.proxy(this.next, this), 500);
-                }
-            }, this)]
-        });
-    }
+        // Click backdrop and hide tour.
+        {
+            node: $('[data-flexitour="backdrop"]'),
+            args: ['click', $.proxy(this.hide, this)]
+        },
 
-    this.listeners.forEach(function (listener) {
-        listener.node.on.apply(listener.node, listener.args);
-    });
+        // Keypresses.
+        {
+            node: $('body'),
+            args: ['keydown', $.proxy(this.handleKeyDown, this)]
+        });
 
-    return this;
-};
+        if (stepConfig.moveOnClick) {
+            var targetNode = this.getStepTarget(stepConfig);
+            this.listeners.push({
+                node: targetNode,
+                args: ['click', $.proxy(function(e) {
+                    if ($(e.target).parents('[data-flexitour="container"]').length === 0) {
+                        // Ignore clicks when they are in the flexitour.
+                        window.setTimeout($.proxy(this.next, this), 500);
+                    }
+                }, this)]
+            });
+        }
 
-/**
- * Reset step listeners.
- *
- * @method  resetStepListeners
- * @chainable
- */
-Tour.prototype.resetStepListeners = function () {
-    // Stop listening to all external handlers.
-    if (this.listeners) {
         this.listeners.forEach(function (listener) {
-            listener.node.off.apply(listener.node, listener.args);
+            listener.node.on.apply(listener.node, listener.args);
         });
-    }
-    this.listeners = [];
 
-    return this;
-};
-
-/**
- * The standard step renderer.
- *
- * @method  renderStep
- * @param   {Object}    stepConfig      The step configuration of the step
- * @chainable
- */
-Tour.prototype.renderStep = function (stepConfig) {
-    // Store the current step configuration for later.
-    this.currentStepConfig = stepConfig;
-    this.setCurrentStepNumber(stepConfig.stepNumber);
-
-    // Fetch the template and convert it to a $ object.
-    var template = $(this.getTemplateContent());
-
-    // Title.
-    template.find('[data-placeholder="title"]').html(stepConfig.title);
-
-    // Body.
-    template.find('[data-placeholder="body"]').html(stepConfig.body);
-
-    // Is this the first step?
-    if (this.isFirstStep(stepConfig.stepNumber)) {
-        template.find('[data-role="previous"]').prop('disabled', true);
-    } else {
-        template.find('[data-role="previous"]').prop('disabled', false);
+        return this;
     }
 
-    // Is this the final step?
-    if (this.isLastStep(stepConfig.stepNumber)) {
-        template.find('[data-role="next"]').prop('disabled', true);
-    } else {
-        template.find('[data-role="next"]').prop('disabled', false);
-    }
+    /**
+     * Reset step listeners.
+     *
+     * @method  resetStepListeners
+     * @chainable
+     * @return {Object} this.
+     */
+    resetStepListeners() {
+        // Stop listening to all external handlers.
+        if (this.listeners) {
+            this.listeners.forEach(function(listener) {
+                listener.node.off.apply(listener.node, listener.args);
+            });
+        }
+        this.listeners = [];
 
-    template.find('[data-role="previous"]').attr('role', 'button');
-    template.find('[data-role="next"]').attr('role', 'button');
-    template.find('[data-role="end"]').attr('role', 'button');
+        return this;
+    }
 
-    // Replace the template with the updated version.
-    stepConfig.template = template;
+    /**
+     * The standard step renderer.
+     *
+     * @method  renderStep
+     * @param   {Object}    stepConfig      The step configuration of the step
+     * @chainable
+     * @return {Object} this.
+     */
+    renderStep(stepConfig) {
+        // Store the current step configuration for later.
+        this.currentStepConfig = stepConfig;
+        this.setCurrentStepNumber(stepConfig.stepNumber);
+
+        // Fetch the template and convert it to a $ object.
+        let template = $(this.getTemplateContent());
+
+        // Title.
+        template.find('[data-placeholder="title"]')
+            .html(stepConfig.title);
+
+        // Body.
+        template.find('[data-placeholder="body"]')
+            .html(stepConfig.body);
+
+        // Is this the first step?
+        if (this.isFirstStep(stepConfig.stepNumber)) {
+            template.find('[data-role="previous"]').prop('disabled', true);
+        } else {
+            template.find('[data-role="previous"]').prop('disabled', false);
+        }
 
-    // Add to the page.
-    this.addStepToPage(stepConfig);
+        // Is this the final step?
+        if (this.isLastStep(stepConfig.stepNumber)) {
+            template.find('[data-role="next"]').prop('disabled', true);
+        } else {
+            template.find('[data-role="next"]').prop('disabled', false);
+        }
 
-    // Process step listeners after adding to the page.
-    // This uses the currentNode.
-    this.processStepListeners(stepConfig);
+        template.find('[data-role="previous"]').attr('role', 'button');
+        template.find('[data-role="next"]').attr('role', 'button');
+        template.find('[data-role="end"]').attr('role', 'button');
 
-    return this;
-};
+        // Replace the template with the updated version.
+        stepConfig.template = template;
 
-/**
- * Getter for the template content.
- *
- * @method  getTemplateContent
- * @return  {$}
- */
-Tour.prototype.getTemplateContent = function () {
-    return $(this.templateContent).clone();
-};
+        // Add to the page.
+        this.addStepToPage(stepConfig);
 
-/**
- * Helper to add a step to the page.
- *
- * @method  addStepToPage
- * @param   {Object}    stepConfig      The step configuration of the step
- * @chainable
- */
-Tour.prototype.addStepToPage = function (stepConfig) {
-    var stepContent = stepConfig.template;
+        // Process step listeners after adding to the page.
+        // This uses the currentNode.
+        this.processStepListeners(stepConfig);
 
-    // Create the stepNode from the template data.
-    var currentStepNode = $('<span data-flexitour="container"></span>').html(stepConfig.template).hide();
+        return this;
+    }
 
-    // The scroll animation occurs on the body or html.
-    var animationTarget = $('body, html').stop(true, true);
+    /**
+     * Getter for the template content.
+     *
+     * @method  getTemplateContent
+     * @return  {$}
+     */
+    getTemplateContent() {
+        return $(this.templateContent).clone();
+    }
 
-    if (this.isStepActuallyVisible(stepConfig)) {
-        var targetNode = this.getStepTarget(stepConfig);
+    /**
+     * Helper to add a step to the page.
+     *
+     * @method  addStepToPage
+     * @param   {Object}    stepConfig      The step configuration of the step
+     * @chainable
+     * @return {Object} this.
+     */
+    addStepToPage(stepConfig) {
+        // Create the stepNode from the template data.
+        let currentStepNode = $('<span data-flexitour="container"></span>')
+            .html(stepConfig.template)
+            .hide();
+
+        // The scroll animation occurs on the body or html.
+        let animationTarget = $('body, html')
+            .stop(true, true);
 
-        targetNode.data('flexitour', 'target');
+        if (this.isStepActuallyVisible(stepConfig)) {
+            let targetNode = this.getStepTarget(stepConfig);
 
-        var zIndex = this.calculateZIndex(targetNode);
-        if (zIndex) {
-            stepConfig.zIndex = zIndex + 1;
-        }
+            targetNode.data('flexitour', 'target');
 
-        if (stepConfig.zIndex) {
-            currentStepNode.css('zIndex', stepConfig.zIndex + 1);
-        }
+            let zIndex = this.calculateZIndex(targetNode);
+            if (zIndex) {
+                stepConfig.zIndex = zIndex + 1;
+            }
 
-        // Add the backdrop.
-        this.positionBackdrop(stepConfig);
+            if (stepConfig.zIndex) {
+                currentStepNode.css('zIndex', stepConfig.zIndex + 1);
+            }
 
-        $(document.body).append(currentStepNode);
-        this.currentStepNode = currentStepNode;
+            // Add the backdrop.
+            this.positionBackdrop(stepConfig);
 
-        // Ensure that the step node is positioned.
-        // Some situations mean that the value is not properly calculated without this step.
-        this.currentStepNode.css({
-            top: 0,
-            left: 0
-        });
+            $(document.body).append(currentStepNode);
+            this.currentStepNode = currentStepNode;
 
-        animationTarget.animate({
-            scrollTop: this.calculateScrollTop(stepConfig)
-        }).promise().then(function () {
-            this.positionStep(stepConfig);
-            this.revealStep(stepConfig);
-        }.bind(this));
-    } else if (stepConfig.orphan) {
-        stepConfig.isOrphan = true;
+            // Ensure that the step node is positioned.
+            // Some situations mean that the value is not properly calculated without this step.
+            this.currentStepNode.css({
+                top: 0,
+                left: 0,
+            });
 
-        // This will be appended to the body instead.
-        stepConfig.attachTo = $('body').first();
-        stepConfig.attachPoint = 'append';
+            animationTarget
+                .animate({
+                    scrollTop: this.calculateScrollTop(stepConfig),
+                }).promise().then(function() {
+                        this.positionStep(stepConfig);
+                        this.revealStep(stepConfig);
+                        return;
+                    }.bind(this))
+                    .catch(function() {
+                        // Silently fail.
+                    });
 
-        // Add the backdrop.
-        this.positionBackdrop(stepConfig);
+        } else if (stepConfig.orphan) {
+            stepConfig.isOrphan = true;
+
+            // This will be appended to the body instead.
+            stepConfig.attachTo = $('body').first();
+            stepConfig.attachPoint = 'append';
+
+            // Add the backdrop.
+            this.positionBackdrop(stepConfig);
+
+            // This is an orphaned step.
+            currentStepNode.addClass('orphan');
+
+            // It lives in the body.
+            $(document.body).append(currentStepNode);
+            this.currentStepNode = currentStepNode;
+
+            this.currentStepNode.offset(this.calculateStepPositionInPage());
+            this.currentStepNode.css('position', 'fixed');
+
+            this.currentStepPopper = new Popper(
+                $('body'),
+                this.currentStepNode[0], {
+                    removeOnDestroy: true,
+                    placement: stepConfig.placement + '-start',
+                    arrowElement: '[data-role="arrow"]',
+                    // Empty the modifiers. We've already placed the step and don't want it moved.
+                    modifiers: {
+                        hide: {
+                            enabled: false,
+                        },
+                        applyStyle: {
+                            onLoad: null,
+                            enabled: false,
+                        },
+                    }
+                }
+            );
 
-        // This is an orphaned step.
-        currentStepNode.addClass('orphan');
+            this.revealStep(stepConfig);
+        }
 
-        // It lives in the body.
-        $(document.body).append(currentStepNode);
-        this.currentStepNode = currentStepNode;
+        return this;
+    }
 
-        this.currentStepNode.offset(this.calculateStepPositionInPage());
-        this.currentStepNode.css('position', 'fixed');
+    /**
+     * Make the given step visible.
+     *
+     * @method revealStep
+     * @param {Object} stepConfig The step configuration of the step
+     * @chainable
+     * @return {Object} this.
+     */
+    revealStep(stepConfig) {
+        // Fade the step in.
+        this.currentStepNode.fadeIn('', $.proxy(function() {
+                // Announce via ARIA.
+                this.announceStep(stepConfig);
+
+                // Focus on the current step Node.
+                this.currentStepNode.focus();
+                window.setTimeout($.proxy(function() {
+                    // After a brief delay, focus again.
+                    // There seems to be an issue with Jaws where it only reads the dialogue title initially.
+                    // This second focus helps it to read the full dialogue.
+                    if (this.currentStepNode) {
+                        this.currentStepNode.focus();
+                    }
+                }, this), 100);
 
-        this.currentStepPopper = new Popper($('body'), this.currentStepNode[0], {
-            removeOnDestroy: true,
-            placement: stepConfig.placement + '-start',
-            arrowElement: '[data-role="arrow"]',
-            // Empty the modifiers. We've already placed the step and don't want it moved.
-            modifiers: {
-                hide: {
-                    enabled: false
-                },
-                applyStyle: {
-                    onLoad: null,
-                    enabled: false
-                }
-            }
-        });
+            }, this));
 
-        this.revealStep(stepConfig);
+        return this;
     }
 
-    return this;
-};
-
-Tour.prototype.revealStep = function (stepConfig) {
-    // Fade the step in.
-    this.currentStepNode.fadeIn('', $.proxy(function () {
-        // Announce via ARIA.
-        this.announceStep(stepConfig);
-
-        // Focus on the current step Node.
-        this.currentStepNode.focus();
-        window.setTimeout($.proxy(function () {
-            // After a brief delay, focus again.
-            // There seems to be an issue with Jaws where it only reads the dialogue title initially.
-            // This second focus helps it to read the full dialogue.
-            if (this.currentStepNode) {
-                this.currentStepNode.focus();
+    /**
+     * Helper to announce the step on the page.
+     *
+     * @method  announceStep
+     * @param   {Object}    stepConfig      The step configuration of the step
+     * @chainable
+     * @return {Object} this.
+     */
+    announceStep(stepConfig) {
+        // Setup the step Dialogue as per:
+        // * https://www.w3.org/TR/wai-aria-practices/#dialog_nonmodal
+        // * https://www.w3.org/TR/wai-aria-practices/#dialog_modal
+
+        // Generate an ID for the current step node.
+        let stepId = 'tour-step-' + this.tourName + '-' + stepConfig.stepNumber;
+        this.currentStepNode.attr('id', stepId);
+
+        let bodyRegion = this.currentStepNode.find('[data-placeholder="body"]').first();
+        bodyRegion.attr('id', stepId + '-body');
+        bodyRegion.attr('role', 'document');
+
+        let headerRegion = this.currentStepNode.find('[data-placeholder="title"]').first();
+        headerRegion.attr('id', stepId + '-title');
+        headerRegion.attr('aria-labelledby', stepId + '-body');
+
+        // Generally, a modal dialog has a role of dialog.
+        this.currentStepNode.attr('role', 'dialog');
+        this.currentStepNode.attr('tabindex', 0);
+        this.currentStepNode.attr('aria-labelledby', stepId + '-title');
+        this.currentStepNode.attr('aria-describedby', stepId + '-body');
+
+        // Configure ARIA attributes on the target.
+        let target = this.getStepTarget(stepConfig);
+        if (target) {
+            if (!target.attr('tabindex')) {
+                target.attr('tabindex', 0);
             }
-        }, this), 100);
-    }, this));
 
-    return this;
-};
-
-/**
- * Helper to announce the step on the page.
- *
- * @method  announceStep
- * @param   {Object}    stepConfig      The step configuration of the step
- * @chainable
- */
-Tour.prototype.announceStep = function (stepConfig) {
-    // Setup the step Dialogue as per:
-    // * https://www.w3.org/TR/wai-aria-practices/#dialog_nonmodal
-    // * https://www.w3.org/TR/wai-aria-practices/#dialog_modal
-
-    // Generate an ID for the current step node.
-    var stepId = 'tour-step-' + this.tourName + '-' + stepConfig.stepNumber;
-    this.currentStepNode.attr('id', stepId);
-
-    var bodyRegion = this.currentStepNode.find('[data-placeholder="body"]').first();
-    bodyRegion.attr('id', stepId + '-body');
-    bodyRegion.attr('role', 'document');
-
-    var headerRegion = this.currentStepNode.find('[data-placeholder="title"]').first();
-    headerRegion.attr('id', stepId + '-title');
-    headerRegion.attr('aria-labelledby', stepId + '-body');
-
-    // Generally, a modal dialog has a role of dialog.
-    this.currentStepNode.attr('role', 'dialog');
-    this.currentStepNode.attr('tabindex', 0);
-    this.currentStepNode.attr('aria-labelledby', stepId + '-title');
-    this.currentStepNode.attr('aria-describedby', stepId + '-body');
-
-    // Configure ARIA attributes on the target.
-    var target = this.getStepTarget(stepConfig);
-    if (target) {
-        if (!target.attr('tabindex')) {
-            target.attr('tabindex', 0);
+            target
+                .data('original-describedby', target.attr('aria-describedby'))
+                .attr('aria-describedby', stepId + '-body')
+                ;
         }
 
-        target.data('original-describedby', target.attr('aria-describedby')).attr('aria-describedby', stepId + '-body');
-    }
+        this.accessibilityShow(stepConfig);
 
-    this.accessibilityShow(stepConfig);
+        return this;
+    }
 
-    return this;
-};
+    /**
+     * Handle key down events.
+     *
+     * @method  handleKeyDown
+     * @param   {EventFacade} e
+     */
+    handleKeyDown(e) {
+        let tabbableSelector = 'a[href], link[href], [draggable=true], [contenteditable=true], ';
+        tabbableSelector += ':input:enabled, [tabindex], button:enabled';
+        switch (e.keyCode) {
+            case 27:
+                this.endTour();
+                break;
+
+            // 9 == Tab - trap focus for items with a backdrop.
+            case 9:
+                // Tab must be handled on key up only in this instance.
+                (function() {
+                    if (!this.currentStepConfig.hasBackdrop) {
+                        // Trapping tab focus is only handled for those steps with a backdrop.
+                        return;
+                    }
 
-/**
- * Handle key down events.
- *
- * @method  handleKeyDown
- * @param   {EventFacade} e
- */
-Tour.prototype.handleKeyDown = function (e) {
-    var tabbableSelector = 'a[href], link[href], [draggable=true], [contenteditable=true], :input:enabled, [tabindex], button:enabled';
-    switch (e.keyCode) {
-        case 27:
-            this.endTour();
-            break;
-
-        // 9 == Tab - trap focus for items with a backdrop.
-        case 9:
-            // Tab must be handled on key up only in this instance.
-            (function () {
-                if (!this.currentStepConfig.hasBackdrop) {
-                    // Trapping tab focus is only handled for those steps with a backdrop.
-                    return;
-                }
+                    // Find all tabbable locations.
+                    let activeElement = $(document.activeElement);
+                    let stepTarget = this.getStepTarget(this.currentStepConfig);
+                    let tabbableNodes = $(tabbableSelector);
+                    let dialogContainer = $('span[data-flexitour="container"]');
+                    let currentIndex;
+                    // Filter out element which is not belong to target section or dialogue.
+                    if (stepTarget) {
+                        tabbableNodes = tabbableNodes.filter(function(index, element) {
+                            return stepTarget !== null
+                                && (stepTarget.has(element).length
+                                    || dialogContainer.has(element).length
+                                    || stepTarget.is(element)
+                                    || dialogContainer.is(element));
+                        });
+                    }
 
-                // Find all tabbable locations.
-                var activeElement = $(document.activeElement);
-                var stepTarget = this.getStepTarget(this.currentStepConfig);
-                var tabbableNodes = $(tabbableSelector);
-                var dialogContainer = $('span[data-flexitour="container"]');
-                var currentIndex = void 0;
-                // Filter out element which is not belong to target section or dialogue.
-                if (stepTarget) {
-                    tabbableNodes = tabbableNodes.filter(function (index, element) {
-                        return stepTarget != null && (stepTarget.has(element).length || dialogContainer.has(element).length || stepTarget.is(element) || dialogContainer.is(element));
+                    // Find index of focusing element.
+                    tabbableNodes.each(function(index, element) {
+                        if (activeElement.is(element)) {
+                            currentIndex = index;
+                            return false;
+                        }
+                        // Keep looping.
+                        return true;
                     });
-                }
 
-                // Find index of focusing element.
-                tabbableNodes.each(function (index, element) {
-                    if (activeElement.is(element)) {
-                        currentIndex = index;
-                        return false;
-                    }
-                });
-
-                var nextIndex = void 0;
-                var nextNode = void 0;
-                var focusRelevant = void 0;
-                if (currentIndex != void 0) {
-                    var direction = 1;
-                    if (e.shiftKey) {
-                        direction = -1;
-                    }
-                    nextIndex = currentIndex;
-                    do {
-                        nextIndex += direction;
-                        nextNode = $(tabbableNodes[nextIndex]);
-                    } while (nextNode.length && nextNode.is(':disabled') || nextNode.is(':hidden'));
-                    if (nextNode.length) {
-                        // A new f
-                        focusRelevant = nextNode.closest(stepTarget).length;
-                        focusRelevant = focusRelevant || nextNode.closest(this.currentStepNode).length;
-                    } else {
-                        // Unable to find the target somehow.
-                        focusRelevant = false;
+                    let nextIndex;
+                    let nextNode;
+                    let focusRelevant;
+                    if (currentIndex != void 0) {
+                        let direction = 1;
+                        if (e.shiftKey) {
+                            direction = -1;
+                        }
+                        nextIndex = currentIndex;
+                        do {
+                            nextIndex += direction;
+                            nextNode = $(tabbableNodes[nextIndex]);
+                        } while (nextNode.length && nextNode.is(':disabled') || nextNode.is(':hidden'));
+                        if (nextNode.length) {
+                            // A new f
+                            focusRelevant = nextNode.closest(stepTarget).length;
+                            focusRelevant = focusRelevant || nextNode.closest(this.currentStepNode).length;
+                        } else {
+                            // Unable to find the target somehow.
+                            focusRelevant = false;
+                        }
                     }
-                }
 
-                if (focusRelevant) {
-                    nextNode.focus();
-                } else {
-                    if (e.shiftKey) {
-                        // Focus on the last tabbable node in the step.
-                        this.currentStepNode.find(tabbableSelector).last().focus();
+                    if (focusRelevant) {
+                        nextNode.focus();
                     } else {
-                        if (this.currentStepConfig.isOrphan) {
-                            // Focus on the step - there is no target.
-                            this.currentStepNode.focus();
+                        if (e.shiftKey) {
+                            // Focus on the last tabbable node in the step.
+                            this.currentStepNode.find(tabbableSelector).last().focus();
                         } else {
-                            // Focus on the step target.
-                            stepTarget.focus();
+                            if (this.currentStepConfig.isOrphan) {
+                                // Focus on the step - there is no target.
+                                this.currentStepNode.focus();
+                            } else {
+                                // Focus on the step target.
+                                stepTarget.focus();
+                            }
                         }
                     }
-                }
-                e.preventDefault();
-            }).call(this);
-            break;
+                    e.preventDefault();
+                }).call(this);
+                break;
+        }
     }
-};
 
-/**
- * Start the current tour.
- *
- * @method  startTour
- * @param   {Integer}   startAt     Which step number to start at. If not specified, starts at the last point.
- * @chainable
- */
-Tour.prototype.startTour = function (startAt) {
-    if (this.storage && typeof startAt === 'undefined') {
-        var storageStartValue = this.storage.getItem(this.storageKey);
-        if (storageStartValue) {
-            var storageStartAt = parseInt(storageStartValue, 10);
-            if (storageStartAt <= this.steps.length) {
-                startAt = storageStartAt;
+    /**
+     * Start the current tour.
+     *
+     * @method  startTour
+     * @param   {Integer}   startAt     Which step number to start at. If not specified, starts at the last point.
+     * @chainable
+     * @return {Object} this.
+     */
+    startTour(startAt) {
+        if (this.storage && typeof startAt === 'undefined') {
+            let storageStartValue = this.storage.getItem(this.storageKey);
+            if (storageStartValue) {
+                let storageStartAt = parseInt(storageStartValue, 10);
+                if (storageStartAt <= this.steps.length) {
+                    startAt = storageStartAt;
+                }
             }
         }
-    }
 
-    if (typeof startAt === 'undefined') {
-        startAt = this.getCurrentStepNumber();
-    }
+        if (typeof startAt === 'undefined') {
+            startAt = this.getCurrentStepNumber();
+        }
 
-    this.fireEventHandlers('beforeStart', startAt);
-    this.gotoStep(startAt);
-    this.fireEventHandlers('afterStart', startAt);
+        this.fireEventHandlers('beforeStart', startAt);
+        this.gotoStep(startAt);
+        this.fireEventHandlers('afterStart', startAt);
 
-    return this;
-};
+        return this;
+    }
 
-/**
- * Restart the tour from the beginning, resetting the completionlag.
- *
- * @method  restartTour
- * @chainable
- */
-Tour.prototype.restartTour = function () {
-    return this.startTour(0);
-};
+    /**
+     * Restart the tour from the beginning, resetting the completionlag.
+     *
+     * @method  restartTour
+     * @chainable
+     * @return {Object} this.
+     */
+    restartTour() {
+        return this.startTour(0);
+    }
 
-/**
- * End the current tour.
- *
- * @method  endTour
- * @chainable
- */
-Tour.prototype.endTour = function () {
-    this.fireEventHandlers('beforeEnd');
-
-    if (this.currentStepConfig) {
-        var previousTarget = this.getStepTarget(this.currentStepConfig);
-        if (previousTarget) {
-            if (!previousTarget.attr('tabindex')) {
-                previousTarget.attr('tabindex', '-1');
+    /**
+     * End the current tour.
+     *
+     * @method  endTour
+     * @chainable
+     * @return {Object} this.
+     */
+    endTour() {
+        this.fireEventHandlers('beforeEnd');
+
+        if (this.currentStepConfig) {
+            let previousTarget = this.getStepTarget(this.currentStepConfig);
+            if (previousTarget) {
+                if (!previousTarget.attr('tabindex')) {
+                    previousTarget.attr('tabindex', '-1');
+                }
+                previousTarget.focus();
             }
-            previousTarget.focus();
         }
-    }
-
-    this.hide(true);
 
-    this.fireEventHandlers('afterEnd');
+        this.hide(true);
 
-    return this;
-};
+        this.fireEventHandlers('afterEnd');
 
-/**
- * Hide any currently visible steps.
- *
- * @method hide
- * @chainable
- */
-Tour.prototype.hide = function (transition) {
-    this.fireEventHandlers('beforeHide');
-
-    if (this.currentStepNode && this.currentStepNode.length) {
-        this.currentStepNode.hide();
-        if (this.currentStepPopper) {
-            this.currentStepPopper.destroy();
-        }
+        return this;
     }
 
-    // Restore original target configuration.
-    if (this.currentStepConfig) {
-        var target = this.getStepTarget(this.currentStepConfig);
-        if (target) {
-            if (target.data('original-labelledby')) {
-                target.attr('aria-labelledby', target.data('original-labelledby'));
-            }
-
-            if (target.data('original-describedby')) {
-                target.attr('aria-describedby', target.data('original-describedby'));
-            }
-
-            if (target.data('original-tabindex')) {
-                target.attr('tabindex', target.data('tabindex'));
+    /**
+     * Hide any currently visible steps.
+     *
+     * @method hide
+     * @param {Bool} transition Animate the visibility change
+     * @chainable
+     * @return {Object} this.
+     */
+    hide(transition) {
+        this.fireEventHandlers('beforeHide');
+
+        if (this.currentStepNode && this.currentStepNode.length) {
+            this.currentStepNode.hide();
+            if (this.currentStepPopper) {
+                this.currentStepPopper.destroy();
             }
         }
 
-        // Clear the step configuration.
-        this.currentStepConfig = null;
-    }
+        // Restore original target configuration.
+        if (this.currentStepConfig) {
+            let target = this.getStepTarget(this.currentStepConfig);
+            if (target) {
+                if (target.data('original-labelledby')) {
+                    target.attr('aria-labelledby', target.data('original-labelledby'));
+                }
 
-    var fadeTime = 0;
-    if (transition) {
-        fadeTime = 400;
-    }
+                if (target.data('original-describedby')) {
+                    target.attr('aria-describedby', target.data('original-describedby'));
+                }
+
+                if (target.data('original-tabindex')) {
+                    target.attr('tabindex', target.data('tabindex'));
+                }
+            }
 
-    // Remove the backdrop features.
-    $('[data-flexitour="step-background"]').remove();
-    $('[data-flexitour="step-backdrop"]').removeAttr('data-flexitour');
-    $('[data-flexitour="backdrop"]').fadeOut(fadeTime, function () {
-        $(this).remove();
-    });
-
-    // Remove aria-describedby and tabindex attributes.
-    if (this.currentStepNode && this.currentStepNode.length) {
-        var stepId = this.currentStepNode.attr('id');
-        if (stepId) {
-            var currentStepElement = '[aria-describedby="' + stepId + '-body"]';
-            $(currentStepElement).removeAttr('tabindex');
-            $(currentStepElement).removeAttr('aria-describedby');
+            // Clear the step configuration.
+            this.currentStepConfig = null;
         }
-    }
 
-    // Reset the listeners.
-    this.resetStepListeners();
+        let fadeTime = 0;
+        if (transition) {
+            fadeTime = 400;
+        }
 
-    this.accessibilityHide();
+        // Remove the backdrop features.
+        $('[data-flexitour="step-background"]').remove();
+        $('[data-flexitour="step-backdrop"]').removeAttr('data-flexitour');
+        $('[data-flexitour="backdrop"]').fadeOut(fadeTime, function() {
+            $(this).remove();
+        });
 
-    this.fireEventHandlers('afterHide');
+        // Remove aria-describedby and tabindex attributes.
+        if (this.currentStepNode && this.currentStepNode.length) {
+            let stepId = this.currentStepNode.attr('id');
+            if (stepId) {
+                let currentStepElement = '[aria-describedby="' + stepId + '-body"]';
+                $(currentStepElement).removeAttr('tabindex');
+                $(currentStepElement).removeAttr('aria-describedby');
+            }
+        }
 
-    this.currentStepNode = null;
-    this.currentStepPopper = null;
-    return this;
-};
+        // Reset the listeners.
+        this.resetStepListeners();
 
-/**
- * Show the current steps.
- *
- * @method show
- * @chainable
- */
-Tour.prototype.show = function () {
-    // Show the current step.
-    var startAt = this.getCurrentStepNumber();
+        this.accessibilityHide();
 
-    return this.gotoStep(startAt);
-};
+        this.fireEventHandlers('afterHide');
 
-/**
- * Return the current step node.
- *
- * @method  getStepContainer
- * @return  {jQuery}
- */
-Tour.prototype.getStepContainer = function () {
-    return $(this.currentStepNode);
-};
-
-/**
- * Calculate scrollTop.
- *
- * @method  calculateScrollTop
- * @param   {Object}    stepConfig      The step configuration of the step
- * @return  {Number}
- */
-Tour.prototype.calculateScrollTop = function (stepConfig) {
-    var scrollTop = $(window).scrollTop();
-    var viewportHeight = $(window).height();
-    var targetNode = this.getStepTarget(stepConfig);
-
-    if (stepConfig.placement === 'top') {
-        // If the placement is top, center scroll at the top of the target.
-        scrollTop = targetNode.offset().top - viewportHeight / 2;
-    } else if (stepConfig.placement === 'bottom') {
-        // If the placement is bottom, center scroll at the bottom of the target.
-        scrollTop = targetNode.offset().top + targetNode.height() - viewportHeight / 2;
-    } else if (targetNode.height() <= viewportHeight * 0.8) {
-        // If the placement is left/right, and the target fits in the viewport, centre screen on the target
-        scrollTop = targetNode.offset().top - (viewportHeight - targetNode.height()) / 2;
-    } else {
-        // If the placement is left/right, and the target is bigger than the viewport, set scrollTop to target.top + buffer
-        // and change step attachmentTarget to top+.
-        scrollTop = targetNode.offset().top - viewportHeight * 0.2;
+        this.currentStepNode = null;
+        this.currentStepPopper = null;
+        return this;
     }
 
-    // Never scroll over the top.
-    scrollTop = Math.max(0, scrollTop);
-
-    // Never scroll beyond the bottom.
-    scrollTop = Math.min($(document).height() - viewportHeight, scrollTop);
+    /**
+     * Show the current steps.
+     *
+     * @method show
+     * @chainable
+     * @return {Object} this.
+     */
+    show() {
+        // Show the current step.
+        let startAt = this.getCurrentStepNumber();
+
+        return this.gotoStep(startAt);
+    }
 
-    return Math.ceil(scrollTop);
-};
+    /**
+     * Return the current step node.
+     *
+     * @method  getStepContainer
+     * @return  {jQuery}
+     */
+    getStepContainer() {
+        return $(this.currentStepNode);
+    }
 
-/**
- * Calculate dialogue position for page middle.
- *
- * @method  calculateScrollTop
- * @return  {Number}
- */
-Tour.prototype.calculateStepPositionInPage = function () {
-    var viewportHeight = $(window).height();
-    var stepHeight = this.currentStepNode.height();
+    /**
+     * Calculate scrollTop.
+     *
+     * @method  calculateScrollTop
+     * @param   {Object}    stepConfig      The step configuration of the step
+     * @return  {Number}
+     */
+    calculateScrollTop(stepConfig) {
+        let scrollTop = $(window).scrollTop();
+        let viewportHeight = $(window).height();
+        let targetNode = this.getStepTarget(stepConfig);
+
+        if (stepConfig.placement === 'top') {
+            // If the placement is top, center scroll at the top of the target.
+            scrollTop = targetNode.offset().top - (viewportHeight / 2);
+        } else if (stepConfig.placement === 'bottom') {
+            // If the placement is bottom, center scroll at the bottom of the target.
+            scrollTop = targetNode.offset().top + targetNode.height() - (viewportHeight / 2);
+        } else if (targetNode.height() <= (viewportHeight * 0.8)) {
+            // If the placement is left/right, and the target fits in the viewport, centre screen on the target
+            scrollTop = targetNode.offset().top - ((viewportHeight - targetNode.height()) / 2);
+        } else {
+            // If the placement is left/right, and the target is bigger than the viewport, set scrollTop to target.top + buffer
+            // and change step attachmentTarget to top+.
+            scrollTop = targetNode.offset().top - (viewportHeight * 0.2);
+        }
 
-    var viewportWidth = $(window).width();
-    var stepWidth = this.currentStepNode.width();
+        // Never scroll over the top.
+        scrollTop = Math.max(0, scrollTop);
 
-    return {
-        top: Math.ceil((viewportHeight - stepHeight) / 2),
-        left: Math.ceil((viewportWidth - stepWidth) / 2)
-    };
-};
+        // Never scroll beyond the bottom.
+        scrollTop = Math.min($(document).height() - viewportHeight, scrollTop);
 
-/**
- * Position the step on the page.
- *
- * @method  positionStep
- * @param   {Object}    stepConfig      The step configuration of the step
- * @chainable
- */
-Tour.prototype.positionStep = function (stepConfig) {
-    var content = this.currentStepNode;
-    if (!content || !content.length) {
-        // Unable to find the step node.
-        return this;
+        return Math.ceil(scrollTop);
     }
 
-    var flipBehavior = void 0;
-    switch (stepConfig.placement) {
-        case 'left':
-            flipBehavior = ['left', 'right', 'top', 'bottom'];
-            break;
-        case 'right':
-            flipBehavior = ['right', 'left', 'top', 'bottom'];
-            break;
-        case 'top':
-            flipBehavior = ['top', 'bottom', 'right', 'left'];
-            break;
-        case 'bottom':
-            flipBehavior = ['bottom', 'top', 'right', 'left'];
-            break;
-        default:
-            flipBehavior = 'flip';
-            break;
+    /**
+     * Calculate dialogue position for page middle.
+     *
+     * @method  calculateScrollTop
+     * @return  {Number}
+     */
+    calculateStepPositionInPage() {
+        let viewportHeight = $(window).height();
+        let stepHeight = this.currentStepNode.height();
+
+        let viewportWidth = $(window).width();
+        let stepWidth = this.currentStepNode.width();
+
+        return {
+            top: Math.ceil((viewportHeight - stepHeight) / 2),
+            left: Math.ceil((viewportWidth - stepWidth) / 2)
+        };
     }
 
-    var target = this.getStepTarget(stepConfig);
-    var config = {
-        placement: stepConfig.placement + '-start',
-        removeOnDestroy: true,
-        modifiers: {
-            flip: {
-                behaviour: flipBehavior
-            },
-            arrow: {
-                element: '[data-role="arrow"]'
-            }
-        },
-        onCreate: function onCreate(data) {
-            recalculateArrowPosition(data);
-        },
-        onUpdate: function onUpdate(data) {
-            recalculateArrowPosition(data);
+    /**
+     * Position the step on the page.
+     *
+     * @method  positionStep
+     * @param   {Object}    stepConfig      The step configuration of the step
+     * @chainable
+     * @return {Object} this.
+     */
+    positionStep(stepConfig) {
+        let content = this.currentStepNode;
+        if (!content || !content.length) {
+            // Unable to find the step node.
+            return this;
         }
-    };
-
-    var recalculateArrowPosition = function recalculateArrowPosition(data) {
-        var placement = data.placement.split('-')[0];
-        var isVertical = ['left', 'right'].indexOf(placement) !== -1;
-        var arrowElement = data.instance.popper.querySelector('[data-role="arrow"]');
-        var stepElement = $(data.instance.popper.querySelector('[data-role="flexitour-step"]'));
-        if (isVertical) {
-            var arrowHeight = parseFloat(window.getComputedStyle(arrowElement).height);
-            var arrowOffset = parseFloat(window.getComputedStyle(arrowElement).top);
-            var popperHeight = parseFloat(window.getComputedStyle(data.instance.popper).height);
-            var popperOffset = parseFloat(window.getComputedStyle(data.instance.popper).top);
-            var popperBorderWidth = parseFloat(stepElement.css('borderTopWidth'));
-            var popperBorderRadiusWidth = parseFloat(stepElement.css('borderTopLeftRadius')) * 2;
-            var arrowPos = arrowOffset + arrowHeight / 2;
-            var maxPos = popperHeight + popperOffset - popperBorderWidth - popperBorderRadiusWidth;
-            var minPos = popperOffset + popperBorderWidth + popperBorderRadiusWidth;
-            if (arrowPos >= maxPos || arrowPos <= minPos) {
-                var newArrowPos = 0;
-                if (arrowPos > popperHeight / 2) {
-                    newArrowPos = maxPos - arrowHeight;
-                } else {
-                    newArrowPos = minPos + arrowHeight;
+
+        let flipBehavior;
+        switch (stepConfig.placement) {
+            case 'left':
+                flipBehavior = ['left', 'right', 'top', 'bottom'];
+                break;
+            case 'right':
+                flipBehavior = ['right', 'left', 'top', 'bottom'];
+                break;
+            case 'top':
+                flipBehavior = ['top', 'bottom', 'right', 'left'];
+                break;
+            case 'bottom':
+                flipBehavior = ['bottom', 'top', 'right', 'left'];
+                break;
+            default:
+                flipBehavior = 'flip';
+                break;
+        }
+
+        let target = this.getStepTarget(stepConfig);
+        var config = {
+            placement: stepConfig.placement + '-start',
+            removeOnDestroy: true,
+            modifiers: {
+                flip: {
+                    behaviour: flipBehavior,
+                },
+                arrow: {
+                    element: '[data-role="arrow"]',
+                },
+            },
+            onCreate: function(data) {
+                recalculateArrowPosition(data);
+            },
+            onUpdate: function(data) {
+                recalculateArrowPosition(data);
+            },
+        };
+
+        let recalculateArrowPosition = function(data) {
+            let placement = data.placement.split('-')[0];
+            const isVertical = ['left', 'right'].indexOf(placement) !== -1;
+            const arrowElement = data.instance.popper.querySelector('[data-role="arrow"]');
+            const stepElement = $(data.instance.popper.querySelector('[data-role="flexitour-step"]'));
+            if (isVertical) {
+                let arrowHeight = parseFloat(window.getComputedStyle(arrowElement).height);
+                let arrowOffset = parseFloat(window.getComputedStyle(arrowElement).top);
+                let popperHeight = parseFloat(window.getComputedStyle(data.instance.popper).height);
+                let popperOffset = parseFloat(window.getComputedStyle(data.instance.popper).top);
+                let popperBorderWidth = parseFloat(stepElement.css('borderTopWidth'));
+                let popperBorderRadiusWidth = parseFloat(stepElement.css('borderTopLeftRadius')) * 2;
+                let arrowPos = arrowOffset + (arrowHeight / 2);
+                let maxPos = popperHeight + popperOffset - popperBorderWidth - popperBorderRadiusWidth;
+                let minPos = popperOffset + popperBorderWidth + popperBorderRadiusWidth;
+                if (arrowPos >= maxPos || arrowPos <= minPos) {
+                    let newArrowPos = 0;
+                    if (arrowPos > (popperHeight / 2)) {
+                        newArrowPos = maxPos - arrowHeight;
+                    } else {
+                        newArrowPos = minPos + arrowHeight;
+                    }
+                    $(arrowElement).css('top', newArrowPos);
                 }
-                $(arrowElement).css('top', newArrowPos);
-            }
-        } else {
-            var arrowWidth = parseFloat(window.getComputedStyle(arrowElement).width);
-            var _arrowOffset = parseFloat(window.getComputedStyle(arrowElement).left);
-            var popperWidth = parseFloat(window.getComputedStyle(data.instance.popper).width);
-            var _popperOffset = parseFloat(window.getComputedStyle(data.instance.popper).left);
-            var _popperBorderWidth = parseFloat(stepElement.css('borderTopWidth'));
-            var _popperBorderRadiusWidth = parseFloat(stepElement.css('borderTopLeftRadius')) * 2;
-            var _arrowPos = _arrowOffset + arrowWidth / 2;
-            var _maxPos = popperWidth + _popperOffset - _popperBorderWidth - _popperBorderRadiusWidth;
-            var _minPos = _popperOffset + _popperBorderWidth + _popperBorderRadiusWidth;
-            if (_arrowPos >= _maxPos || _arrowPos <= _minPos) {
-                var _newArrowPos = 0;
-                if (_arrowPos > popperWidth / 2) {
-                    _newArrowPos = _maxPos - arrowWidth;
-                } else {
-                    _newArrowPos = _minPos + arrowWidth;
+            } else {
+                let arrowWidth = parseFloat(window.getComputedStyle(arrowElement).width);
+                let arrowOffset = parseFloat(window.getComputedStyle(arrowElement).left);
+                let popperWidth = parseFloat(window.getComputedStyle(data.instance.popper).width);
+                let popperOffset = parseFloat(window.getComputedStyle(data.instance.popper).left);
+                let popperBorderWidth = parseFloat(stepElement.css('borderTopWidth'));
+                let popperBorderRadiusWidth = parseFloat(stepElement.css('borderTopLeftRadius')) * 2;
+                let arrowPos = arrowOffset + (arrowWidth / 2);
+                let maxPos = popperWidth + popperOffset - popperBorderWidth - popperBorderRadiusWidth;
+                let minPos = popperOffset + popperBorderWidth + popperBorderRadiusWidth;
+                if (arrowPos >= maxPos || arrowPos <= minPos) {
+                    let newArrowPos = 0;
+                    if (arrowPos > (popperWidth / 2)) {
+                        newArrowPos = maxPos - arrowWidth;
+                    } else {
+                        newArrowPos = minPos + arrowWidth;
+                    }
+                    $(arrowElement).css('left', newArrowPos);
                 }
-                $(arrowElement).css('left', _newArrowPos);
             }
+        };
+
+        let background = $('[data-flexitour="step-background"]');
+        if (background.length) {
+            target = background;
         }
-    };
+        this.currentStepPopper = new Popper(target, content[0], config);
 
-    var background = $('[data-flexitour="step-background"]');
-    if (background.length) {
-        target = background;
+        return this;
     }
-    this.currentStepPopper = new Popper(target, content[0], config);
 
-    return this;
-};
+    /**
+     * Add the backdrop.
+     *
+     * @method  positionBackdrop
+     * @param   {Object}    stepConfig      The step configuration of the step
+     * @chainable
+     * @return {Object} this.
+     */
+    positionBackdrop(stepConfig) {
+        if (stepConfig.backdrop) {
+            this.currentStepConfig.hasBackdrop = true;
+            let backdrop = $('<div data-flexitour="backdrop"></div>');
 
-/**
- * Add the backdrop.
- *
- * @method  positionBackdrop
- * @param   {Object}    stepConfig      The step configuration of the step
- * @chainable
- */
-Tour.prototype.positionBackdrop = function (stepConfig) {
-    if (stepConfig.backdrop) {
-        this.currentStepConfig.hasBackdrop = true;
-        var backdrop = $('<div data-flexitour="backdrop"></div>');
-
-        if (stepConfig.zIndex) {
-            if (stepConfig.attachPoint === 'append') {
-                stepConfig.attachTo.append(backdrop);
+            if (stepConfig.zIndex) {
+                if (stepConfig.attachPoint === 'append') {
+                    stepConfig.attachTo.append(backdrop);
+                } else {
+                    backdrop.insertAfter(stepConfig.attachTo);
+                }
             } else {
-                backdrop.insertAfter(stepConfig.attachTo);
+                $('body').append(backdrop);
             }
-        } else {
-            $('body').append(backdrop);
-        }
 
-        if (this.isStepActuallyVisible(stepConfig)) {
-            // The step has a visible target.
-            // Punch a hole through the backdrop.
-            var background = $('<div data-flexitour="step-background"></div>');
+            if (this.isStepActuallyVisible(stepConfig)) {
+                // The step has a visible target.
+                // Punch a hole through the backdrop.
+                let background = $('<div data-flexitour="step-background"></div>');
 
-            var targetNode = this.getStepTarget(stepConfig);
-
-            var buffer = 10;
+                let targetNode = this.getStepTarget(stepConfig);
 
-            var colorNode = targetNode;
-            if (buffer) {
-                colorNode = $('body');
-            }
+                let buffer = 10;
 
-            background.css({
-                width: targetNode.outerWidth() + buffer + buffer,
-                height: targetNode.outerHeight() + buffer + buffer,
-                left: targetNode.offset().left - buffer,
-                top: targetNode.offset().top - buffer,
-                backgroundColor: this.calculateInherittedBackgroundColor(colorNode)
-            });
+                let colorNode = targetNode;
+                if (buffer) {
+                    colorNode = $('body');
+                }
 
-            if (targetNode.offset().left < buffer) {
                 background.css({
-                    width: targetNode.outerWidth() + targetNode.offset().left + buffer,
-                    left: targetNode.offset().left
+                    width: targetNode.outerWidth() + buffer + buffer,
+                    height: targetNode.outerHeight() + buffer + buffer,
+                    left: targetNode.offset().left - buffer,
+                    top: targetNode.offset().top - buffer,
+                    backgroundColor: this.calculateInherittedBackgroundColor(colorNode),
                 });
-            }
 
-            if (targetNode.offset().top < buffer) {
-                background.css({
-                    height: targetNode.outerHeight() + targetNode.offset().top + buffer,
-                    top: targetNode.offset().top
-                });
-            }
+                if (targetNode.offset().left < buffer) {
+                    background.css({
+                        width: targetNode.outerWidth() + targetNode.offset().left + buffer,
+                        left: targetNode.offset().left,
+                    });
+                }
 
-            var targetRadius = targetNode.css('borderRadius');
-            if (targetRadius && targetRadius !== $('body').css('borderRadius')) {
-                background.css('borderRadius', targetRadius);
-            }
+                if (targetNode.offset().top < buffer) {
+                    background.css({
+                        height: targetNode.outerHeight() + targetNode.offset().top + buffer,
+                        top: targetNode.offset().top,
+                    });
+                }
 
-            var targetPosition = this.calculatePosition(targetNode);
-            if (targetPosition === 'fixed') {
-                background.css('top', 0);
-            } else if (targetPosition === 'absolute') {
-                background.css('position', 'fixed');
-            }
+                let targetRadius = targetNode.css('borderRadius');
+                if (targetRadius && targetRadius !== $('body').css('borderRadius')) {
+                    background.css('borderRadius', targetRadius);
+                }
 
-            var fader = background.clone();
-            fader.css({
-                backgroundColor: backdrop.css('backgroundColor'),
-                opacity: backdrop.css('opacity')
-            });
-            fader.attr('data-flexitour', 'step-background-fader');
+                let targetPosition = this.calculatePosition(targetNode);
+                if (targetPosition === 'fixed') {
+                    background.css('top', 0);
+                } else if (targetPosition === 'absolute') {
+                    background.css('position', 'fixed');
+                }
 
-            if (stepConfig.zIndex) {
-                if (stepConfig.attachPoint === 'append') {
-                    stepConfig.attachTo.append(background);
+                let fader = background.clone();
+                fader.css({
+                    backgroundColor: backdrop.css('backgroundColor'),
+                    opacity: backdrop.css('opacity'),
+                });
+                fader.attr('data-flexitour', 'step-background-fader');
+
+                if (stepConfig.zIndex) {
+                    if (stepConfig.attachPoint === 'append') {
+                        stepConfig.attachTo.append(background);
+                    } else {
+                        fader.insertAfter(stepConfig.attachTo);
+                        background.insertAfter(stepConfig.attachTo);
+                    }
                 } else {
-                    fader.insertAfter(stepConfig.attachTo);
-                    background.insertAfter(stepConfig.attachTo);
+                    $('body').append(fader);
+                    $('body').append(background);
                 }
-            } else {
-                $('body').append(fader);
-                $('body').append(background);
-            }
 
-            // Add the backdrop data to the actual target.
-            // This is the part which actually does the work.
-            targetNode.attr('data-flexitour', 'step-backdrop');
+                // Add the backdrop data to the actual target.
+                // This is the part which actually does the work.
+                targetNode.attr('data-flexitour', 'step-backdrop');
 
-            if (stepConfig.zIndex) {
-                backdrop.css('zIndex', stepConfig.zIndex);
-                background.css('zIndex', stepConfig.zIndex + 1);
-                targetNode.css('zIndex', stepConfig.zIndex + 2);
-            }
+                if (stepConfig.zIndex) {
+                    backdrop.css('zIndex', stepConfig.zIndex);
+                    background.css('zIndex', stepConfig.zIndex + 1);
+                    targetNode.css('zIndex', stepConfig.zIndex + 2);
+                }
 
-            fader.fadeOut('2000', function () {
-                $(this).remove();
-            });
+                fader.fadeOut('2000', function() {
+                    $(this).remove();
+                });
+            }
         }
+        return this;
     }
-    return this;
-};
 
-/**
- * Calculate the inheritted z-index.
- *
- * @method  calculateZIndex
- * @param   {jQuery}    elem                        The element to calculate z-index for
- * @return  {Number}                                Calculated z-index
- */
-Tour.prototype.calculateZIndex = function (elem) {
-    elem = $(elem);
-    while (elem.length && elem[0] !== document) {
-        // Ignore z-index if position is set to a value where z-index is ignored by the browser
-        // This makes behavior of this function consistent across browsers
-        // WebKit always returns auto if the element is positioned.
-        var position = elem.css("position");
-        if (position === "absolute" || position === "relative" || position === "fixed") {
-            // IE returns 0 when zIndex is not specified
-            // other browsers return a string
-            // we ignore the case of nested elements with an explicit value of 0
-            // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
-            var value = parseInt(elem.css("zIndex"), 10);
-            if (!isNaN(value) && value !== 0) {
-                return value;
+    /**
+     * Calculate the inheritted z-index.
+     *
+     * @method  calculateZIndex
+     * @param   {jQuery}    elem                        The element to calculate z-index for
+     * @return  {Number}                                Calculated z-index
+     */
+    calculateZIndex(elem) {
+        elem = $(elem);
+        while (elem.length && elem[0] !== document) {
+            // Ignore z-index if position is set to a value where z-index is ignored by the browser
+            // This makes behavior of this function consistent across browsers
+            // WebKit always returns auto if the element is positioned.
+            let position = elem.css("position");
+            if (position === "absolute" || position === "relative" || position === "fixed") {
+                // IE returns 0 when zIndex is not specified
+                // other browsers return a string
+                // we ignore the case of nested elements with an explicit value of 0
+                // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+                let value = parseInt(elem.css("zIndex"), 10);
+                if (!isNaN(value) && value !== 0) {
+                    return value;
+                }
             }
+            elem = elem.parent();
         }
-        elem = elem.parent();
-    }
-
-    return 0;
-};
 
-/**
- * Calculate the inheritted background colour.
- *
- * @method  calculateInherittedBackgroundColor
- * @param   {jQuery}    elem                        The element to calculate colour for
- * @return  {String}                                Calculated background colour
- */
-Tour.prototype.calculateInherittedBackgroundColor = function (elem) {
-    // Use a fake node to compare each element against.
-    var fakeNode = $('<div>').hide();
-    $('body').append(fakeNode);
-    var fakeElemColor = fakeNode.css('backgroundColor');
-    fakeNode.remove();
-
-    elem = $(elem);
-    while (elem.length && elem[0] !== document) {
-        var color = elem.css('backgroundColor');
-        if (color !== fakeElemColor) {
-            return color;
-        }
-        elem = elem.parent();
+        return 0;
     }
 
-    return null;
-};
-
-/**
- * Calculate the inheritted position.
- *
- * @method  calculatePosition
- * @param   {jQuery}    elem                        The element to calculate position for
- * @return  {String}                                Calculated position
- */
-Tour.prototype.calculatePosition = function (elem) {
-    elem = $(elem);
-    while (elem.length && elem[0] !== document) {
-        var position = elem.css('position');
-        if (position !== 'static') {
-            return position;
+    /**
+     * Calculate the inheritted background colour.
+     *
+     * @method  calculateInherittedBackgroundColor
+     * @param   {jQuery}    elem                        The element to calculate colour for
+     * @return  {String}                                Calculated background colour
+     */
+    calculateInherittedBackgroundColor(elem) {
+        // Use a fake node to compare each element against.
+        let fakeNode = $('<div>').hide();
+        $('body').append(fakeNode);
+        let fakeElemColor = fakeNode.css('backgroundColor');
+        fakeNode.remove();
+
+        elem = $(elem);
+        while (elem.length && elem[0] !== document) {
+            let color = elem.css('backgroundColor');
+            if (color !== fakeElemColor) {
+                return color;
+            }
+            elem = elem.parent();
         }
-        elem = elem.parent();
-    }
 
-    return null;
-};
+        return null;
+    }
 
-/**
- * Perform accessibility changes for step shown.
- *
- * This will add aria-hidden="true" to all siblings and parent siblings.
- *
- * @method  accessibilityShow
- */
-Tour.prototype.accessibilityShow = function () {
-    var stateHolder = 'data-has-hidden';
-    var attrName = 'aria-hidden';
-    var hideFunction = function hideFunction(child) {
-        var flexitourRole = child.data('flexitour');
-        if (flexitourRole) {
-            switch (flexitourRole) {
-                case 'container':
-                case 'target':
-                    return;
+    /**
+     * Calculate the inheritted position.
+     *
+     * @method  calculatePosition
+     * @param   {jQuery}    elem                        The element to calculate position for
+     * @return  {String}                                Calculated position
+     */
+    calculatePosition(elem) {
+        elem = $(elem);
+        while (elem.length && elem[0] !== document) {
+            let position = elem.css('position');
+            if (position !== 'static') {
+                return position;
             }
+            elem = elem.parent();
         }
 
-        var hidden = child.attr(attrName);
-        if (!hidden) {
-            child.attr(stateHolder, true);
-            child.attr(attrName, true);
-        }
-    };
-
-    this.currentStepNode.siblings().each(function (index, node) {
-        hideFunction($(node));
-    });
-    this.currentStepNode.parentsUntil('body').siblings().each(function (index, node) {
-        hideFunction($(node));
-    });
-};
+        return null;
+    }
 
-/**
- * Perform accessibility changes for step hidden.
- *
- * This will remove any newly added aria-hidden="true".
- *
- * @method  accessibilityHide
- */
-Tour.prototype.accessibilityHide = function () {
-    var stateHolder = 'data-has-hidden';
-    var attrName = 'aria-hidden';
-    var showFunction = function showFunction(child) {
-        var hidden = child.attr(stateHolder);
-        if (typeof hidden !== 'undefined') {
-            child.removeAttr(stateHolder);
-            child.removeAttr(attrName);
-        }
-    };
+    /**
+     * Perform accessibility changes for step shown.
+     *
+     * This will add aria-hidden="true" to all siblings and parent siblings.
+     *
+     * @method  accessibilityShow
+     */
+    accessibilityShow() {
+        let stateHolder = 'data-has-hidden';
+        let attrName = 'aria-hidden';
+        let hideFunction = function(child) {
+            let flexitourRole = child.data('flexitour');
+            if (flexitourRole) {
+                switch (flexitourRole) {
+                    case 'container':
+                    case 'target':
+                        return;
+                }
+            }
 
-    $('[' + stateHolder + ']').each(function (index, node) {
-        showFunction($(node));
-    });
-};
+            let hidden = child.attr(attrName);
+            if (!hidden) {
+                child.attr(stateHolder, true);
+                child.attr(attrName, true);
+            }
+        };
 
-if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
-    module.exports = Tour;
-}
+        this.currentStepNode.siblings().each(function(index, node) {
+            hideFunction($(node));
+        });
+        this.currentStepNode.parentsUntil('body').siblings().each(function(index, node) {
+            hideFunction($(node));
+        });
+    }
 
-return Tour;
+    /**
+     * Perform accessibility changes for step hidden.
+     *
+     * This will remove any newly added aria-hidden="true".
+     *
+     * @method  accessibilityHide
+     */
+    accessibilityHide() {
+        let stateHolder = 'data-has-hidden';
+        let attrName = 'aria-hidden';
+        let showFunction = function(child) {
+            let hidden = child.attr(stateHolder);
+            if (typeof hidden !== 'undefined') {
+                child.removeAttr(stateHolder);
+                child.removeAttr(attrName);
+            }
+        };
 
-}));
+        $('[' + stateHolder + ']').each(function(index, node) {
+            showFunction($(node));
+        });
+    }
+}
diff --git a/admin/tool/usertours/thirdpartylibs.xml b/admin/tool/usertours/thirdpartylibs.xml
deleted file mode 100644 (file)
index 8f1c4f5..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0"?>
-<libraries>
-  <library>
-    <location>amd/src/tour.js</location>
-    <name>Flexitour</name>
-    <license>GPLv3</license>
-    <version>0.12.3</version>
-    <licenseversion>3</licenseversion>
-  </library>
-</libraries>