From 9fb02822c35cf5f45d5a0d4b43d23eab35afa957 Mon Sep 17 00:00:00 2001 From: Brian Sipple Date: Wed, 21 Nov 2018 21:26:18 -0500 Subject: [PATCH] Remove unnecessary `id` attribute on step tooltip containers. Follows up on the discussion [here](https://github.com/shipshapecode/shepherd/pull/282#discussion_r226880019). --- index.md | 2 ++ src/js/step.js | 2 +- src/js/tour.js | 39 +++++++++++++++++++++++++++++++++++++-- test/unit/test.tour.js | 21 +++++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/index.md b/index.md index 4886053b1..30ec08136 100644 --- a/index.md +++ b/index.md @@ -124,6 +124,8 @@ const myTour = new Shepherd.Tour(options); - `steps`: An array of Step instances to initialize the tour with - `defaultStepOptions`: Default options for Steps created through `addStep` +- `tourName`: An optional "name" for the tour. This will be appended to the the tour's +dynamically generated `id` property -- which is also set on the `body` element as the `data-shepherd-active-tour` attribute whenever the tour becomes active. - `confirmCancel`: If true, will issue a window.confirm before cancelling - `confirmCancelMessage`: The message to display in the confirm dialog diff --git a/src/js/step.js b/src/js/step.js index 6ad339aeb..04ddbc7b1 100644 --- a/src/js/step.js +++ b/src/js/step.js @@ -190,7 +190,7 @@ export class Step extends Evented { _createTooltipContent() { const content = document.createElement('div'); const classes = this.options.classes || ''; - const element = createFromHTML(`
`); + const element = createFromHTML(`
`); const header = document.createElement('header'); if (this.options.title) { diff --git a/src/js/tour.js b/src/js/tour.js index 496bbe5c5..ed7f43082 100644 --- a/src/js/tour.js +++ b/src/js/tour.js @@ -5,6 +5,19 @@ import { bindMethods } from './bind.js'; import tippy from 'tippy.js'; import { defaults as tooltipDefaults } from './utils/tooltip-defaults'; +/** + * Creates incremented ID for each newly created tour + * + * @private + * @return {Number} The unique id for the tour + */ +const uniqueId = (function() { + let id = 0; + return function() { + return ++id; + }; +})(); + const Shepherd = new Evented(); /** @@ -17,6 +30,9 @@ export class Tour extends Evented { * @param {Object} options The options for the tour * @param {Object} options.defaultStepOptions Default options for Steps created through `addStep` * @param {Step[]} options.steps An array of Step instances to initialize the tour with + * @param {string} options.tourName An optional "name" for the tour. This will be appended to the the tour's + * dynamically generated `id` property -- which is also set on the `body` element as the `data-shepherd-active-tour` attribute + * whenever the tour becomes active. * @returns {Tour} */ constructor(options = {}) { @@ -43,6 +59,7 @@ export class Tour extends Evented { }); this._setTooltipDefaults(); + this._setTourID(); return this; } @@ -119,7 +136,7 @@ export class Tour extends Evented { this.trigger(event); Shepherd.activeTour = null; - document.body.classList.remove('shepherd-active'); + this._removeBodyAttrs(); this.trigger('inactive', { tour: this }); } @@ -260,7 +277,7 @@ export class Tour extends Evented { * @private */ _setupActiveTour() { - document.body.classList.add('shepherd-active'); + this._addBodyAttrs(); this.trigger('active', { tour: this }); Shepherd.activeTour = this; @@ -291,6 +308,24 @@ export class Tour extends Evented { this._setupActiveTour(); } } + + _setTourID() { + const tourName = this.options.tourName || 'tour'; + const uuid = uniqueId(); + + this.id = `${tourName}--${uuid}`; + } + + _addBodyAttrs() { + document.body.setAttribute('data-shepherd-active-tour', this.id); + document.body.classList.add('shepherd-active'); + } + + _removeBodyAttrs() { + document.body.removeAttribute('data-shepherd-active-tour'); + document.body.classList.remove('shepherd-active'); + } + } export { Shepherd }; diff --git a/test/unit/test.tour.js b/test/unit/test.tour.js index 23f028d41..1ef1329a7 100644 --- a/test/unit/test.tour.js +++ b/test/unit/test.tour.js @@ -67,6 +67,19 @@ describe('Tour | Top-Level Class', function() { assert.equal(tippySpy.callCount, 1); assert.equal(tippySpy.calledWith(tooltipDefaults), true); }); + + it('generates a unique `id` property, optionally based upon the `tourName` option', function() { + const instance1 = new Shepherd.Tour(); + const instance2 = new Shepherd.Tour({ tourName: 'select-avatar'}); + + assert.equal(instance1.id.startsWith('tour--'), true); + assert.equal(instance2.id.startsWith('select-avatar--'), true); + + const uniqueId1 = instance1.id.split('--')[1]; + const uniqueId2 = instance2.id.split('--')[1]; + + assert.notEqual(uniqueId1, uniqueId2); + }); }); describe('methods', () => { @@ -142,6 +155,14 @@ describe('Tour | Top-Level Class', function() { assert.equal(instance, Shepherd.activeTour); }); + + it('adds the current tour\'s "id" property to the body as a data attribute', function() { + instance.id = 'test-id'; + instance.start(); + + assert.equal(document.body.hasAttribute('data-shepherd-active-tour'), true); + assert.equal(document.body.getAttribute('data-shepherd-active-tour'), 'test-id'); + }); }); describe('.getCurrentStep()', function() {