From eaaa9a7f334cc464dd0a61d28adf79a2eb7e4356 Mon Sep 17 00:00:00 2001 From: Robert Wagner Date: Sat, 13 Jul 2019 11:08:38 -0400 Subject: [PATCH] Cleanup public/private API --- src/js/step.js | 121 +++++++++++++++++++++-------------------- src/js/tour.js | 96 ++++++++++++++++---------------- test/unit/step.spec.js | 22 ++++---- test/unit/tour.spec.js | 4 +- 4 files changed, 124 insertions(+), 119 deletions(-) diff --git a/src/js/step.js b/src/js/step.js index 3d05f73e2..21e9bd742 100644 --- a/src/js/step.js +++ b/src/js/step.js @@ -108,17 +108,17 @@ export class Step extends Evented { super(tour, options); this.tour = tour; bindMethods.call(this, [ + '_scrollTo', + '_setupElements', '_show', 'cancel', 'complete', 'destroy', 'hide', 'isOpen', - 'scrollTo', - 'setupElements', 'show' ]); - this.setOptions(options); + this._setOptions(options); this.bindAdvance = bindAdvance.bind(this); this.bindButtonEvents = bindButtonEvents.bind(this); this.bindCancelLink = bindCancelLink.bind(this); @@ -209,60 +209,6 @@ export class Step extends Evented { ); } - /** - * Create the element and set up the tippy instance - */ - setupElements() { - if (!isUndefined(this.el)) { - this.destroy(); - } - - this.el = this._createTooltipContent(); - - this._addKeyDownHandler(this.el); - - if (this.options.advanceOn) { - this.bindAdvance(); - } - - this.setupTooltip(); - } - - /** - * If a custom scrollToHandler is defined, call that, otherwise do the generic - * scrollIntoView call. - * - * @param {boolean|Object} scrollToOptions If true, uses the default `scrollIntoView`, - * if an object, passes that object as the params to `scrollIntoView` i.e. `{ behavior: 'smooth', block: 'center' }` - */ - scrollTo(scrollToOptions) { - const { element } = this.parseAttachTo(); - - if (isFunction(this.options.scrollToHandler)) { - this.options.scrollToHandler(element); - } else if (isElement(element)) { - element.scrollIntoView(scrollToOptions); - } - } - - /** - * Sets the options for the step, maps `when` to events, sets up buttons - * @param {Object} options The options for the step - */ - setOptions(options = {}) { - this.options = options; - const { when } = this.options; - - this.destroy(); - this.id = this.options.id || `step-${uniqueId()}`; - - if (when) { - Object.entries(when).forEach(([event, handler]) => { - this.on(event, handler, this); - }); - } - } - /** * Wraps `_show` and ensures `beforeShowPromise` resolves before calling show * @return {*|Promise} @@ -450,6 +396,63 @@ export class Step extends Evented { return element; } + /** + * If a custom scrollToHandler is defined, call that, otherwise do the generic + * scrollIntoView call. + * + * @param {boolean|Object} scrollToOptions If true, uses the default `scrollIntoView`, + * if an object, passes that object as the params to `scrollIntoView` i.e. `{ behavior: 'smooth', block: 'center' }` + * @private + */ + _scrollTo(scrollToOptions) { + const { element } = this.parseAttachTo(); + + if (isFunction(this.options.scrollToHandler)) { + this.options.scrollToHandler(element); + } else if (isElement(element)) { + element.scrollIntoView(scrollToOptions); + } + } + + /** + * Sets the options for the step, maps `when` to events, sets up buttons + * @param {Object} options The options for the step + * @private + */ + _setOptions(options = {}) { + this.options = options; + const { when } = this.options; + + this.destroy(); + this.id = this.options.id || `step-${uniqueId()}`; + + if (when) { + Object.entries(when).forEach(([event, handler]) => { + this.on(event, handler, this); + }); + } + } + + /** + * Create the element and set up the tippy instance + * @private + */ + _setupElements() { + if (!isUndefined(this.el)) { + this.destroy(); + } + + this.el = this._createTooltipContent(); + + this._addKeyDownHandler(this.el); + + if (this.options.advanceOn) { + this.bindAdvance(); + } + + this.setupTooltip(); + } + /** * Triggers `before-show`, generates the tooltip DOM content, * sets up a tippy instance for the tooltip, then triggers `show`. @@ -460,7 +463,7 @@ export class Step extends Evented { this.trigger('before-show'); if (!this.el) { - this.setupElements(); + this._setupElements(); } this.target.classList.add('shepherd-enabled', 'shepherd-target'); @@ -469,7 +472,7 @@ export class Step extends Evented { if (this.options.scrollTo) { setTimeout(() => { - this.scrollTo(this.options.scrollTo); + this._scrollTo(this.options.scrollTo); }); } diff --git a/src/js/tour.js b/src/js/tour.js index 0e7a624bb..d0fe437ce 100644 --- a/src/js/tour.js +++ b/src/js/tour.js @@ -97,7 +97,7 @@ export class Tour extends Evented { } if (!(step instanceof Step)) { - step = this.setupStep(step, name); + step = this._setupStep(step, name); } else { step.tour = this; } @@ -115,7 +115,7 @@ export class Tour extends Evented { } /** - * Calls done() triggering the 'cancel' event + * Calls _done() triggering the 'cancel' event * If `confirmCancel` is true, will show a window.confirm before cancelling */ cancel() { @@ -123,43 +123,18 @@ export class Tour extends Evented { const cancelMessage = this.options.confirmCancelMessage || 'Are you sure you want to stop the tour?'; const stopTour = window.confirm(cancelMessage); if (stopTour) { - this.done('cancel'); + this._done('cancel'); } } else { - this.done('cancel'); + this._done('cancel'); } } /** - * Calls done() triggering the `complete` event + * Calls _done() triggering the `complete` event */ complete() { - this.done('complete'); - } - - /** - * Called whenever the tour is cancelled or completed, basically anytime we exit the tour - * @param {String} event The event name to trigger - */ - done(event) { - if (Array.isArray(this.steps)) { - this.steps.forEach((step) => step.destroy()); - } - - cleanupStepEventListeners.call(this); - cleanupSteps(this.tourObject); - - this.trigger(event); - - Shepherd.activeTour = null; - this._removeBodyAttrs(); - this.trigger('inactive', { tour: this }); - - if (this.options.disableScroll) { - clearAllBodyScrollLocks(); - } - - this.modal.cleanup(); + this._done('complete'); } /** @@ -243,22 +218,6 @@ export class Tour extends Evented { } } - /** - * Setup a new step object - * @param {Object} stepOptions The object describing the options for the step - * @param {String|Number} name The string or number to use as the `id` for the step - * @return {Step} The step instance - */ - setupStep(stepOptions, name) { - if (isString(name) || isNumber(name)) { - stepOptions.id = name.toString(); - } - - stepOptions = Object.assign({}, this.options.defaultStepOptions, stepOptions); - - return new Step(this, stepOptions); - } - beforeShowStep(step) { this.modal.setupForStep(step); this._styleTargetElementForStep(step); @@ -307,6 +266,32 @@ export class Tour extends Evented { this.next(); } + /** + * Called whenever the tour is cancelled or completed, basically anytime we exit the tour + * @param {String} event The event name to trigger + * @private + */ + _done(event) { + if (Array.isArray(this.steps)) { + this.steps.forEach((step) => step.destroy()); + } + + cleanupStepEventListeners.call(this); + cleanupSteps(this.tourObject); + + this.trigger(event); + + Shepherd.activeTour = null; + this._removeBodyAttrs(); + this.trigger('inactive', { tour: this }); + + if (this.options.disableScroll) { + clearAllBodyScrollLocks(); + } + + this.modal.cleanup(); + } + /** * Make this tour "active" * @private @@ -319,6 +304,23 @@ export class Tour extends Evented { Shepherd.activeTour = this; } + /** + * Setup a new step object + * @param {Object} stepOptions The object describing the options for the step + * @param {String|Number} name The string or number to use as the `id` for the step + * @return {Step} The step instance + * @private + */ + _setupStep(stepOptions, name) { + if (isString(name) || isNumber(name)) { + stepOptions.id = name.toString(); + } + + stepOptions = Object.assign({}, this.options.defaultStepOptions, stepOptions); + + return new Step(this, stepOptions); + } + /** * Modulates the styles of the passed step's target element, based on the step's options and * the tour's `modal` option, to visually emphasize the element diff --git a/test/unit/step.spec.js b/test/unit/step.spec.js index a17de7cca..558d065aa 100644 --- a/test/unit/step.spec.js +++ b/test/unit/step.spec.js @@ -274,14 +274,14 @@ describe('Tour | Step', () => { it('binds the expected methods', () => { const step = new Step(); const methods = [ + '_scrollTo', + '_setupElements', '_show', 'cancel', 'complete', 'destroy', 'hide', 'isOpen', - 'scrollTo', - 'setupElements', 'show' ]; methods.forEach((method) => { @@ -369,14 +369,14 @@ describe('Tour | Step', () => { }); }); - describe('setupElements()', () => { + describe('_setupElements()', () => { it('calls destroy on the step if the content element is already set', () => { const step = new Step(); let destroyCalled = false; step.el = document.createElement('a'); step.destroy = () => destroyCalled = true; - step.setupElements(); - expect(destroyCalled, 'setupElements method called destroy with element set').toBeTruthy(); + step._setupElements(); + expect(destroyCalled, '_setupElements method called destroy with element set').toBeTruthy(); }); it('calls destroy on the tooltip if it already exists', () => { @@ -385,8 +385,8 @@ describe('Tour | Step', () => { step.tooltip = { destroy() { destroyCalled = true; } }; - step.setupElements(); - expect(destroyCalled, 'setupElements method called destroy on the existing tooltip').toBe(true); + step._setupElements(); + expect(destroyCalled, '_setupElements method called destroy on the existing tooltip').toBe(true); }); it('calls bindAdvance() if advanceOn passed', () => { @@ -396,13 +396,13 @@ describe('Tour | Step', () => { advanceOn: { selector: '.click-test', event: 'test' } }); const bindFunction = spy(step, 'bindAdvance'); - step.setupElements(); + step._setupElements(); expect(bindFunction.called).toBeTruthy(); }); }); - describe('scrollTo()', () => { + describe('_scrollTo()', () => { it('calls the scroll native method', () => { const div = document.createElement('div'); let handlerCalled = false; @@ -413,7 +413,7 @@ describe('Tour | Step', () => { }); div.scrollIntoView = () => handlerCalled = true; - step.scrollTo(); + step._scrollTo(); expect(handlerCalled).toBeTruthy(); }); @@ -423,7 +423,7 @@ describe('Tour | Step', () => { scrollToHandler: () => handlerAdded = true }); - step.scrollTo(); + step._scrollTo(); expect(handlerAdded).toBeTruthy(); }); }); diff --git a/test/unit/tour.spec.js b/test/unit/tour.spec.js index c7b30dde6..9628a4292 100644 --- a/test/unit/tour.spec.js +++ b/test/unit/tour.spec.js @@ -296,7 +296,7 @@ describe('Tour | Top-Level Class', function() { }); it('calls `done()`', () => { - const doneSpy = spy(instance, 'done'); + const doneSpy = spy(instance, '_done'); expect(doneSpy.callCount).toBe(0); @@ -307,7 +307,7 @@ describe('Tour | Top-Level Class', function() { }); }); - describe('.done()', function() { + describe('._done()', function() { it('tears down the active tour', function() { instance.start();