diff --git a/addon/services/tour.js b/addon/services/tour.js index ee44656a..12de01ca 100644 --- a/addon/services/tour.js +++ b/addon/services/tour.js @@ -346,6 +346,22 @@ export default Service.extend(Evented, { $('#highlightOverlay').remove(); } }); + + let $window = $(window); + + // Allow scrollbar scrolling so scrollTo works. + currentStep.options.scrollToHandler = (elem) => { + $window.disablescroll({ + handleScrollbar: false + }); + + if (typeof elem !== 'undefined') { + elem.scrollIntoView(); + } + + $window.disablescroll(this.get('disableScroll') ? undefined : 'undo'); + }; + }); if (this.get('autoStart')) { Ember.run.later(()=> { diff --git a/tests/acceptance/ember-shepherd-test.js b/tests/acceptance/ember-shepherd-test.js index 0678e6e4..2f25fc04 100644 --- a/tests/acceptance/ember-shepherd-test.js +++ b/tests/acceptance/ember-shepherd-test.js @@ -10,12 +10,12 @@ function patchClick(sel, container) { } module('Tour functionality tests', { - beforeEach: function() { + beforeEach: function () { App = startApp(); container = App.__container__; container.lookup('route:application').set('initialModalValue', false); }, - afterEach: function() { + afterEach: function () { //Remove all Shepherd stuff, to start fresh each time. find('.shepherd-active', 'body').removeClass('shepherd-active'); find('[class^=shepherd]', 'body').remove(); @@ -25,34 +25,34 @@ module('Tour functionality tests', { }); -test("Modal page contents", function(assert) { +test("Modal page contents", function (assert) { assert.expect(3); visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { assert.equal(find('.shepherd-active', 'html').length, 1, "Body gets class of shepherd-active, when shepherd becomes active"); assert.equal(find('.shepherd-enabled', 'body').length, 2, "attachTo element and tour have shepherd-enabled class"); assert.equal(find('#shepherdOverlay', 'body').length, 1, "#shepherdOverlay exists, since modal"); }); }); -test("Non-modal page contents", function(assert) { +test("Non-modal page contents", function (assert) { assert.expect(3); visit('/'); click(':contains(Non-modal)'); - andThen(function() { + andThen(function () { assert.equal(find('body.shepherd-active', 'html').length, 1, "Body gets class of shepherd-active, when shepherd becomes active"); assert.equal(find('.shepherd-enabled', 'body').length, 2, "attachTo element and tour get shepherd-enabled class"); assert.equal(find('#shepherdOverlay', 'body').length, 0, "#shepherdOverlay should not exist, since non-modal"); }); }); -test("Tour next, back, and cancel builtInButtons work", function(assert) { +test("Tour next, back, and cancel builtInButtons work", function (assert) { assert.expect(3); visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { patchClick('.shepherd-content a:contains(Next)', 'body'); assert.equal(find('.back-button', '.shepherd-enabled', 'body').length, 1, "Ensure that the back button appears"); patchClick('.shepherd-content a:contains(Back)', 'body'); @@ -62,7 +62,7 @@ test("Tour next, back, and cancel builtInButtons work", function(assert) { }); }); -test("Highlight applied", function(assert) { +test("Highlight applied", function (assert) { assert.expect(2); var steps = [{ @@ -94,14 +94,14 @@ test("Highlight applied", function(assert) { visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { assert.equal(find('.highlight', 'body').length, 1, "currentElement highlighted"); patchClick('.shepherd-content a:contains(Exit)', 'body'); assert.equal(find('.highlight', 'body').length, 0, "highlightClass removed on cancel"); }); }); -test("Defaults applied", function(assert) { +test("Defaults applied", function (assert) { assert.expect(1); var defaults = { @@ -139,13 +139,13 @@ test("Defaults applied", function(assert) { visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { assert.equal(find('.test-defaults', 'body').length, 1, "defaults class applied"); patchClick('.shepherd-content a:contains(Exit)', 'body'); }); }); -test('configuration works with attachTo object when element is a simple string', function(assert) { +test('configuration works with attachTo object when element is a simple string', function (assert) { assert.expect(1); // Override default behavior @@ -179,12 +179,12 @@ test('configuration works with attachTo object when element is a simple string', visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { assert.ok(find('.shepherd-step', 'body').length, "tour is visible"); }); }); -test('configuration works with attachTo object when element is dom element', function(assert) { +test('configuration works with attachTo object when element is dom element', function (assert) { assert.expect(1); // Override default behavior @@ -218,13 +218,13 @@ test('configuration works with attachTo object when element is dom element', fun visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { assert.ok(find('.shepherd-step', 'body').length, "tour is visible"); }); }); -test('buttons work when type is not specified and passed action is triggered', function(assert) { +test('buttons work when type is not specified and passed action is triggered', function (assert) { assert.expect(4); var buttonActionCalled = false; @@ -248,7 +248,8 @@ test('buttons work when type is not specified and passed action is triggered', f { classes: 'shepherd-button-secondary button-three', text: 'button three', - action: () => {} + action: () => { + } } ], classes: 'shepherd shepherd-open shepherd-theme-arrows shepherd-transparent-text', @@ -263,20 +264,20 @@ test('buttons work when type is not specified and passed action is triggered', f visit('/'); click(':contains(Modal Demo)'); - andThen(function() { + andThen(function () { assert.ok(find('.button-one', 'body').length, "tour button one is visible"); assert.ok(find('.button-two', 'body').length, "tour button two is visible"); assert.ok(find('.button-three', 'body').length, "tour button three is visible"); patchClick('.button-two', 'body'); }); - andThen(function() { + andThen(function () { assert.ok(buttonActionCalled, 'button action triggered'); }); }); -test("`pointer-events` is set to `auto` for any step element on clean up", function(assert) { +test("`pointer-events` is set to `auto` for any step element on clean up", function (assert) { assert.expect(4); visit('/'); @@ -307,3 +308,21 @@ test("`pointer-events` is set to `auto` for any step element on clean up", funct }); }); }); + +test("scrollTo works with disableScroll on", (assert) => { + assert.expect(2); + // Setup controller tour settings + container.lookup('route:application').set('autoStart', false); + container.lookup('route:application').set('disableScroll', true); + container.lookup('route:application').set('scrollTo', true); + + // Visit route + visit('/'); + + assert.equal($('#ember-testing-container')[0].scrollTop, 0, 'Scroll is initially 0'); + click(':contains(Modal Demo)'); + + andThen(() => { + assert.ok($('#ember-testing-container')[0].scrollTop > 0, 'Scrolled down correctly'); + }); +}); diff --git a/tests/dummy/app/routes/application.js b/tests/dummy/app/routes/application.js index 415e756f..c411f3ec 100644 --- a/tests/dummy/app/routes/application.js +++ b/tests/dummy/app/routes/application.js @@ -3,6 +3,8 @@ import Ember from 'ember'; export default Ember.Route.extend({ initialModalValue: true, tour: Ember.inject.service(), + disableScroll: true, + autoStart: true, defaults: { classes: 'shepherd-element shepherd-open shepherd-theme-arrows', scrollTo: true, @@ -229,7 +231,7 @@ export default Ember.Route.extend({ setupController: function (controller, model) { let tour = this.get('tour'); - tour.set('autoStart', true); + tour.set('autoStart', this.get('autoStart')); tour.set('defaults', this.get('defaults')); tour.set('steps', this.get('initialSteps')); tour.set('requiredElements', [ @@ -245,7 +247,7 @@ export default Ember.Route.extend({ } ]); - tour.set('disableScroll', false); + tour.set('disableScroll', this.get('disableScroll')); tour.set('modal', this.get('initialModalValue')); tour.on('cancel', () => {