diff --git a/config/build.config.js b/config/build.config.js
index bab712c335..fbffcd8480 100644
--- a/config/build.config.js
+++ b/config/build.config.js
@@ -57,6 +57,7 @@ module.exports = {
'js/views/listView.js',
'js/views/modalView.js',
'js/views/sideMenuView.js',
+ 'js/views/sliderView.js',
'js/views/toggleView.js'
],
diff --git a/js/angular/controller/slideBoxController.js b/js/angular/controller/slideBoxController.js
deleted file mode 100644
index 8c927cd706..0000000000
--- a/js/angular/controller/slideBoxController.js
+++ /dev/null
@@ -1,401 +0,0 @@
-IonicModule
-.controller('$ionSlideBox', [
- '$scope',
- '$element',
- '$log',
- '$document',
- '$$q',
- '$timeout',
- '$interval',
- '$$ionicAttachDrag',
- '$rootScope',
-function(scope, element, $log, $document, $$q, $timeout, $interval, $$ionicAttachDrag, $rootScope) {
- var self = this;
- var SLIDE_TRANSITION_DURATION = 250;
- var SLIDE_SUCCESS_VELOCITY = (1 / 4); // pixels / ms
-
- var container = jqLite(element[0].querySelector('.slider-slides'));
-
- // Live-updated list of slides
- var slideNodes = container[0].getElementsByTagName('ion-slide');
-
- // If we're already sliding and a new selection is triggered, add it to the queue,
- // to be taken off once the current slide animation is done
- var slideQueue = [];
-
- // Whether we're currently sliding through the slideQueue
- var isSliding = false;
-
- var slideCount = 0;
- var selectedIndex = -1;
- var isLoop = false;
-
- self.element = element;
-
- self.autoPlay = autoPlay;
- self.count = count;
- self.enableSlide = enableSlide;
- self.isValidIndex = isValidIndex;
- self.loop = loop;
- self.next = next;
- self.onAddSlide = onAddSlide;
- self.onRemoveSlide = onRemoveSlide;
- self.previous = previous;
- self.select = select;
- self.selected = selected;
-
- $$ionicAttachDrag(scope, container, {
- getDistance: function () { return container.prop('offsetWidth'); },
- onDragStart: onDragStart,
- onDrag: onDrag,
- onDragEnd: onDragEnd
- });
-
- /****** DEPRECATED, as of v1.0.0-beta14 ********/
- self.update = deprecated.method(
- '$ionicSlideBoxDelegate.update() has been deprecated! Slidebox updates on its own now.',
- $log.warn,
- angular.noop
- );
- self.currentIndex = deprecated.method(
- '$ionicSlideBoxDelegate.currentIndex() has been deprecated! Use self.selected() instead.',
- $log.warn,
- self.selected
- );
- self.slide = deprecated.method(
- '$ionicSlideBoxDelegate.slide(newIndex[, speed]) has been deprecated! Use self.select(newIndex[, speed]) instead.',
- $log.warn,
- self.select
- );
- self.slidesCount = deprecated.method(
- '$ionicSlideBoxDelegate.slidesCount() has been deprecated! Use self.count() instead.',
- $log.warn,
- self.count
- );
- self.stop = deprecated.method(
- '$ionicSlideBoxDelegate.stop() has been deprecated! Use $ionicSlideBoxDelegate.autoPlay(0) to stop instead.',
- $log.warn,
- function stopDeprecated() {
- self._stoppedInterval = self.autoPlayInterval;
- self.autoPlay(0);
- }
- );
- self.start = deprecated.method(
- '$ionicSlideBoxDelegate.start() has been deprecated! Use $ionicSlideBoxDelegate.autoPlay(newInterval) to start instead.',
- $log.warn,
- function startDeprecated() {
- self.autoPlay(self._stoppedInterval);
- }
- );
-
- /***************************
- * Public Methods
- ***************************/
-
- function autoPlay(newInterval) {
- self.autoPlayInterval = newInterval;
- $interval.cancel(self.autoPlayTimeout);
-
- if (angular.isNumber(newInterval) && newInterval > 0) {
- self.autoPlayTimeout = $interval(function() {
- if (!ionic.Utils.isScopeDisconnected(scope)) {
- self.select(self.next());
- }
- }, newInterval);
- }
- }
-
- function count() {
- return slideCount;
- }
-
- function enableSlide(enable) {
- if (arguments.length) self.dragDisabled = !enable;
- return !self.dragDisabled;
- }
-
- function isValidIndex(index) {
- return index > -1 && index < self.count();
- }
-
- function loop(loopValue) {
- if (arguments.length) isLoop = !!loopValue;
- return isLoop;
- }
-
- // gives the next index relative to the given index (default selectedIndex)
- function next(index) {
- index = arguments.length ? index : selectedIndex;
- var nextIndex = index + 1;
- if (nextIndex >= self.count()) {
- // We can only have a next if there's more than one item
- if (isLoop && self.count() > 1) return 0;
- return -1;
- }
- return nextIndex;
- }
-
- // Called by ionSlide directive
- function onAddSlide() {
- slideCount++;
- // If we're waiting for a certain slide to be added so we can select it,
- // or we just have selectedIndex at -1, go ahead and select.
- if ((!angular.isNumber(scope.selected) || scope.selected < self.count()) &&
- !self.isValidIndex(selectedIndex)) {
- enqueueSelect(self.isValidIndex(scope.selected) ? scope.selected : 0);
-
- } else if (self.isValidIndex(selectedIndex)) {
- // 'Refresh' the selection at end of digest when a new slide is added
- enqueueSelect(selectedIndex);
- }
- }
-
- // Called by ionSlide directive
- function onRemoveSlide() {
- slideCount--;
- if (selectedIndex >= self.count()) {
- enqueueSelect( Math.max(selectedIndex - 1, 0) );
-
- } else if (self.isValidIndex(selectedIndex)) {
- // 'Refresh' the selection at end of digest when a slide is removed
- enqueueSelect(selectedIndex);
- }
- }
-
- // gives the previous index relative to the given index (default selectedIndex)
- function previous(index) {
- index = arguments.length ? index : selectedIndex;
- var previousIndex = index - 1;
- if (previousIndex < 0) {
- // EDGE CASE: If there are only two slides and loop is enabled, we cannot have a previous
- // because previous === next. Only loop with previous if we have at least 3 slides
- if (isLoop && slideCount > 2) {
- return self.count() - 1;
- }
- return -1;
- }
- return previousIndex;
- }
-
- // adds data to the queue for selection.
- // Index can be either a number or a getter (to be called when starting the slide)
- function select(newIndex, transitionDuration, isDrag) {
- slideQueue.unshift([
- angular.isFunction(newIndex) ? newIndex : function() { return newIndex; },
- transitionDuration || SLIDE_TRANSITION_DURATION,
- !!isDrag
- ]);
- if (!isSliding) {
- runSelectQueue();
- }
- }
-
- function selected() {
- return selectedIndex;
- }
-
- /***************************
- * Private Methods
- ***************************/
-
- // If slides are added or removed, we only want to re-set the selected index
- // once per digest.
- function enqueueSelect(index) {
- enqueueSelect.index = index;
- if (!enqueueSelect.queued) {
- enqueueSelect.queued = true;
- scope.$$postDigest(function() {
- enqueueSelect.queued = false;
- select(enqueueSelect.index);
- });
- }
- }
-
- // Recursively takes an item off slideQueue array, selects it,
- // then repeats until nothing is left in the slideQueue.
- // Once slideQueue is empty, publishes the select data to scope.
- function runSelectQueue() {
- isSliding = slideQueue.length > 0;
- if (isSliding) {
- var data = slideQueue.pop();
- data[0] = data[0](); //index is a getter
- slideTo.apply(null, data).then(runSelectQueue);
- } else {
- // Publish the data to scope once we're all done
- scope.$evalAsync(function() {
- scope.selected = selectedIndex;
- scope.onSlideChanged({
- $index: selectedIndex, //DEPRECATED $index
- $slideIndex: selectedIndex
- });
- });
- }
- }
-
- function slideTo(newIndex, duration, isDrag) {
- newIndex = parseInt(newIndex);
- // Immediately finish invalid selection
- if (isNaN(newIndex) || !self.isValidIndex(newIndex)) return $$q.when();
-
- var deferred = $$q.defer();
- var delta = getDelta(selectedIndex, newIndex);
- var width = (slideNodes[selectedIndex] || slideNodes[newIndex] || {}).offsetWidth || 0;
- 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)) {
- // Instantly slide over if there's no change or we don't already have a selected index
- finishSliding();
- } else {
- // Make sure the newIndex is one of the three displayed slides before
- // trying to transition to it
- if (delta < 0) {
- direction = 'previous';
- translatePx = width;
- setDisplayedSlides(newIndex, selectedIndex, self.next());
- } else if (delta > 0) {
- direction = 'next';
- translatePx = -width;
- setDisplayedSlides(self.previous(), selectedIndex, newIndex);
- } else {
- direction = '';
- translatePx = 0;
- setDisplayedSlides(self.previous(), selectedIndex, self.next());
- }
-
- container.css(ionic.CSS.TRANSITION_DURATION, duration + 'ms');
- // Wait for transitionDuration css to apply...
- ionic.requestAnimationFrame(function() {
- container.css(ionic.CSS.TRANSFORM, 'translate3d(' + translatePx + 'px,0,0)');
- $timeout(finishSliding, duration, false);
- });
- }
-
- return deferred.promise;
-
- function finishSliding() {
- container.css(ionic.CSS.TRANSITION_DURATION, '0ms');
- // Wait for transitionDuration css to apply...
- ionic.requestAnimationFrame(function() {
- setSelectedSlide(newIndex);
- deferred.resolve();
- });
- }
- }
-
- function setSelectedSlide(newIndex) {
- selectedIndex = newIndex;
- setDisplayedSlides(self.previous(newIndex), newIndex, self.next(newIndex));
- container.css(ionic.CSS.TRANSFORM, '');
- }
-
- /**
- * setDisplayedSlides: set css to show only the three given slide indexes
- * note: prev & next could both be -1 if there's only one slide in the slidebox
- */
- var currentDisplayed = [];
- function setDisplayedSlides(previous, selected, next) {
- var newDisplayed = [
- previous !== -1 && slideNodes[previous],
- selected !== -1 && slideNodes[selected],
- next !== -1 && slideNodes[next]
- ];
- var oldSlide;
-
- // Hide & disconnect the currently displayed slides that aren't part of the new slides.
- for (var i = 0; i < currentDisplayed.length; i++) {
- oldSlide = currentDisplayed[i];
- if (oldSlide && newDisplayed.indexOf(oldSlide) === -1) {
- oldSlide.removeAttribute('slide-display');
- ionic.Utils.disconnectScope( jqLite(oldSlide).data('$ionSlideScope') );
- }
- }
-
- setDisplay(newDisplayed[0], 'previous');
- setDisplay(newDisplayed[1], 'selected');
- setDisplay(newDisplayed[2], 'next');
-
- function setDisplay(slide, display) {
- if (!slide) return;
- var slideScope = jqLite(slide).data('$ionSlideScope');
- if (slideScope && !ionic.Utils.isScopeDisconnected(scope)) {
- ionic.Utils.reconnectScope(slideScope);
- // Digest the slide so it updates before being shown
- if (!$rootScope.$$phase) slideScope.$digest();
- }
- slide.setAttribute('slide-display', display);
- }
-
- // Save the now displayed slides so we can check next time
- currentDisplayed = newDisplayed;
- }
-
- scope.$on('$ionic.reconnectScope', function() {
- setDisplayedSlides(self.previous(), self.selected(), self.next());
- });
-
- function getDelta(fromIndex, toIndex) {
- var difference = toIndex - fromIndex;
- if (!isLoop) return difference;
-
- // If looping is on, check for the looped difference.
- // For example, going from the first item to the last item
- // is actually a change of -1.
- var loopedDifference = 0;
- if (toIndex > fromIndex) {
- loopedDifference = toIndex - fromIndex - self.count();
- } else {
- loopedDifference = self.count() - fromIndex + toIndex;
- }
- if (Math.abs(loopedDifference) < Math.abs(difference)) {
- return loopedDifference;
- }
- return difference;
- }
-
-
- /********** DRAGGING **********/
- var dragWidth;
- function onDragStart() {
- if (self.dragDisabled || !self.count()) return false;
- if (!isSliding) {
- // Make sure that the correct slides are to the left and right
- // before we start dragging
- setSelectedSlide(selectedIndex);
- }
- dragWidth = slideNodes[selectedIndex].offsetWidth;
- }
-
- // percent is negative 0-1 for backward slide
- // positive 0-1 for forward slide
- function onDrag(percent) {
- // Only follow user's finger if we aren't currently sliding
- if (!isSliding) {
- container.css(ionic.CSS.TRANSFORM, 'translate3d(' + (-percent * dragWidth) + 'px,0,0)');
- }
- }
-
- function onDragEnd(percent, velocity) {
- var isSuccess = Math.abs(percent) > 0.5 || velocity > SLIDE_SUCCESS_VELOCITY;
-
- if (isSuccess) {
- var distanceRemaining = (1 - Math.abs(percent)) * dragWidth;
- 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.
- var nextIndex = percent > 0 ? self.next() : self.previous();
- return self.isValidIndex(nextIndex) ? nextIndex : selectedIndex;
- }, transitionDuration, true);
-
- } else if (!isSliding) {
- // If the drag failed, then just slide back to current slide being the center.
- slideTo(selectedIndex, SLIDE_TRANSITION_DURATION, true);
- }
- }
-
-}]);
diff --git a/js/angular/directive/slide.js b/js/angular/directive/slide.js
deleted file mode 100644
index 26f730faa0..0000000000
--- a/js/angular/directive/slide.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * @ngdoc directive
- * @name ionSlide
- * @parent ionic.directive:ionSlideBox
- * @module ionic
- *
- * @description
- * Displays a slide inside of a slidebox.
- *
- * For more complete examples, see {@link ionic.directive:ionSlideBox}.
- *
- * @usage
- * ```html
- *
- * 1
- * 2
- *
- * ```
- */
-IonicModule
-.directive('ionSlide', ['$timeout', function($timeout) {
- return {
- restrict: 'E',
- require: ['^ionSlideBox', '^^?ionSlide'],
- transclude: true,
- controller: angular.noop,
- link: postLink
- };
-
- 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();
-
- var childScope = scope.$new();
- element.data('$ionSlideScope', childScope);
-
- // Disconnect by default, will be reconnected if shown
- // ionic.Utils.disconnectScope(childScope);
-
- transclude(childScope, function(contents) {
- element.append(contents);
- });
-
- scope.$on('$destroy', function() {
- slideBoxCtrl.onRemoveSlide();
- element.remove();
- });
- }
-}]);
diff --git a/js/angular/directive/slideBox.js b/js/angular/directive/slideBox.js
index 37a1e4e609..c9b7587875 100644
--- a/js/angular/directive/slideBox.js
+++ b/js/angular/directive/slideBox.js
@@ -1,3 +1,4 @@
+
/**
* @ngdoc directive
* @name ionSlideBox
@@ -9,113 +10,177 @@
*
* 
*
- * Note: The slideBox will take up the whole width and height of its parent element.
- *
* @usage
* ```html
- *
- *
- *
- *
BLUE
- *
- *
- *
YELLOW
- *
- *
- *
PINK
- *
- *
- *
+ *
+ *
+ *
BLUE
+ *
+ *
+ *
YELLOW
+ *
+ *
+ *
PINK
+ *
+ *
* ```
*
- * @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 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}.
+ * @param {string=} delegate-handle The handle used to identify this slideBox
+ * with {@link ionic.service:$ionicSlideBoxDelegate}.
+ * @param {boolean=} does-continue Whether the slide box should loop.
+ * @param {boolean=} auto-play Whether the slide box should automatically slide. Default true if does-continue is true.
+ * @param {number=} slide-interval How many milliseconds to wait to change slides (if does-continue is true). Defaults to 4000.
+ * @param {boolean=} show-pager Whether a pager should be shown for this slide box.
+ * @param {expression=} pager-click Expression to call when a pager is clicked (if show-pager is true). Is passed the 'index' variable.
+ * @param {expression=} on-slide-changed Expression called whenever the slide is changed. Is passed an '$index' variable.
+ * @param {expression=} active-slide Model to bind the current slide to.
*/
IonicModule
.directive('ionSlideBox', [
- '$ionicSlideBoxDelegate',
- '$ionicHistory',
'$timeout',
-function($ionicSlideBoxDelegate, $ionicHistory, $timeout) {
-
+ '$compile',
+ '$ionicSlideBoxDelegate',
+function($timeout, $compile, $ionicSlideBoxDelegate) {
return {
restrict: 'E',
- controller: '$ionSlideBox',
- require: 'ionSlideBox',
+ replace: true,
transclude: true,
scope: {
- selected: '=?',
+ autoPlay: '=',
+ doesContinue: '@',
+ slideInterval: '@',
+ showPager: '@',
+ pagerClick: '&',
+ disableScroll: '@',
onSlideChanged: '&',
- onSlideStart: '&'
+ activeSlide: '=?'
},
- template: '