diff --git a/.gitignore b/.gitignore index 8a325f0..cedd4ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .DS_Store -test/spec-1-api.js -test/spec-2-shell.js -test/spec-3-tests.js \ No newline at end of file +.sass-cache/ +progress/ \ No newline at end of file diff --git a/pitchdeck.core.js b/pitchdeck.core.js index 09915f3..53b71f0 100644 --- a/pitchdeck.core.js +++ b/pitchdeck.core.js @@ -69,18 +69,44 @@ function updateStates() { var oc = options.classes, $container = $(options.selectors.container), - old = $container.data('onSlide'); + old = $container.data('onSlide'), + $all = $(); + // Container state $container.removeClass(oc.onPrefix + old) .addClass(oc.onPrefix + current) .data('onSlide', current); - $.each(slides, function(i, $e) { - $e.toggleClass(oc.before, i < current - 1) - .toggleClass(oc.previous, i === current - 1) - .toggleClass(oc.current, i === current) - .toggleClass(oc.next, i === current + 1) - .toggleClass(oc.after, i > current + 1); + + // Remove previous states + $.each(slides, function(i, el) { + $all = $all.add(el); }); + $all.removeClass([ + oc.before, + oc.previous, + oc.current, + oc.next, + oc.after + ].join(" ")); + + // Add new states back in + slides[current].addClass(oc.current); + if (current > 0) { + slides[current-1].addClass(oc.previous); + } + if (current + 1 < slides.length) { + slides[current+1].addClass(oc.next); + } + if (current > 1) { + $.each(slides.slice(0, current - 1), function(i, el) { + el.addClass(oc.before); + }); + } + if (current + 2 < slides.length) { + $.each(slides.slice(current+2), function(i, el) { + el.addClass(oc.after); + }) + } } $[pd] = function(method, arg) { diff --git a/test/fixtures/complex.html b/test/fixtures/complex.html new file mode 100644 index 0000000..d9a2956 --- /dev/null +++ b/test/fixtures/complex.html @@ -0,0 +1,12 @@ +
+
+ +
+
+
+
+ +
+ +
+
\ No newline at end of file diff --git a/test/index.html b/test/index.html index 962ca1e..7501fcc 100644 --- a/test/index.html +++ b/test/index.html @@ -6,7 +6,7 @@ - + diff --git a/test/spec.core.js b/test/spec.core.js index f9d7561..20585b8 100755 --- a/test/spec.core.js +++ b/test/spec.core.js @@ -4,247 +4,308 @@ var defaults = $.pitchdeck.defaults; // Go tests, go describe('PitchDeck', function() { - beforeEach(function() { - loadFixtures('standard.html'); - }); - - describe('init(selector)', function() { - it('should create slides', function() { - $.pitchdeck('.slide'); - expect($.pitchdeck('getSlides').length).toEqual($('.slide').length); + describe('standard html structure', function() { + beforeEach(function() { + loadFixtures('standard.html'); + }); + + describe('init(selector)', function() { + it('should create slides', function() { + $.pitchdeck('.slide'); + expect($.pitchdeck('getSlides').length).toEqual($('.slide').length); + }); + }); + + describe('init([selectors])', function() { + it('should create slides', function() { + $.pitchdeck([ + '.slide1', + '.slide2', + '.slide3', + '.slide4', + '.slide5' + ]); + expect($.pitchdeck('getSlides').length).toEqual($('.slide').length); + }); + }); + + describe('navigation functions', function() { + beforeEach(function() { + $.pitchdeck('.slide'); + }); + + describe('go(i)', function() { + it('should go to the i slide (0 based index)', function() { + $.pitchdeck('go', 3); + expect($.pitchdeck('getSlide')).toHaveClass('slide4'); + }); + + it('should go nowhere if i is NaN', function() { + $.pitchdeck('go', 'foobar'); + expect($.pitchdeck('getSlide')).toHaveClass('slide1'); + }); + + it('should go nowhere if i is out of bounds', function() { + $.pitchdeck('go', 5); + expect($.pitchdeck('getSlide')).toHaveClass('slide1'); + }); + }); + + describe('next()', function() { + it('should go to the next slide', function() { + $.pitchdeck('next'); + expect($.pitchdeck('getSlide')).toHaveClass('slide2'); + }); + + it('should go nowhere if on the last slide', function() { + $.pitchdeck('go', 4); + $.pitchdeck('next'); + expect($.pitchdeck('getSlide')).toHaveClass('slide5'); + }); + }); + + describe('prev()', function() { + it('should go to the previous slide', function() { + $.pitchdeck('go', 2); + $.pitchdeck('prev'); + expect($.pitchdeck('getSlide')).toHaveClass('slide2'); + }); + + it('should go nowhere if on the first slide', function() { + $.pitchdeck('prev'); + expect($.pitchdeck('getSlide')).toHaveClass('slide1'); + }); + }); + }); + + describe('getters', function() { + beforeEach(function() { + $.pitchdeck('.slide'); + }); + + describe('getSlide()', function() { + it('should get the current slide', function() { + expect($.pitchdeck('getSlide')).toHaveClass('slide1'); + $.pitchdeck('go', 2); + expect($.pitchdeck('getSlide')).toHaveClass('slide3'); + }); + }); + + describe('getSlide(i)', function() { + it('should get slide number i (0 based index)', function() { + expect($.pitchdeck('getSlide', 1)).toHaveClass('slide2'); + expect($.pitchdeck('getSlide', 3)).toHaveClass('slide4'); + }); + + it('should return null if i is NaN', function() { + expect($.pitchdeck('getSlide', 'barfoo')).toBeNull(); + }); + + it('should return null if i is out of bounds', function() { + expect($.pitchdeck('getSlide', 6)).toBeNull(); + }); + }); + + describe('getSlides()', function() { + it('should return an array of jQuery objects for each slide', function() { + var expectation = []; + $('.slide').each(function() { + expectation.push($(this)); + }); + slides = $.pitchdeck('getSlides'); + expect(slides).toEqual(expectation); + }); + }); + }); + + describe('container states', function() { + beforeEach(function() { + $.pitchdeck('.slide'); + }); + + it('should start at state 0', function() { + expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '0'); + }); + + it('should change states with the slide number', function() { + $.pitchdeck('next'); + expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '1'); + $.pitchdeck('go', 3); + expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '3'); + $.pitchdeck('prev'); + expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '2'); + }); + }); + + describe('options object', function() { + var $d = $(document); + + beforeEach(function() { + $d.unbind('keydown'); + $.pitchdeck('.alt-slide', { + classes: { + after: 'alt-after', + before: 'alt-before', + current: 'alt-current', + onPrefix: 'alt-on-', + next: 'alt-next', + previous: 'alt-prev' + }, + + selectors: { + container: '.alt-container' + }, + + keys: { + next: 87, + previous: 69 + } + }); + }); + + describe('classes', function() { + it('should use the specified after class', function() { + expect($('.alt-slide3, .alt-slide4, .alt-slide5')).toHaveClass('alt-after'); + }); + + it('should use the specified before class', function() { + $.pitchdeck('go', 4); + expect($('.alt-slide1, .alt-slide2, .alt-slide3')).toHaveClass('alt-before'); + }); + + it('should use the specified container class', function() { + $.pitchdeck('go', 2); + expect($('.alt-container')).toHaveClass('alt-on-2'); + }); + + it('should use the specified current class', function() { + expect($.pitchdeck('getSlide')).toHaveClass('alt-current'); + }); + + it('should use the specified next class', function() { + expect($('.alt-slide2')).toHaveClass('alt-next'); + }); + + it('should use the specified previous class', function() { + $.pitchdeck('next'); + expect($('.alt-slide1')).toHaveClass('alt-prev'); + }); + }); + + describe('key bindings', function() { + var e; + + beforeEach(function() { + e = jQuery.Event('keydown'); + }); + + it('should go to the next slide using the specified key', function() { + e.which = 87; // 'w' + $d.trigger(e); + expect($.pitchdeck('getSlide')).toHaveClass('alt-slide2'); + }); + + it('should go to the previous slide using the specified key', function() { + $.pitchdeck('next'); + e.which = 69; // 'e' + $d.trigger(e); + expect($.pitchdeck('getSlide')).toHaveClass('alt-slide1'); + }); + }); + }); + + describe('events', function() { + var $d = $(document); + + beforeEach(function() { + $.pitchdeck('.slide'); + $.pitchdeck('go', 1); + spyOnEvent($d, 'pitchdeck.change'); + }); + + describe('pitchdeck.change', function() { + it('should fire on go(i)', function() { + $.pitchdeck('go', 3); + expect('pitchdeck.change').toHaveBeenTriggeredOn($d); + }); + + it('should fire on next()', function() { + $.pitchdeck('next'); + expect('pitchdeck.change').toHaveBeenTriggeredOn($d); + }); + + it('should fire on prev()', function() { + $.pitchdeck('prev'); + expect('pitchdeck.change').toHaveBeenTriggeredOn($d); + }); + + it('should pass parameters with from and to indices', function() { + $d.bind('pitchdeck.change', function(e, from, to) { + expect(from).toEqual(1); + expect(to).toEqual(3); + }); + $.pitchdeck('go', 3); + $d.unbind('pitchdeck.change'); + }); + }); }); }); - describe('init([selectors])', function() { - it('should create slides', function() { + describe('complex html structure', function() { + beforeEach(function() { + loadFixtures('complex.html'); $.pitchdeck([ '.slide1', '.slide2', '.slide3', '.slide4', - '.slide5' + '.slide5', + '.slide6', + '.slide7', + '.slide8', + '.slide9', + '.slide10', ]); - expect($.pitchdeck('getSlides').length).toEqual($('.slide').length); - }); - }); - - describe('navigation functions', function() { - beforeEach(function() { - $.pitchdeck('.slide'); + $.pitchdeck('go', 2); }); - describe('go(i)', function() { - it('should go to the i slide (0 based index)', function() { - $.pitchdeck('go', 3); - expect($.pitchdeck('getSlide')).toHaveClass('slide4'); - }); - - it('should go nowhere if i is NaN', function() { - $.pitchdeck('go', 'foobar'); - expect($.pitchdeck('getSlide')).toHaveClass('slide1'); - }); - - it('should go nowhere if i is out of bounds', function() { - $.pitchdeck('go', 5); - expect($.pitchdeck('getSlide')).toHaveClass('slide1'); - }); - }); - - describe('next()', function() { - it('should go to the next slide', function() { - $.pitchdeck('next'); - expect($.pitchdeck('getSlide')).toHaveClass('slide2'); - }); - - it('should go nowhere if on the last slide', function() { - $.pitchdeck('go', 4); - $.pitchdeck('next'); - expect($.pitchdeck('getSlide')).toHaveClass('slide5'); - }); - }); - - describe('prev()', function() { - it('should go to the previous slide', function() { - $.pitchdeck('go', 2); - $.pitchdeck('prev'); - expect($.pitchdeck('getSlide')).toHaveClass('slide2'); - }); - - it('should go nowhere if on the first slide', function() { - $.pitchdeck('prev'); - expect($.pitchdeck('getSlide')).toHaveClass('slide1'); - }); - }); - }); - - describe('getters', function() { - beforeEach(function() { - $.pitchdeck('.slide'); - }); - - describe('getSlide()', function() { - it('should get the current slide', function() { - expect($.pitchdeck('getSlide')).toHaveClass('slide1'); - $.pitchdeck('go', 2); - expect($.pitchdeck('getSlide')).toHaveClass('slide3'); - }); - }); - - describe('getSlide(i)', function() { - it('should get slide number i (0 based index)', function() { - expect($.pitchdeck('getSlide', 1)).toHaveClass('slide2'); - expect($.pitchdeck('getSlide', 3)).toHaveClass('slide4'); - }); - - it('should return null if i is NaN', function() { - expect($.pitchdeck('getSlide', 'barfoo')).toBeNull(); - }); - - it('should return null if i is out of bounds', function() { - expect($.pitchdeck('getSlide', 6)).toBeNull(); - }); - }); - - describe('getSlides()', function() { - it('should return an array of jQuery objects for each slide', function() { - var expectation = []; - $('.slide').each(function() { - expectation.push($(this)); + describe('compound state classes', function() { + it('should apply current class', function() { + $('.slide3').each(function(i, el) { + expect($(el)).toHaveClass(defaults.classes.current); }); - slides = $.pitchdeck('getSlides'); - expect(slides).toEqual(expectation); - }); - }); - }); - - describe('container states', function() { - beforeEach(function() { - $.pitchdeck('.slide'); - }); - - it('should start at state 0', function() { - expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '0'); - }); - - it('should change states with the slide number', function() { - $.pitchdeck('next'); - expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '1'); - $.pitchdeck('go', 3); - expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '3'); - $.pitchdeck('prev'); - expect($(defaults.selectors.container)).toHaveClass(defaults.classes.onPrefix + '2'); - }); - }); - - describe('options object', function() { - var $d = $(document); - - beforeEach(function() { - $d.unbind('keydown'); - $.pitchdeck('.alt-slide', { - classes: { - after: 'alt-after', - before: 'alt-before', - current: 'alt-current', - onPrefix: 'alt-on-', - next: 'alt-next', - previous: 'alt-prev' - }, - - selectors: { - container: '.alt-container' - }, - - keys: { - next: 87, - previous: 69 - } - }); - }); - - describe('classes', function() { - it('should use the specified after class', function() { - expect($('.alt-slide3, .alt-slide4, .alt-slide5')).toHaveClass('alt-after'); }); - it('should use the specified before class', function() { - $.pitchdeck('go', 4); - expect($('.alt-slide1, .alt-slide2, .alt-slide3')).toHaveClass('alt-before'); - }); - - it('should use the specified container class', function() { - $.pitchdeck('go', 2); - expect($('.alt-container')).toHaveClass('alt-on-2'); - }); - - it('should use the specified current class', function() { - expect($.pitchdeck('getSlide')).toHaveClass('alt-current'); - }); - - it('should use the specified next class', function() { - expect($('.alt-slide2')).toHaveClass('alt-next'); - }); - - it('should use the specified previous class', function() { - $.pitchdeck('next'); - expect($('.alt-slide1')).toHaveClass('alt-prev'); - }); - }); - - describe('key bindings', function() { - var e; - - beforeEach(function() { - e = jQuery.Event('keydown'); - }); - - it('should go to the next slide using the specified key', function() { - e.which = 87; // 'w' - $d.trigger(e); - expect($.pitchdeck('getSlide')).toHaveClass('alt-slide2'); - }); - - it('should go to the previous slide using the specified key', function() { - $.pitchdeck('next'); - e.which = 69; // 'e' - $d.trigger(e); - expect($.pitchdeck('getSlide')).toHaveClass('alt-slide1'); - }); - }); - }); - - describe('events', function() { - var $d = $(document); - - beforeEach(function() { - $.pitchdeck('.slide'); - $.pitchdeck('go', 1); - spyOnEvent($d, 'pitchdeck.change'); - }); - - describe('pitchdeck.change', function() { - it('should fire on go(i)', function() { - $.pitchdeck('go', 3); - expect('pitchdeck.change').toHaveBeenTriggeredOn($d); - }); - - it('should fire on next()', function() { - $.pitchdeck('next'); - expect('pitchdeck.change').toHaveBeenTriggeredOn($d); - }); - - it('should fire on prev()', function() { - $.pitchdeck('prev'); - expect('pitchdeck.change').toHaveBeenTriggeredOn($d); - }); - - it('should pass parameters with from and to indices', function() { - $d.bind('pitchdeck.change', function(e, from, to) { - expect(from).toEqual(1); - expect(to).toEqual(3); + it('should apply previous class', function() { + $('.slide2').each(function(i, el) { + expect($(el)).toHaveClass(defaults.classes.previous); }); - $.pitchdeck('go', 3); }); + + it('should apply next class', function() { + $('.slide4').each(function(i, el) { + expect($(el)).toHaveClass(defaults.classes.next); + }); + }); + + it('should apply before class', function() { + $('.slide1').each(function(i, el) { + expect($(el)).toHaveClass(defaults.classes.before); + }); + }); + + it('should apply after class', function() { + $('.slide5, .slide6, .slide7, .slide8, .slide9, .slide10').each(function(i, el) { + expect($(el)).toHaveClass(defaults.classes.after); + }); + }); + }); + + it('should remove old state classes', function() { + $.pitchdeck('go', 4); + expect($('.slide3').not('.slide5')).not.toHaveClass(defaults.classes.current); + expect($('.slide2').not('.slide4')).not.toHaveClass(defaults.classes.previous); + expect($('.slide4').not('.slide6')).not.toHaveClass(defaults.classes.next); }); }); }); \ No newline at end of file