mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
feat(slideBox): add on-slide-start callback
This commit is contained in:
6
js/angular/controller/slideBoxController.js
vendored
6
js/angular/controller/slideBoxController.js
vendored
@@ -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.
|
||||
|
||||
14
js/angular/directive/slide.js
vendored
14
js/angular/directive/slide.js
vendored
@@ -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);
|
||||
|
||||
27
js/angular/directive/slideBox.js
vendored
27
js/angular/directive/slideBox.js
vendored
@@ -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: '<div class="slider-slides" ng-transclude></div>',
|
||||
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) {
|
||||
|
||||
26
js/angular/directive/slideBoxPager.js
vendored
26
js/angular/directive/slideBoxPager.js
vendored
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,12 @@ describe('ionSlideBox', function() {
|
||||
|
||||
|
||||
describe('directive', function() {
|
||||
it('should error with nested ion-slides', function() {
|
||||
expect(function() {
|
||||
setup('', '<ion-slide> <ion-slide>Nested</ion-slide> </ion-slide>');
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
describe('selection', function() {
|
||||
it('should select first slide automatically', inject(function($rootScope, $timeout) {
|
||||
var el = setup('selected="$root.current"');
|
||||
@@ -140,16 +146,28 @@ describe('ionSlideBox', function() {
|
||||
it('should call when selected changes', inject(function($rootScope, $timeout) {
|
||||
$rootScope.changed = jasmine.createSpy('changed');
|
||||
var el = setup('selected="$root.current" on-slide-changed="changed($slideIndex)"');
|
||||
expect($rootScope.changed).not.toHaveBeenCalled();
|
||||
$timeout.flush();
|
||||
expect($rootScope.changed).toHaveBeenCalledWith(0);
|
||||
|
||||
$rootScope.changed.reset();
|
||||
$rootScope.$apply('current = 2');
|
||||
expect($rootScope.changed).not.toHaveBeenCalled();
|
||||
$timeout.flush();
|
||||
expect($rootScope.changed).toHaveBeenCalledWith(2);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('onSlideStart', function() {
|
||||
it('should call when animation starts', inject(function($rootScope, $timeout) {
|
||||
$rootScope.start = jasmine.createSpy('start');
|
||||
$rootScope.current = 1;
|
||||
var el = setup('selected="$root.current" on-slide-start="$root.start($slideIndex)">');
|
||||
expect($rootScope.start).toHaveBeenCalledWith(1);
|
||||
$timeout.flush();
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('delegate', function() {
|
||||
@@ -324,27 +342,38 @@ describe('ionSlideBox', function() {
|
||||
|
||||
it('when queueing, should only publish after final slide', inject(function($timeout, $rootScope) {
|
||||
$rootScope.changed = jasmine.createSpy('changed');
|
||||
var el = setup('selected="$root.current" on-slide-changed="$root.changed($slideIndex)"');
|
||||
$rootScope.start = jasmine.createSpy('start');
|
||||
var el = setup('selected="$root.current" on-slide-changed="$root.changed($slideIndex)" on-slide-start="$root.start($slideIndex)"');
|
||||
$timeout.flush();
|
||||
$rootScope.changed.reset();
|
||||
$rootScope.start.reset();
|
||||
|
||||
$del.select(1);
|
||||
$del.select(2);
|
||||
$del.select(1);
|
||||
|
||||
expect($rootScope.start).toHaveBeenCalledWith(1);
|
||||
$rootScope.start.reset();
|
||||
$timeout.flush();
|
||||
|
||||
// Scope data bindings not published
|
||||
expect($rootScope.changed).not.toHaveBeenCalled();
|
||||
expect($rootScope.current).toBe(0);
|
||||
// Elements look different, though.
|
||||
expect(slideDisplays(el)).toEqual(['previous', 'selected', 'next']);
|
||||
|
||||
expect($rootScope.start).toHaveBeenCalledWith(2);
|
||||
$rootScope.start.reset();
|
||||
$timeout.flush();
|
||||
|
||||
expect($rootScope.changed).not.toHaveBeenCalled();
|
||||
expect($rootScope.current).toBe(0);
|
||||
expect(slideDisplays(el)).toEqual(['', 'previous', 'selected']);
|
||||
|
||||
expect($rootScope.start).toHaveBeenCalledWith(1);
|
||||
$rootScope.start.reset();
|
||||
$timeout.flush();
|
||||
|
||||
expect($rootScope.changed).toHaveBeenCalledWith(1);
|
||||
expect($rootScope.current).toBe(1);
|
||||
expect(slideDisplays(el)).toEqual(['previous', 'selected', 'next']);
|
||||
|
||||
@@ -59,7 +59,6 @@ describe('<ion-slide-pager> directive', function() {
|
||||
var slideBoxCtrl = el.controller('ionSlideBox');
|
||||
var pagers = el.find('.slider-pager-page');
|
||||
|
||||
expect(slideBoxCtrl.selected()).toBe(0);
|
||||
pagers.eq(1).click();
|
||||
expect(slideBoxCtrl.selected()).toBe(0);
|
||||
expect($rootScope.click).toHaveBeenCalledWith(1);
|
||||
|
||||
Reference in New Issue
Block a user