Skip to content
This repository has been archived by the owner on May 10, 2018. It is now read-only.

Feat (attribute) : Infinite Loop Support #237

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9057960
feat (rn-carousel): add infinite loop support
dcjohnston Oct 27, 2014
6e44c8e
add looping for swipes
dcjohnston Oct 27, 2014
eb607bd
uncomment other examples in index.html
dcjohnston Oct 27, 2014
5f1dd02
fix slide count for repeat
dcjohnston Oct 28, 2014
804fe7a
fixed problem with dom copy insertion
dcjohnston Oct 28, 2014
5b2127e
added id's for selection only children li, not all descendants
dcjohnston Oct 28, 2014
db7fcfe
eliminate browser flicker
dcjohnston Oct 29, 2014
70c02e0
only add signalling directive to children if looping is active
dcjohnston Oct 29, 2014
1b1f036
namespace the emitted event
dcjohnston Oct 29, 2014
020b774
uncomment other demos
dcjohnston Oct 29, 2014
59ef8b1
update README
dcjohnston Oct 29, 2014
2806047
add tests
dcjohnston Oct 29, 2014
26f0100
fixed tabs as spaces emacs madness
dcjohnston Oct 29, 2014
ca40a1c
add proper dom manipulation when repeat collection changes
dcjohnston Oct 29, 2014
25286e1
dom manipulation on repeatCollection change is not working in the tes…
dcjohnston Oct 29, 2014
77333cb
fix else if case so that it properly handles collection with one element
dcjohnston Nov 3, 2014
23976f2
fix typo
dcjohnston Nov 3, 2014
490ab1b
run grunt to compile to dist/
dcjohnston Nov 3, 2014
b5a4e14
fix removing for case og for case of one element
dcjohnston Nov 3, 2014
7b96a36
simplify DOM insertion/deletion
dcjohnston Nov 4, 2014
e44e41c
make sure inserted virtual node doesnt end up on top of the controls
dcjohnston Nov 4, 2014
9b6b968
fix copy reference in non-ngrepeat element insertion
dcjohnston Nov 9, 2014
6d0e543
add lock check to scope.previousSlide
dcjohnston Nov 10, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ angular.module('MyApp', ['angular-carousel']);
- `rn-carousel-auto-slide` add this attribute to make the carousel slide automatically after given seconds (default=3)
- `rn-carousel-transition` : transition type, can be one of `slide, zoom, hexagon, slideAndFade, none`. (default=slide)
- `rn-carousel-locked`: two way binding boolean that lock/unlock the carousel
- `rn-carousel-loop` : make the carousel loop around from the first element to the last and vice versa. Note that this feature will be disabled if `rn-carousel-buffered` is also declared.

## Indicators

Expand Down
2 changes: 2 additions & 0 deletions dist/angular-carousel.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 104 additions & 11 deletions dist/angular-carousel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Angular Carousel - Mobile friendly touch carousel for AngularJS
* @version v0.3.5 - 2014-10-21
* @version v0.3.5 - 2014-11-09
* @link http://revolunet.github.com/angular-carousel
* @author Julien Bouquillon <[email protected]>
* @license MIT License, http://www.opensource.org/licenses/MIT
Expand Down Expand Up @@ -213,6 +213,18 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
};
})

.directive('signalRepeatDone', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
if (scope.$first || scope.$last){
scope.$emit('rnRepeatReady', element);
}
}
};

})

