diff --git a/js/angular/controller/slideBoxController.js b/js/angular/controller/slideBoxController.js index d42ffceb92..03f3745331 100644 --- a/js/angular/controller/slideBoxController.js +++ b/js/angular/controller/slideBoxController.js @@ -240,6 +240,8 @@ function(scope, element, $log, $document, $$q, $timeout, $interval, $$ionicAttac var direction; var translatePx; + element.triggerHandler('$ionSlideBox.slide', newIndex); + // We're interested in isDrag, because a failed drag is the only case // where we want to run a slide animation yet have no change in selectedIndex if (!isDrag && (delta === 0 || selectedIndex === -1)) { @@ -284,8 +286,8 @@ function(scope, element, $log, $document, $$q, $timeout, $interval, $$ionicAttac function setSelectedSlide(newIndex) { selectedIndex = newIndex; - container.css(ionic.CSS.TRANSFORM, ''); setDisplayedSlides(self.previous(newIndex), newIndex, self.next(newIndex)); + container.css(ionic.CSS.TRANSFORM, ''); } /** @@ -375,7 +377,7 @@ function(scope, element, $log, $document, $$q, $timeout, $interval, $$ionicAttac if (isSuccess) { var distanceRemaining = (1 - Math.abs(percent)) * dragWidth; - var transitionDuration = Math.min(distanceRemaining / velocity, SLIDE_TRANSITION_DURATION); + var transitionDuration = Math.min((distanceRemaining / velocity) - 34, SLIDE_TRANSITION_DURATION); self.select(function getIndex() { // This will be called once this dragend is reached in the select queue. diff --git a/js/angular/directive/slide.js b/js/angular/directive/slide.js index 5907f99468..26f730faa0 100644 --- a/js/angular/directive/slide.js +++ b/js/angular/directive/slide.js @@ -21,12 +21,20 @@ IonicModule .directive('ionSlide', ['$timeout', function($timeout) { return { restrict: 'E', - require: '^ionSlideBox', + require: ['^ionSlideBox', '^^?ionSlide'], transclude: true, + controller: angular.noop, link: postLink }; - function postLink(scope, element, attr, slideBoxCtrl, transclude) { + function postLink(scope, element, attr, ctrls, transclude) { + var slideBoxCtrl = ctrls[0]; + var slideCtrl = ctrls[1]; + + if (slideCtrl) { + throw new Error('You cannot have an ion-slide within another ion-slide!'); + } + element.addClass('slider-slide'); slideBoxCtrl.onAddSlide(); @@ -35,7 +43,7 @@ IonicModule element.data('$ionSlideScope', childScope); // Disconnect by default, will be reconnected if shown - ionic.Utils.disconnectScope(childScope); + // ionic.Utils.disconnectScope(childScope); transclude(childScope, function(contents) { element.append(contents); diff --git a/js/angular/directive/slideBox.js b/js/angular/directive/slideBox.js index c40d6acc23..37a1e4e609 100644 --- a/js/angular/directive/slideBox.js +++ b/js/angular/directive/slideBox.js @@ -30,18 +30,22 @@ * * @param {expression=} selected A model bound to the selected slide index. * @param {boolean=} loop Whether the slide box should loop. Default false. - * @param {number=} auto-play If a positive number, then every time the given number of milliseconds have passed, slideBox will go to the next slide. Set to a non-positive number to disable. Default: -1. - * @param {expression=} on-slide-changed Expression called whenever the slide is changed. Is passed a '$slideIndex' variable. + * @param {number=} auto-play If a positive number, then every time the given number of + * milliseconds have passed, slideBox will go to the next slide. Set to a non-positive number + * to disable. Default: -1. + * @param {expression=} on-slide-changed Expression called when all currently queued slide + * animations finish. Is passed a '$slideIndex' variable. + * @param {expression=} on-slide-start Expression called whenever a slide animation starts. + * Is passed a '$slideIndex' variable. * @param {string=} delegate-handle The handle used to identify this slideBox with * {@link ionic.service:$ionicSlideBoxDelegate}. */ IonicModule .directive('ionSlideBox', [ '$ionicSlideBoxDelegate', - '$window', '$ionicHistory', - '$parse', -function($ionicSlideBoxDelegate, $window, $ionicHistory, $parse) { + '$timeout', +function($ionicSlideBoxDelegate, $ionicHistory, $timeout) { return { restrict: 'E', @@ -50,7 +54,8 @@ function($ionicSlideBoxDelegate, $window, $ionicHistory, $parse) { transclude: true, scope: { selected: '=?', - onSlideChanged: '&' + onSlideChanged: '&', + onSlideStart: '&' }, template: '
', compile: compile @@ -72,6 +77,7 @@ function($ionicSlideBoxDelegate, $window, $ionicHistory, $parse) { } ); + listenForSlide(); watchSelected(); isDefined(attr.loop) && watchLoop(); isDefined(attr.autoPlay) && watchAutoPlay(); @@ -82,6 +88,15 @@ function($ionicSlideBoxDelegate, $window, $ionicHistory, $parse) { // Methods // *** + function listenForSlide() { + element.on('$ionSlideBox.slide', function(ev, index) { + scope.onSlideStart({ + $slideIndex: index + }); + $timeout(angular.noop); + }); + } + function watchSelected() { scope.$watch('selected', function(index) { if (slideBoxCtrl.selected() !== index) { diff --git a/js/angular/directive/slideBoxPager.js b/js/angular/directive/slideBoxPager.js index 12bbe7aaa8..743a510a44 100644 --- a/js/angular/directive/slideBoxPager.js +++ b/js/angular/directive/slideBoxPager.js @@ -48,6 +48,7 @@ function($parse) { return { restrict: 'E', require: '^ionSlideBox', + scope: {}, link: postLink }; @@ -60,16 +61,27 @@ function($parse) { var node = element[0]; // Put it outside the slides container it was transcluded into - slideBoxCtrl.element.append(element); + slideBoxCtrl.element.prepend(element); - element.addClass('slider-pager'); - scope.slideBoxCtrl = slideBoxCtrl; - scope.pages = []; element.on('click', onPagerClicked); scope.$watch(slideBoxCtrl.count, watchCountAction); scope.$watch(slideBoxCtrl.selected, watchSelectedAction); + slideBoxCtrl.element.on('$ionSlideBox.slide', onSlideStart); + scope.$on('$destroy', function() { + slideBoxCtrl.element.off('$ionSlideBox.slide', onSlideStart); + }); + + element.addClass('ng-hide'); + ionic.requestAnimationFrame(function() { + element.removeClass('ng-hide').addClass('slider-pager'); + }); + + function onSlideStart(ev, index) { + watchSelectedAction(index); + } + function onPagerClicked(ev) { for (var i = 0, pager; (pager = node.children[i]); i++) { if (pager === ev.target) { @@ -88,18 +100,20 @@ function($parse) { } } - function watchSelectedAction(selected, oldSelected) { + var oldSelected; + function watchSelectedAction(selected) { var old = node.children[oldSelected]; if (old) old.classList.remove('active'); var current = node.children[selected]; if (current) current.classList.add('active'); + oldSelected = selected; } //* Extra methods *// function doClick(index) { scope.$apply(function() { - clickFn(scope, { + clickFn(scope.$parent, { index: index, // DEPRECATED `index` $slideIndex: index, }); diff --git a/scss/_slide-box.scss b/scss/_slide-box.scss index 51305bed9a..0e92cb0083 100644 --- a/scss/_slide-box.scss +++ b/scss/_slide-box.scss @@ -10,34 +10,31 @@ .slider-slides { width: 100%; - position: relative; @include translate3d(0,0,0); - &.transition { - -webkit-transition: linear -webkit-transform; - transition: linear transform; - } + -webkit-transition: linear -webkit-transform; + transition: linear transform; } .slider-slide { width: 100%; height: 100%; - &:not([slide-display]) { - display: none; - } + display: none; + @include translate3d(0,0,0); + &[slide-display] { display: inline-block; } - &[slide-display="selected"] { - } &[slide-display="previous"] { position: absolute; - left: -100%; top: 0; + left: 0; + @include translate3d(-100%,0,0); } &[slide-display="next"] { position: absolute; - left: 100%; top: 0; + left: 0; + @include translate3d(100%,0,0); } } diff --git a/test/unit/angular/directive/slideBox.unit.js b/test/unit/angular/directive/slideBox.unit.js index 41dee4d6f7..6bf3fb22f0 100644 --- a/test/unit/angular/directive/slideBox.unit.js +++ b/test/unit/angular/directive/slideBox.unit.js @@ -37,6 +37,12 @@ describe('ionSlideBox', function() { describe('directive', function() { + it('should error with nested ion-slides', function() { + expect(function() { + setup('', '