The question has already been asked here and I may have found a solution. But I’ve got another problem…
(/!\ You don’t have to read the whole code to understand my problem or what I’ve made. You juste need my comments! 'cause if you read everything… You may be dead before finishing!)
Here is what I wanted to do (Sorry for the bad quality…):
I have 3 slides : Green, Red and Blue. When I’m on the Red slide, no problem. But when I’m on Green slide… We should see the red on the right but as you can see… There is the blue slide.
Here is my html code (a basic ion-slide-box but with a new directive “ion-slide-box-small”):
<ion-slide-box-small id="gallery">
<ion-slide>
<div class="bar bar-header bar_custom">
<div class="title">
GREEN
</div>
</div>
<div class="page_content">
<ion-scroll>
<div class="img_content"><img src="http://bit.ly/RTKBkx" /></div>
<div class="img_content"><img src="http://bit.ly/1kxffH5" /></div>
<div class="img_content"><img src="http://bit.ly/1pxptiI" /></div>
</ion-scroll>
</div>
</ion-slide>
<ion-slide>
<div class="bar bar-header bar_custom">
<div class="title">
RED
</div>
</div>
<div class="page_content">
<ion-scroll>
<div class="img_content"><img src="http://bit.ly/1nTSdjE" /></div>
<div class="img_content"><img src="http://bit.ly/1m3rOeT" /></div>
<div class="img_content"><img src="http://bit.ly/1kYIyH6" /></div>
<div class="img_content"><img src="http://bit.ly/1pJwH07" /></div>
<div class="img_content"><img src="http://bit.ly/1pJwFWi" /></div>
</ion-scroll>
</div>
</ion-slide>
<ion-slide>
<div class="bar bar-header bar_custom">
<div class="title">
BLUE
</div>
</div>
<div class="page_content">
<ion-scroll>
<div class="img_content"><img src="http://bit.ly/1nTRK0O" /></div>
<div class="img_content"><img src="http://bit.ly/1gTzVOH" /></div>
<div class="img_content"><img src="http://bit.ly/RTKg1g" /></div>
<div class="img_content"><img src="http://bit.ly/1u594BG" /></div>
<div class="img_content"><img src="http://bit.ly/1pxpjI5" /></div>
<div class="img_content"><img src="http://bit.ly/1mG7yS6" /></div>
</ion-scroll>
</div>
</ion-slide>
</ion-slide-box-small>
And I’ve created a new directive inspired by .directive(‘ionSlideBox’);. I copy the code from the directive ionSlideBox and directly in the ionic.bundle.js, I past (I’ve just changed the directives’ name):
/***** CRAZY TEST ***/
.directive('ionSlideBoxSmall', [
'$timeout',
'$compile',
'$ionicSlideBoxDelegate',
function($timeout, $compile, $ionicSlideBoxDelegate) {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
doesContinue: '@',
slideInterval: '@',
showPager: '@',
pagerClick: '&',
disableScroll: '@',
onSlideChanged: '&',
activeSlide: '=?'
},
controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var _this = this;
var continuous = $scope.$eval($scope.doesContinue) === true;
var slideInterval = continuous ? $scope.$eval($scope.slideInterval) || 4000 : 0;
var slider = new ionic.views.SliderSmall({
el: $element[0],
auto: slideInterval,
continuous: continuous,
startSlide: $scope.activeSlide,
slidesChanged: function() {
$scope.currentSlide = slider.currentIndex();
// Try to trigger a digest
$timeout(function() {});
},
callback: function(slideIndex) {
$scope.currentSlide = slideIndex;
$scope.onSlideChanged({index:$scope.currentSlide});
$scope.$parent.$broadcast('slideBox.slideChanged', slideIndex);
$scope.activeSlide = slideIndex;
// Try to trigger a digest
$timeout(function() {});
}
});
slider.enableSlide($scope.$eval($attrs.disableScroll) !== true);
$scope.$watch('activeSlide', function(nv) {
if(angular.isDefined(nv)){
slider.slide(nv);
}
});
$scope.$on('slideBox.nextSlide', function() {
slider.next();
});
$scope.$on('slideBox.prevSlide', function() {
slider.prev();
});
$scope.$on('slideBox.setSlide', function(e, index) {
slider.slide(index);
});
//Exposed for testing
this.__slider = slider;
var deregisterInstance = $ionicSlideBoxDelegate._registerInstance(slider, $attrs.delegateHandle);
$scope.$on('$destroy', deregisterInstance);
this.slidesCount = function() {
return slider.slidesCount();
};
this.onPagerClick = function(index) {
void 0;
$scope.pagerClick({index: index});
};
$timeout(function() {
slider.load();
});
}],
template: '<div class="slider">\
<div class="slider-slides" ng-transclude>\
</div>\
</div>',
link: function($scope, $element, $attr, slideBoxCtrl) {
// If the pager should show, append it to the slide box
if($scope.$eval($scope.showPager) !== false) {
var childScope = $scope.$new();
var pager = angular.element('<ion-pager></ion-pager>');
$element.append(pager);
$compile(pager)(childScope);
}
}
};
}])
.directive('ionSlideSmall', function() {
return {
restrict: 'E',
require: '^ionSlideBoxSmall',
compile: function(element, attr) {
element.addClass('slider-slide');
return function($scope, $element, $attr) {
};
},
};
})
.directive('ionPagerSmall', function() {
return {
restrict: 'E',
replace: true,
require: '^ionSlideBoxSmall',
template: '<div class="slider-pager"><span class="slider-pager-page" ng-repeat="slide in numSlides() track by $index" ng-class="{active: $index == currentSlide}" ng-click="pagerClick($index)"><i class="icon ion-record"></i></span></div>',
link: function($scope, $element, $attr, slideBox) {
var selectPage = function(index) {
var children = $element[0].children;
var length = children.length;
for(var i = 0; i < length; i++) {
if(i == index) {
children[i].classList.add('active');
} else {
children[i].classList.remove('active');
}
}
};
$scope.pagerClick = function(index) {
slideBox.onPagerClick(index);
};
$scope.numSlides = function() {
return new Array(slideBox.slidesCount());
};
$scope.$watch('currentSlide', function(v) {
selectPage(v);
});
}
};
});
Then I copy another piece of code and I paste it in the iconic.bundle.js (I changed only few lines… See below):
(function(ionic) {
'use strict';
ionic.views.SliderSmall = ionic.views.View.inherit({
initialize: function (options) {
var slider = this;
// utilities
var noop = function() {}; // simple no operation function
var offloadFn = function(fn) { setTimeout(fn || noop, 0) }; // offload a functions execution
// check browser capabilities
var browser = {
addEventListener: !!window.addEventListener,
touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
transitions: (function(temp) {
var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
for ( var i in props ) if (temp.style[ props[i] ] !== undefined) return true;
return false;
})(document.createElement('swipe'))
};
var container = options.el;
// quit if no root element
if (!container) return;
var element = container.children[0];
var slides, slidePos, width, length;
options = options || {};
var index = parseInt(options.startSlide, 10) || 0;
var speed = options.speed || 300;
options.continuous = options.continuous !== undefined ? options.continuous : true;
function setup() {
// cache slides
slides = element.children;
length = slides.length;
// set continuous to false if only one slide
if (slides.length < 2) options.continuous = false;
//special case if two slides
if (browser.transitions && options.continuous && slides.length < 3) {
element.appendChild(slides[0].cloneNode(true));
element.appendChild(element.children[1].cloneNode(true));
slides = element.children;
}
// create an array to store current positions of each slide
slidePos = new Array(slides.length);
// determine width of each slide
width = container.getBoundingClientRect().width - 80 || container.offsetWidth;
element.style.width = (slides.length * width) + 'px';
// stack elements
var pos = slides.length;
while(pos--) {
var slide = slides[pos];
slide.style.width = width + 'px';
slide.setAttribute('data-index', pos);
if (browser.transitions) {
slide.style.left = (pos * -width + 40) + 'px';
move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
}
}
// reposition elements before and after index
if (options.continuous && browser.transitions) {
move(circle(index-1), -width, 0);
move(circle(index+1), width, 0);
}
if (!browser.transitions) element.style.left = (index * -width) + 'px';
container.style.visibility = 'visible';
options.slidesChanged && options.slidesChanged();
}
function prev() {
if (options.continuous) slide(index-1);
else if (index) slide(index-1);
}
function next() {
if (options.continuous) slide(index+1);
else if (index < slides.length - 1) slide(index+1);
}
function circle(index) {
// a simple positive modulo using slides.length
return (slides.length + (index % slides.length)) % slides.length;
}
function slide(to, slideSpeed) {
// do nothing if already on requested slide
if (index == to) return;
if (browser.transitions) {
var direction = Math.abs(index-to) / (index-to); // 1: backward, -1: forward
// get the actual position of the slide
if (options.continuous) {
var natural_direction = direction;
direction = -slidePos[circle(to)] / width;
// if going forward but to < index, use to = slides.length + to
// if going backward but to > index, use to = -slides.length + to
if (direction !== natural_direction) to = -direction * slides.length + to;
}
var diff = Math.abs(index-to) - 1;
// move all the slides between index and to in the right direction
while (diff--) move( circle((to > index ? to : index) - diff - 1), width * direction, 0);
to = circle(to);
move(index, width * direction, slideSpeed || speed);
move(to, 0, slideSpeed || speed);
if (options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place
} else {
to = circle(to);
animate(index * -width, to * -width, slideSpeed || speed);
//no fallback for a circular continuous if the browser does not accept transitions
}
index = to;
offloadFn(options.callback && options.callback(index, slides[index]));
}
function move(index, dist, speed) {
translate(index, dist, speed);
slidePos[index] = dist;
}
function translate(index, dist, speed) {
var slide = slides[index];
var style = slide && slide.style;
if (!style) return;
style.webkitTransitionDuration =
style.MozTransitionDuration =
style.msTransitionDuration =
style.OTransitionDuration =
style.transitionDuration = speed + 'ms';
style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
style.msTransform =
style.MozTransform =
style.OTransform = 'translateX(' + dist + 'px)';
}
function animate(from, to, speed) {
// if not an animation, just reposition
if (!speed) {
element.style.left = to + 'px';
return;
}
var start = +new Date;
var timer = setInterval(function() {
var timeElap = +new Date - start;
if (timeElap > speed) {
element.style.left = to + 'px';
if (delay) begin();
options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);
clearInterval(timer);
return;
}
element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';
}, 4);
}
// setup auto slideshow
var delay = options.auto || 0;
var interval;
function begin() {
interval = setTimeout(next, delay);
}
function stop() {
delay = options.auto || 0;
clearTimeout(interval);
}
// setup initial vars
var start = {};
var delta = {};
var isScrolling;
// setup event capturing
var events = {
handleEvent: function(event) {
if(event.type == 'mousedown' || event.type == 'mouseup' || event.type == 'mousemove') {
event.touches = [{
pageX: event.pageX,
pageY: event.pageY
}];
}
switch (event.type) {
case 'mousedown': this.start(event); break;
case 'touchstart': this.start(event); break;
case 'touchmove': this.touchmove(event); break;
case 'mousemove': this.touchmove(event); break;
case 'touchend': offloadFn(this.end(event)); break;
case 'mouseup': offloadFn(this.end(event)); break;
case 'webkitTransitionEnd':
case 'msTransitionEnd':
case 'oTransitionEnd':
case 'otransitionend':
case 'transitionend': offloadFn(this.transitionEnd(event)); break;
case 'resize': offloadFn(setup); break;
}
if (options.stopPropagation) event.stopPropagation();
},
start: function(event) {
var touches = event.touches[0];
// measure start values
start = {
// get initial touch coords
x: touches.pageX,
y: touches.pageY,
// store time to determine touch duration
time: +new Date
};
// used for testing first move event
isScrolling = undefined;
// reset delta and end measurements
delta = {};
// attach touchmove and touchend listeners
if(browser.touch) {
element.addEventListener('touchmove', this, false);
element.addEventListener('touchend', this, false);
} else {
element.addEventListener('mousemove', this, false);
element.addEventListener('mouseup', this, false);
document.addEventListener('mouseup', this, false);
}
},
touchmove: function(event) {
// ensure swiping with one touch and not pinching
// ensure sliding is enabled
if (event.touches.length > 1 ||
event.scale && event.scale !== 1 ||
slider.slideIsDisabled) {
return;
}
if (options.disableScroll) event.preventDefault();
var touches = event.touches[0];
// measure change in x and y
delta = {
x: touches.pageX - start.x,
y: touches.pageY - start.y
}
// determine if scrolling test has run - one time test
if ( typeof isScrolling == 'undefined') {
isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) );
}
// if user is not trying to scroll vertically
if (!isScrolling) {
// prevent native scrolling
event.preventDefault();
// stop slideshow
stop();
// increase resistance if first or last slide
if (options.continuous) { // we don't add resistance at the end
translate(circle(index-1), delta.x + slidePos[circle(index-1)], 0);
translate(index, delta.x + slidePos[index], 0);
translate(circle(index+1), delta.x + slidePos[circle(index+1)], 0);
} else {
delta.x =
delta.x /
( (!index && delta.x > 0 // if first slide and sliding left
|| index == slides.length - 1 // or if last slide and sliding right
&& delta.x < 0 // and if sliding at all
) ?
( Math.abs(delta.x) / width + 1 ) // determine resistance level
: 1 ); // no resistance if false
// translate 1:1
translate(index-1, delta.x + slidePos[index-1], 0);
translate(index, delta.x + slidePos[index], 0);
translate(index+1, delta.x + slidePos[index+1], 0);
}
}
},
end: function(event) {
// measure duration
var duration = +new Date - start.time;
// determine if slide attempt triggers next/prev slide
var isValidSlide =
Number(duration) < 250 // if slide duration is less than 250ms
&& Math.abs(delta.x) > 20 // and if slide amt is greater than 20px
|| Math.abs(delta.x) > width/2; // or if slide amt is greater than half the width
// determine if slide attempt is past start and end
var isPastBounds =
!index && delta.x > 0 // if first slide and slide amt is greater than 0
|| index == slides.length - 1 && delta.x < 0; // or if last slide and slide amt is less than 0
if (options.continuous) isPastBounds = false;
// determine direction of swipe (true:right, false:left)
var direction = delta.x < 0;
// if not scrolling vertically
if (!isScrolling) {
if (isValidSlide && !isPastBounds) {
if (direction) {
if (options.continuous) { // we need to get the next in this direction in place
move(circle(index-1), -width, 0);
move(circle(index+2), width, 0);
} else {
move(index-1, -width, 0);
}
move(index, slidePos[index]-width, speed);
move(circle(index+1), slidePos[circle(index+1)]-width, speed);
index = circle(index+1);
} else {
if (options.continuous) { // we need to get the next in this direction in place
move(circle(index+1), width, 0);
move(circle(index-2), -width, 0);
} else {
move(index+1, width, 0);
}
move(index, slidePos[index]+width, speed);
move(circle(index-1), slidePos[circle(index-1)]+width, speed);
index = circle(index-1);
}
options.callback && options.callback(index, slides[index]);
} else {
if (options.continuous) {
move(circle(index-1), -width, speed);
move(index, 0, speed);
move(circle(index+1), width, speed);
} else {
move(index-1, -width, speed);
move(index, 0, speed);
move(index+1, width, speed);
}
}
}
// kill touchmove and touchend event listeners until touchstart called again
if(browser.touch) {
element.removeEventListener('touchmove', events, false)
element.removeEventListener('touchend', events, false)
} else {
element.removeEventListener('mousemove', events, false)
element.removeEventListener('mouseup', events, false)
document.removeEventListener('mouseup', events, false);
}
},
transitionEnd: function(event) {
if (parseInt(event.target.getAttribute('data-index'), 10) == index) {
if (delay) begin();
options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);
}
}
}
// Public API
this.update = function() {
setTimeout(setup);
};
this.setup = function() {
setup();
};
this.enableSlide = function(shouldEnable) {
if (arguments.length) {
this.slideIsDisabled = !shouldEnable;
}
return !this.slideIsDisabled;
},
this.slide = function(to, speed) {
// cancel slideshow
stop();
slide(to, speed);
};
this.prev = this.previous = function() {
// cancel slideshow
stop();
prev();
};
this.next = function() {
// cancel slideshow
stop();
next();
};
this.stop = function() {
// cancel slideshow
stop();
};
this.currentIndex = function() {
// return current index position
return index;
};
this.slidesCount = function() {
// return total number of slides
return length;
};
this.kill = function() {
// cancel slideshow
stop();
// reset element
element.style.width = '';
element.style.left = '';
// reset slides
var pos = slides.length;
while(pos--) {
var slide = slides[pos];
slide.style.width = '';
slide.style.left = '';
if (browser.transitions) translate(pos, 0, 0);
}
// removed event listeners
if (browser.addEventListener) {
// remove current event listeners
element.removeEventListener('touchstart', events, false);
element.removeEventListener('webkitTransitionEnd', events, false);
element.removeEventListener('msTransitionEnd', events, false);
element.removeEventListener('oTransitionEnd', events, false);
element.removeEventListener('otransitionend', events, false);
element.removeEventListener('transitionend', events, false);
window.removeEventListener('resize', events, false);
}
else {
window.onresize = null;
}
};
this.load = function() {
// trigger setup
setup();
// start auto slideshow if applicable
if (delay) begin();
// add event listeners
if (browser.addEventListener) {
// set touchstart event on element
if (browser.touch) {
element.addEventListener('touchstart', events, false);
} else {
element.addEventListener('mousedown', events, false);
}
if (browser.transitions) {
element.addEventListener('webkitTransitionEnd', events, false);
element.addEventListener('msTransitionEnd', events, false);
element.addEventListener('oTransitionEnd', events, false);
element.addEventListener('otransitionend', events, false);
element.addEventListener('transitionend', events, false);
}
// set resize event on window
window.addEventListener('resize', events, false);
} else {
window.onresize = function () { setup() }; // to play nice with old IE
}
}
}
});
})(ionic);
I changed only few lines. This one because I want to see 40px on the left and on the right. So the slide’s width is its container’s width - 80px:
// determine width of each slide
width = container.getBoundingClientRect().width || container.offsetWidth;
changed -->
// determine width of each slide
width = container.getBoundingClientRect().width - 80 || container.offsetWidth;
and this line the position my slider 40px to the left:
if (browser.transitions) {
slide.style.left = (pos * -width<img src="/uploads/default/869/ea3a7775b2c3c910.gif" width="206" height="360"> <img src="/uploads/default/869/ea3a7775b2c3c910.gif" width="206" height="360"> ) + 'px';
move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
}
changed -->
if (browser.transitions) {
slide.style.left = (pos * -width + 40) + 'px';
move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
}
Everything works great but… As you can se, when I’m on the first slide… All the other slides are on the right… But we can see all of them! I would like to be abble to see only the next slide. Not the others. I’m pretty sure that if I add another slide “Yellow” after “Blue”… It will be on the top of the others slides and visible on the right.
It’s a problem of position when we slide but I don’t understand the whole ionic.bundle.js code. I think it’s a complicated question but if you may have time to look at this problem, I would be so grateful!
Thanks a lot!