.directive('rnCarousel', ['$swipe', '$window', '$document', '$parse', '$compile', '$timeout', '$interval', 'computeCarouselSlideStyle', 'createStyleString', 'Tweenable',
function($swipe, $window, $document, $parse, $compile, $timeout, $interval, computeCarouselSlideStyle, createStyleString, Tweenable) {
// internal ids to allow multiple instances
Expand All @@ -233,6 +245,9 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
isBuffered = false,
repeatItem,
repeatCollection;

// check if looping is specified
var loop = angular.isDefined(tAttributes['rnCarouselLoop']);

// try to find an ngRepeat expression
// at this point, the attributes are not yet normalized so we need to try various syntax
Expand All @@ -250,12 +265,14 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
if (angular.isDefined(tAttributes['rnCarouselBuffered'])) {
// update the current ngRepeat expression and add a slice operator if buffered
isBuffered = true;
loop = false; //disable looping if buffering
repeatAttribute.value = repeatItem + ' in ' + repeatCollection + '|carouselSlice:carouselBufferIndex:carouselBufferSize';
if (trackProperty) {
repeatAttribute.value += ' track by ' + trackProperty;
}
}
isRepeatBased = true;
if (loop) angular.element(firstChild).attr('signal-repeat-done', '');
return false;
}
}
Expand All @@ -264,7 +281,62 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach

return function(scope, iElement, iAttributes, containerCtrl) {

carouselId++;
carouselId++;

iElement[0].id = 'carousel' + carouselId;
function produceVirtualSlides(event, element){
//head true if we are removing front-most clone
var head = event.targetScope.$last ? true : false;
var tail = event.targetScope.$first ? true : false;
var eleToRemove, copy;
if (head){
eleToRemove = document.querySelectorAll('#' + iElement[0].id + ' .rn-carousel-virtual-slide-head')[0];
copy = element.clone();
copy.addClass('rn-carousel-virtual-slide-head');
if (eleToRemove ) {
iElement[0].replaceChild(copy[0], eleToRemove);
} else {
iElement.prepend(copy);
}
}
if (tail){
eleToRemove = document.querySelectorAll('#'+ iElement[0].id + ' .rn-carousel-virtual-slide-tail')[0];
copy = element.clone();
copy.addClass('rn-carousel-virtual-slide-tail');
if (eleToRemove) {
iElement[0].replaceChild(copy[0], eleToRemove);
} else {
var controlsNode =
document.querySelectorAll('#' + iElement[0].id + ' .rn-carousel-controls');
iElement[0].insertBefore(copy[0], controlsNode[0]);
}
}
event.stopPropagation();
}

// add virtual slides for looping
if (loop){
if (!isRepeatBased){
var children = document.querySelectorAll('#' + iElement[0].id + '> li');
var firstCopy = angular.element(children[0]).clone();
var lastCopy = angular.element(children[children.length-1]).clone();
iElement.prepend(lastCopy);
var controlsNode =
document.querySelectorAll('#' + iElement[0].id + ' .rn-carousel-controls');
iElement[0].insertBefore(firstCopy[0], controlsNode[0]);

} else {
// this eliminates flicker caused by using $timeout
scope.$on('rnRepeatReady', function(event, element){
scope.$evalAsync(function(){
produceVirtualSlides(event, element);
});
});
}
}

//for displaying carousel controls
scope.loop = loop;

var defaultOptions = {
transitionType: iAttributes.rnCarouselTransition || 'slide',
Expand Down Expand Up @@ -299,8 +371,8 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
if(iAttributes.rnCarouselControls!==undefined) {
// dont use a directive for this
var tpl = '<div class="rn-carousel-controls">\n' +
' <span class="rn-carousel-control rn-carousel-control-prev" ng-click="prevSlide()" ng-if="carouselIndex > 0"></span>\n' +
' <span class="rn-carousel-control rn-carousel-control-next" ng-click="nextSlide()" ng-if="carouselIndex < ' + repeatCollection + '.length - 1"></span>\n' +
' <span class="rn-carousel-control rn-carousel-control-prev" ng-click="prevSlide()" ng-if="carouselIndex > 0 || loop"></span>\n' +
' <span class="rn-carousel-control rn-carousel-control-next" ng-click="nextSlide()" ng-if="carouselIndex < ' + repeatCollection + '.length - 1 || loop"></span>\n' +
'</div>';
iElement.append($compile(angular.element(tpl))(scope));
}
Expand Down Expand Up @@ -329,16 +401,19 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach

function updateSlidesPosition(offset) {
// manually apply transformation to carousel childrens
// todo : optim : apply only to visible items
// todo : optim : apply only to visible items
var x = scope.carouselBufferIndex * 100 + offset;
if (loop) {
x -= 100;
}
angular.forEach(getSlidesDOM(), function(child, index) {
child.style.cssText = createStyleString(computeCarouselSlideStyle(index, x, options.transitionType));
});
}

scope.nextSlide = function(slideOptions) {
var index = scope.carouselIndex + 1;
if (index > currentSlides.length - 1) {
if (index > currentSlides.length - 1 && !loop) {
index = 0;
}
if (!locked) {
Expand All @@ -348,18 +423,20 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach

scope.prevSlide = function(slideOptions) {
var index = scope.carouselIndex - 1;
if (index < 0) {
if (index < 0 && !loop) {
index = currentSlides.length - 1;
}
goToSlide(index, slideOptions);
if (!locked) {
goToSlide(index, slideOptions);
}
};

function goToSlide(index, slideOptions) {
// move a to the given slide index
if (index === undefined) {
index = scope.carouselIndex;
}

slideOptions = slideOptions || {};
if (slideOptions.animate === false || options.transitionType === 'none') {
locked = false;
Expand All @@ -384,11 +461,22 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
updateSlidesPosition(state.x);
},
finish: function() {

locked = false;
scope.$apply(function() {
scope.carouselIndex = index;
offset = index * -100;
updateBufferIndex();
if (loop && index === -1){
index = currentSlides.length -1;
goToSlide(index,
{animate: false});
}
if (loop && index === currentSlides.length){
index = 0;
goToSlide(index,
{animate: false});
}
});
}
});
Expand Down Expand Up @@ -440,6 +528,9 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
angular.forEach(getSlidesDOM(), function(node, index) {
currentSlides.push({id: index});
});
if (loop) {
currentSlides.length -= 2;
}
}

var autoSlider;
Expand Down Expand Up @@ -510,6 +601,8 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach

if (isRepeatBased) {
scope.$watchCollection(repeatCollection, function(newValue, oldValue) {
// TODO: add looping support to update virtual slides

//console.log('repeatCollection', arguments);
currentSlides = newValue;
goToSlide(scope.carouselIndex);
Expand Down Expand Up @@ -540,10 +633,10 @@ angular.module('angular-carousel').run(['$templateCache', function($templateCach
slidesMove = -Math[absMove >= 0 ? 'ceil' : 'floor'](absMove / elWidth),
shouldMove = Math.abs(absMove) > minMove;

if (currentSlides && (slidesMove + scope.carouselIndex) >= currentSlides.length) {
if (currentSlides && (slidesMove + scope.carouselIndex) >= currentSlides.length && !loop) {
slidesMove = currentSlides.length - 1 - scope.carouselIndex;
}
if ((slidesMove + scope.carouselIndex) < 0) {
if ((slidesMove + scope.carouselIndex) < 0 && !loop) {
slidesMove = -scope.carouselIndex;
}
var moveOffset = shouldMove ? slidesMove : 0;
Expand Down
4 changes: 2 additions & 2 deletions dist/angular-carousel.min.js

Large diffs are not rendered by default.

37 changes: 36 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,41 @@ <h3>Custom templates without ng-repeat and auto-slide</h3>
</div>
</div>
<br>
<div>
<h3>Custom templates with looping</h3>
<div class="details">
</div>
<div class="carousel-demo">
<ul rn-carousel rn-carousel-loop rn-carousel-controls class="carousel5">
<li>Slide 1</li>
<li>Slide 2</li>
<li>Slide 3</li>
<li>Slide 4</li>
<li>Slide 5</li>
<li>Slide 6</li>
<li>Slide 7</li>
<li>Slide 8</li>
<li>Slide 9</li>
</ul>
</div>
</div>
<br>
<br>
<div>
<h3>Looping with ng-repeat and autoscroll looping</h3>
<div class="details">
</div>
<div class="carousel-demo">
<ul rn-carousel rn-carousel-loop rn-carousel-auto-slide="3" rn-carousel-controls class="carousel5">
<li ng-repeat="slide in slides3">
<div ng-style="{'background-image': 'url(' + slide.img + ')'}" class="bgimage">
#{{ slide.id }}
</div>
</li>
</ul>
</div>
</div>
<br>
<div>
<h3>Lockable carousel</h3>
<div class="details">
Expand All @@ -128,7 +163,7 @@ <h3>Lockable carousel</h3>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-touch.min.js"></script>

<script src="./dist/angular-carousel.min.js"></script>
<script src="./dist/angular-carousel.js"></script>
<!--<script src="./src/angular-carousel.js"></script>
<script src="./src/directives/rn-carousel.js"></script>
<script src="./src/directives/rn-carousel-indicators.js"></script>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"karma-requirejs": "~0.2.1",
"karma-script-launcher": "~0.1.0",
"load-grunt-tasks": "~0.3.0",
"requirejs": "~2.1.11"
"requirejs": "~2.1.11",
"karma-coverage": "~0.2.6"
},
"scripts": {
"test": "karma start test/karma.conf.js --single-run --browsers Chrome",
Expand Down
Loading