├── .bowerrc ├── app ├── scripts │ ├── app.js │ ├── services │ │ └── simplesliderservice.js │ └── directives │ │ └── simple-slider.js ├── styles │ └── main.css ├── index.html └── views │ └── main.html ├── .gitignore ├── .travis.yml ├── test ├── runner.html ├── spec │ ├── controllers │ │ └── main.js │ └── directives │ │ └── simple-slider.js └── .jshintrc ├── .jshintrc ├── .editorconfig ├── bower.json ├── README.md ├── karma.conf.js ├── karma-e2e.conf.js ├── package.json ├── dist ├── angular-simple-slider.min.js └── angular-simple-slider.js └── Gruntfile.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/scripts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularSimpleSlider', []); 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | .tmp 5 | .sass-cache 6 | app/bower_components 7 | -------------------------------------------------------------------------------- /app/styles/main.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | body { 3 | padding-top: 20px; 4 | padding-bottom: 20px; 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | before_script: 5 | - 'npm install -g bower grunt-cli' 6 | - 'bower install' 7 | -------------------------------------------------------------------------------- /test/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | End2end Test Runner 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/scripts/services/simplesliderservice.js: -------------------------------------------------------------------------------- 1 | var context = this; 2 | 3 | angular.module('angularSimpleSlider') 4 | .factory('SimpleSliderService', function () { 5 | 6 | 'use strict'; 7 | 8 | return typeof module != 'undefined' && module.exports ? // jshint ignore:line 9 | module.exports : 10 | context.SimpleSlider; 11 | }); 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "angular": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-simple-slider", 3 | "version": "1.0.0", 4 | "authors": [ 5 | "Ruy Adorno" 6 | ], 7 | "main": "dist/angular-simple-slider.js", 8 | "keywords": [ 9 | "slider", 10 | "simple", 11 | "gallery", 12 | "carousel", 13 | "angular", 14 | "images" 15 | ], 16 | "dependencies": { 17 | "angular": "^1.x.x" 18 | }, 19 | "devDependencies": { 20 | "angular-mocks": "^1.x.x", 21 | "angular-scenario": "^1.x.x", 22 | "SimpleSlider": "^0.x.x" 23 | }, 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /test/spec/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: MainCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('angularSimpleSliderApp')); 7 | 8 | var MainCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | MainCtrl = $controller('MainCtrl', { 15 | $scope: scope 16 | }); 17 | })); 18 | 19 | it('should attach a list of awesomeThings to the scope', function () { 20 | expect(scope.awesomeThings.length).toBe(3); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/spec/directives/simple-slider.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Directive: simpleSlider', function () { 4 | 5 | // load the directive's module 6 | beforeEach(module('angularSimpleSliderApp')); 7 | 8 | var element, 9 | scope; 10 | 11 | beforeEach(inject(function ($rootScope) { 12 | scope = $rootScope.$new(); 13 | })); 14 | 15 | it('should make hidden element visible', inject(function ($compile) { 16 | element = angular.element(''); 17 | element = $compile(element)(scope); 18 | expect(element.text()).toBe('this is the simpleSlider directive'); 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "after": false, 23 | "afterEach": false, 24 | "angular": false, 25 | "before": false, 26 | "beforeEach": false, 27 | "browser": false, 28 | "describe": false, 29 | "expect": false, 30 | "inject": false, 31 | "it": false, 32 | "jasmine": false, 33 | "spyOn": false 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular SimpleSlider 2 | 3 | version: 1.0.0 4 | 5 | 6 | ## About 7 | 8 | This **AngularJS** directive aims to provide a simple slider element for your application. 9 | 10 | 11 | ## Usage 12 | 13 | To use the directive, simply import one of the `dist/` files into your html and initiate the `angularSimpleSlider` module. 14 | 15 | The following example shows you how to configure a slider with 612x612 pixels using an fading animation: 16 | 17 | ```html 18 | 19 | 20 | 21 | 22 | 23 | 24 | ``` 25 | 26 | 27 | ## Examples 28 | 29 | Many others examples of using can be found on the [app/views/main.html](https://github.com/ruyadorno/angular-simple-slider/blob/master/app/views/main.html) file in this repository. 30 | 31 | 32 | ## More info 33 | 34 | This project is a simple directive implementation of [SimpleSlider](http://ruyadorno.github.io/SimpleSlider/). Please visit its page for more information. 35 | 36 | 37 | ## License 38 | 39 | MIT 40 | 41 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.10/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | // base path, that will be used to resolve files and exclude 7 | basePath: '', 8 | 9 | // testing framework to use (jasmine/mocha/qunit/...) 10 | frameworks: ['jasmine'], 11 | 12 | // list of files / patterns to load in the browser 13 | files: [ 14 | 'app/bower_components/angular/angular.js', 15 | 'app/bower_components/angular-mocks/angular-mocks.js', 16 | 'app/scripts/*.js', 17 | 'app/scripts/**/*.js', 18 | 'test/mock/**/*.js', 19 | 'test/spec/**/*.js' 20 | ], 21 | 22 | // list of files / patterns to exclude 23 | exclude: [], 24 | 25 | // web server port 26 | port: 8080, 27 | 28 | // level of logging 29 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 30 | logLevel: config.LOG_INFO, 31 | 32 | 33 | // enable / disable watching file and executing tests whenever any file changes 34 | autoWatch: false, 35 | 36 | 37 | // Start these browsers, currently available: 38 | // - Chrome 39 | // - ChromeCanary 40 | // - Firefox 41 | // - Opera 42 | // - Safari (only Mac) 43 | // - PhantomJS 44 | // - IE (only Windows) 45 | browsers: ['Chrome'], 46 | 47 | 48 | // Continuous Integration mode 49 | // if true, it capture browsers, run tests and exit 50 | singleRun: false 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /karma-e2e.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.10/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | // base path, that will be used to resolve files and exclude 7 | basePath: '', 8 | 9 | // testing framework to use (jasmine/mocha/qunit/...) 10 | frameworks: ['ng-scenario'], 11 | 12 | // list of files / patterns to load in the browser 13 | files: [ 14 | 'test/e2e/**/*.js' 15 | ], 16 | 17 | // list of files / patterns to exclude 18 | exclude: [], 19 | 20 | // web server port 21 | port: 8080, 22 | 23 | // level of logging 24 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 25 | logLevel: config.LOG_INFO, 26 | 27 | 28 | // enable / disable watching file and executing tests whenever any file changes 29 | autoWatch: false, 30 | 31 | 32 | // Start these browsers, currently available: 33 | // - Chrome 34 | // - ChromeCanary 35 | // - Firefox 36 | // - Opera 37 | // - Safari (only Mac) 38 | // - PhantomJS 39 | // - IE (only Windows) 40 | browsers: ['Chrome'], 41 | 42 | 43 | // Continuous Integration mode 44 | // if true, it capture browsers, run tests and exit 45 | singleRun: false 46 | 47 | // Uncomment the following lines if you are using grunt's server to run the tests 48 | // proxies: { 49 | // '/': 'http://localhost:9000/' 50 | // }, 51 | // URL root prevent conflicts with the site root 52 | // urlRoot: '_karma_' 53 | }); 54 | }; 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-simple-slider", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "angular": "^1.0.0" 6 | }, 7 | "devDependencies": { 8 | "grunt": "~0.4.1", 9 | "grunt-bump": "~0.0.x", 10 | "grunt-autoprefixer": "~0.4.0", 11 | "grunt-bower-install": "~0.7.0", 12 | "grunt-concurrent": "~0.4.1", 13 | "grunt-contrib-clean": "~0.5.0", 14 | "grunt-contrib-coffee": "~0.7.0", 15 | "grunt-contrib-compass": "~0.6.0", 16 | "grunt-contrib-concat": "~0.3.0", 17 | "grunt-contrib-connect": "~0.5.0", 18 | "grunt-contrib-copy": "~0.4.1", 19 | "grunt-contrib-cssmin": "~0.7.0", 20 | "grunt-contrib-htmlmin": "~0.1.3", 21 | "grunt-contrib-imagemin": "~0.3.0", 22 | "grunt-contrib-jshint": "~0.7.1", 23 | "grunt-contrib-uglify": "~0.2.0", 24 | "grunt-contrib-watch": "~0.5.2", 25 | "grunt-google-cdn": "~0.2.0", 26 | "grunt-newer": "~0.5.4", 27 | "grunt-ngmin": "~0.0.2", 28 | "grunt-rev": "~0.1.0", 29 | "grunt-svgmin": "~0.2.0", 30 | "grunt-usemin": "~2.0.0", 31 | "jshint-stylish": "~0.1.3", 32 | "load-grunt-tasks": "~0.2.0", 33 | "time-grunt": "~0.2.1", 34 | "karma-ng-scenario": "^0.1.0", 35 | "grunt-karma": "^0.6.2", 36 | "karma-script-launcher": "^0.1.0", 37 | "karma-chrome-launcher": "^0.1.2", 38 | "karma-firefox-launcher": "^0.1.3", 39 | "karma-html2js-preprocessor": "^0.1.0", 40 | "karma-jasmine": "^0.1.5", 41 | "karma-coffee-preprocessor": "^0.1.3", 42 | "requirejs": "^2.1.11", 43 | "karma-requirejs": "^0.2.1", 44 | "karma-phantomjs-launcher": "^0.1.2", 45 | "karma": "^0.10.9", 46 | "karma-ng-html2js-preprocessor": "^0.1.0" 47 | }, 48 | "engines": { 49 | "node": ">=0.8.0" 50 | }, 51 | "scripts": { 52 | "test": "grunt test" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/scripts/directives/simple-slider.js: -------------------------------------------------------------------------------- 1 | angular.module('angularSimpleSlider') 2 | .directive('simpleSlider', ['SimpleSliderService', '$timeout', function (SimpleSliderService, $timeout) { 3 | 4 | 'use strict'; 5 | 6 | return { 7 | 8 | restrict: 'AE', 9 | scope: { 10 | onChange: '&', 11 | current: '=?currentSlide', 12 | slider: '=?sliderInstance' 13 | }, 14 | 15 | link: function postLink(scope, element, attrs) { 16 | var options = attrs, disposeWatcher, disposeCurrentWatcher; 17 | 18 | if (attrs.onChange) { 19 | options.onChange = scope.onChange; 20 | } else { 21 | options.onChange = function (prev, next) { 22 | if (parseInt(scope.current) !== next) { 23 | $timeout(function () { 24 | scope.$apply(function () { 25 | scope.current = next; 26 | }); 27 | }); 28 | } 29 | }; 30 | } 31 | 32 | if (element[0].children.length === 0) { 33 | disposeWatcher = scope.$watch(function () { 34 | return element[0].children.length > 0; 35 | }, function (hasChildren) { 36 | if (hasChildren) { 37 | scope.slider = new SimpleSliderService(element[0], options); 38 | disposeWatcher(); 39 | } 40 | }); 41 | } else { 42 | scope.slider = new SimpleSliderService(element[0], options); 43 | } 44 | 45 | disposeCurrentWatcher = scope.$watch('current', function(next, prev) { 46 | if (next && next !== prev) { 47 | scope.slider.change(parseInt(next)); 48 | } 49 | }); 50 | 51 | // Clears up all functionality from directive when removed 52 | scope.$on('$destroy', function () { 53 | 54 | // Dispose watchers 55 | if (disposeWatcher) { 56 | disposeWatcher(); 57 | } 58 | disposeCurrentWatcher(); 59 | 60 | // Dispose SimpleSlider instance 61 | scope.slider.dispose(); 62 | }); 63 | } 64 | }; 65 | }]); 66 | -------------------------------------------------------------------------------- /app/views/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 40 | 41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /dist/angular-simple-slider.min.js: -------------------------------------------------------------------------------- 1 | "use strict";!function(context,definition){"undefined"!=typeof module&&module.exports?module.exports=definition():"function"==typeof define&&define.amd?define(function(){return window.SimpleSlider=definition()}):context.SimpleSlider=definition()}(this,function(){function getdef(val,def){return void 0===val||null===val||""===val?def:val}function getUnit(args,transitionProperty){for(var item,count=args.length,unit="";--count>=0;)item=args[count],"string"==typeof item&&(unit=item.replace(parseInt(item,10)+"",""));return"opacity"!==transitionProperty&&""===unit&&(unit="px"),unit}function testChildrenNum(value){if(0>=value){try{console.warn("A SimpleSlider main container elementshould have at least one child.")}catch(e){}return!0}return!1}function anim(target,prop,unit,transitionDuration,startTime,elapsedTime,fromValue,toValue,easeFunc){function loop(){window.requestAnimationFrame(function(time){0===startTime&&(startTime=time),anim(target,prop,unit,transitionDuration,startTime,time,fromValue,toValue,easeFunc)})}var newValue;return 0===startTime?loop():(newValue=easeFunc(elapsedTime-startTime,fromValue,toValue-fromValue,transitionDuration),void(transitionDuration>=elapsedTime-startTime?(target[prop]=newValue+unit,loop()):target[prop]=toValue+unit))}function startSlides(container,unit,startValue,visibleValue,transitionProperty){for(var imgs=[],i=container.children.length;--i>=0;)imgs[i]=container.children[i],imgs[i].style.position="absolute",imgs[i].style.top="0"+unit,imgs[i].style.left="0"+unit,imgs[i].style[transitionProperty]=startValue+unit,imgs[i].style.zIndex=0;return imgs[0].style[transitionProperty]=visibleValue+unit,imgs[0].style.zIndex=1,imgs}function manageRemovingSlideOrder(oldSlide,newSlide){return newSlide.style.zIndex=3,oldSlide&&(oldSlide.style.zIndex=1),newSlide}function manageInsertingSlideOrder(oldSlide,newSlide){return newSlide.style.zIndex=4,oldSlide&&(oldSlide.style.zIndex=2),newSlide}function parseStringToBoolean(value){return"false"===value?!1:value}function updateVisibility(slider){document[hidden]?slider.pauseAutoPlay():slider.resumeAutoPlay()}Date.now||(Date.now=function(){return(new Date).getTime()});for(var vendors=["webkit","moz"],i=0;i1},SimpleSlider.prototype.pauseAutoPlay=function(){this.isAutoPlayable()&&(this.remainingTime=this.delay-(Date.now()-this.intervalStartTime),window.clearTimeout(this.interval),this.interval=null)},SimpleSlider.prototype.resumeAutoPlay=function(){this.startInterval()},SimpleSlider.prototype.startAnim=function(target,fromValue,toValue){anim(target.style,this.trProp,this.unit,1e3*this.trTime,0,0,fromValue,toValue,this.ease)},SimpleSlider.prototype.remove=function(index){this.removed=manageRemovingSlideOrder(this.removed,this.imgs[index]),this.startAnim(this.imgs[index],this.visVal,this.endVal)},SimpleSlider.prototype.insert=function(index){this.inserted=manageInsertingSlideOrder(this.inserted,this.imgs[index]),this.startAnim(this.imgs[index],this.startVal,this.visVal)},SimpleSlider.prototype.change=function(newIndex){var prevIndex=this.actualIndex;this.remove(this.actualIndex),this.insert(newIndex),this.actualIndex=newIndex,(this.onChange||"[object Function]"==Object.prototype.toString.call(this.onChange))&&this.onChange(prevIndex,this.actualIndex)},SimpleSlider.prototype.next=function(){this.change(this.nextIndex()),this.startInterval()},SimpleSlider.prototype.prev=function(){this.change(this.prevIndex()),this.startInterval()},SimpleSlider.prototype.nextIndex=function(){var newIndex=this.actualIndex+1;return newIndex>=this.imgs.length&&(newIndex=0),newIndex},SimpleSlider.prototype.prevIndex=function(){var newIndex=this.actualIndex-1;return 0>newIndex&&(newIndex=this.imgs.length-1),newIndex},SimpleSlider.prototype.dispose=function(){if(window.clearTimeout(this.interval),this.imgs){for(var i=this.imgs.length;--i>=0;)this.imgs.pop();this.imgs=null}this.containerElem=null,this.interval=null,this.trProp=null,this.trTime=null,this.delay=null,this.startVal=null,this.endVal=null,this.autoPlay=null,this.actualIndex=null,this.inserted=null,this.removed=null,this.remainingTime=null},SimpleSlider}),angular.module("angularSimpleSlider",[]);var context=this;angular.module("angularSimpleSlider").factory("SimpleSliderService",function(){return"undefined"!=typeof module&&module.exports?module.exports:context.SimpleSlider}),angular.module("angularSimpleSlider").directive("simpleSlider",["SimpleSliderService","$timeout",function(SimpleSliderService,$timeout){return{restrict:"AE",scope:{onChange:"&",current:"=?currentSlide",slider:"=?sliderInstance"},link:function(scope,element,attrs){var disposeWatcher,options=attrs;attrs.onChange?options.onChange=scope.onChange:options.onChange=function(prev,next){parseInt(scope.current)!==next&&$timeout(function(){scope.$apply(function(){scope.current=next})})},0===element[0].children.length?disposeWatcher=scope.$watch(function(){return element[0].children.length>0},function(hasChildren){hasChildren&&(scope.slider=new SimpleSliderService(element[0],options),disposeWatcher())}):scope.slider=new SimpleSliderService(element[0],options),scope.$watch("current",function(next,prev){next!==undefined&&next!==prev&&scope.slider.change(parseInt(next))})}}}]); 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on 2014-03-07 using generator-angular 0.7.1 2 | 'use strict'; 3 | 4 | // # Globbing 5 | // for performance reasons we're only matching one level down: 6 | // 'test/spec/{,*/}*.js' 7 | // use this if you want to recursively match all subfolders: 8 | // 'test/spec/**/*.js' 9 | 10 | module.exports = function (grunt) { 11 | 12 | // Load grunt tasks automatically 13 | require('load-grunt-tasks')(grunt); 14 | 15 | // Time how long tasks take. Can help when optimizing build times 16 | require('time-grunt')(grunt); 17 | 18 | // Define the configuration for all the tasks 19 | grunt.initConfig({ 20 | 21 | // Project settings 22 | yeoman: { 23 | // configurable paths 24 | app: require('./bower.json').appPath || 'app', 25 | dist: 'dist' 26 | }, 27 | 28 | // Watches files for changes and runs tasks based on the changed files 29 | watch: { 30 | js: { 31 | files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], 32 | tasks: ['newer:jshint:all'], 33 | options: { 34 | livereload: true 35 | } 36 | }, 37 | jsTest: { 38 | files: ['test/spec/{,*/}*.js'], 39 | tasks: ['newer:jshint:test', 'karma'] 40 | }, 41 | styles: { 42 | files: ['<%= yeoman.app %>/styles/{,*/}*.css'], 43 | tasks: ['newer:copy:styles', 'autoprefixer'] 44 | }, 45 | gruntfile: { 46 | files: ['Gruntfile.js'] 47 | }, 48 | livereload: { 49 | options: { 50 | livereload: '<%= connect.options.livereload %>' 51 | }, 52 | files: [ 53 | '<%= yeoman.app %>/{,*/}*.html', 54 | '.tmp/styles/{,*/}*.css', 55 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 56 | ] 57 | } 58 | }, 59 | 60 | // The actual grunt server settings 61 | connect: { 62 | options: { 63 | port: 9000, 64 | // Change this to '0.0.0.0' to access the server from outside. 65 | hostname: 'localhost', 66 | livereload: 35729 67 | }, 68 | livereload: { 69 | options: { 70 | open: true, 71 | base: [ 72 | '.tmp', 73 | '<%= yeoman.app %>' 74 | ] 75 | } 76 | }, 77 | test: { 78 | options: { 79 | port: 9001, 80 | base: [ 81 | '.tmp', 82 | 'test', 83 | '<%= yeoman.app %>' 84 | ] 85 | } 86 | }, 87 | dist: { 88 | options: { 89 | base: '<%= yeoman.dist %>' 90 | } 91 | } 92 | }, 93 | 94 | // Make sure code styles are up to par and there are no obvious mistakes 95 | jshint: { 96 | options: { 97 | jshintrc: '.jshintrc', 98 | reporter: require('jshint-stylish') 99 | }, 100 | all: [ 101 | 'Gruntfile.js', 102 | '<%= yeoman.app %>/scripts/{,*/}*.js' 103 | ], 104 | test: { 105 | options: { 106 | jshintrc: 'test/.jshintrc' 107 | }, 108 | src: ['test/spec/{,*/}*.js'] 109 | } 110 | }, 111 | 112 | // Empties folders to start fresh 113 | clean: { 114 | dist: { 115 | files: [{ 116 | dot: true, 117 | src: [ 118 | '.tmp', 119 | '<%= yeoman.dist %>/*', 120 | '!<%= yeoman.dist %>/.git*' 121 | ] 122 | }] 123 | }, 124 | server: '.tmp' 125 | }, 126 | 127 | // Add vendor prefixed styles 128 | autoprefixer: { 129 | options: { 130 | browsers: ['last 1 version'] 131 | }, 132 | dist: { 133 | files: [{ 134 | expand: true, 135 | cwd: '.tmp/styles/', 136 | src: '{,*/}*.css', 137 | dest: '.tmp/styles/' 138 | }] 139 | } 140 | }, 141 | 142 | // Automatically inject Bower components into the app 143 | 'bower-install': { 144 | app: { 145 | html: '<%= yeoman.app %>/index.html', 146 | ignorePath: '<%= yeoman.app %>/' 147 | } 148 | }, 149 | 150 | 151 | 152 | 153 | 154 | // Renames files for browser caching purposes 155 | rev: { 156 | dist: { 157 | files: { 158 | src: [ 159 | '<%= yeoman.dist %>/scripts/{,*/}*.js', 160 | '<%= yeoman.dist %>/styles/{,*/}*.css', 161 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 162 | '<%= yeoman.dist %>/styles/fonts/*' 163 | ] 164 | } 165 | } 166 | }, 167 | 168 | // Reads HTML for usemin blocks to enable smart builds that automatically 169 | // concat, minify and revision files. Creates configurations in memory so 170 | // additional tasks can operate on them 171 | useminPrepare: { 172 | html: '<%= yeoman.app %>/index.html', 173 | options: { 174 | dest: '<%= yeoman.dist %>' 175 | } 176 | }, 177 | 178 | // Performs rewrites based on rev and the useminPrepare configuration 179 | usemin: { 180 | html: ['<%= yeoman.dist %>/{,*/}*.html'], 181 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], 182 | options: { 183 | assetsDirs: ['<%= yeoman.dist %>'] 184 | } 185 | }, 186 | 187 | // The following *-min tasks produce minified files in the dist folder 188 | imagemin: { 189 | dist: { 190 | files: [{ 191 | expand: true, 192 | cwd: '<%= yeoman.app %>/images', 193 | src: '{,*/}*.{png,jpg,jpeg,gif}', 194 | dest: '<%= yeoman.dist %>/images' 195 | }] 196 | } 197 | }, 198 | svgmin: { 199 | dist: { 200 | files: [{ 201 | expand: true, 202 | cwd: '<%= yeoman.app %>/images', 203 | src: '{,*/}*.svg', 204 | dest: '<%= yeoman.dist %>/images' 205 | }] 206 | } 207 | }, 208 | htmlmin: { 209 | dist: { 210 | options: { 211 | collapseWhitespace: true, 212 | collapseBooleanAttributes: true, 213 | removeCommentsFromCDATA: true, 214 | removeOptionalTags: true 215 | }, 216 | files: [{ 217 | expand: true, 218 | cwd: '<%= yeoman.dist %>', 219 | src: ['*.html', 'views/{,*/}*.html'], 220 | dest: '<%= yeoman.dist %>' 221 | }] 222 | } 223 | }, 224 | 225 | // Allow the use of non-minsafe AngularJS files. Automatically makes it 226 | // minsafe compatible so Uglify does not destroy the ng references 227 | ngmin: { 228 | dist: { 229 | files: [{ 230 | expand: true, 231 | cwd: '.tmp/concat/scripts', 232 | src: '*.js', 233 | dest: '.tmp/concat/scripts' 234 | }] 235 | } 236 | }, 237 | 238 | // Replace Google CDN references 239 | cdnify: { 240 | dist: { 241 | html: ['<%= yeoman.dist %>/*.html'] 242 | } 243 | }, 244 | 245 | // Copies remaining files to places other tasks can use 246 | copy: { 247 | dist: { 248 | files: [{ 249 | expand: true, 250 | dot: true, 251 | cwd: '<%= yeoman.app %>', 252 | dest: '<%= yeoman.dist %>', 253 | src: [ 254 | '*.{ico,png,txt}', 255 | '.htaccess', 256 | '*.html', 257 | 'views/{,*/}*.html', 258 | 'bower_components/**/*', 259 | 'images/{,*/}*.{webp}', 260 | 'fonts/*' 261 | ] 262 | }, { 263 | expand: true, 264 | cwd: '.tmp/images', 265 | dest: '<%= yeoman.dist %>/images', 266 | src: ['generated/*'] 267 | }] 268 | }, 269 | styles: { 270 | expand: true, 271 | cwd: '<%= yeoman.app %>/styles', 272 | dest: '.tmp/styles/', 273 | src: '{,*/}*.css' 274 | } 275 | }, 276 | 277 | // Run some tasks in parallel to speed up the build process 278 | concurrent: { 279 | server: [ 280 | 'copy:styles' 281 | ], 282 | test: [ 283 | 'copy:styles' 284 | ], 285 | dist: [ 286 | 'copy:styles', 287 | 'imagemin', 288 | 'svgmin' 289 | ] 290 | }, 291 | 292 | bump: { 293 | options: { 294 | files: ['package.json', 'bower.json', 'README.md'], 295 | updateConfigs: [], 296 | commit: true, 297 | commitMessage: 'Release v%VERSION%', 298 | commitFiles: ['-a'], // '-a' for all files 299 | createTag: true, 300 | tagName: 'v%VERSION%', 301 | tagMessage: 'Version %VERSION%', 302 | push: true, 303 | pushTo: 'origin master', 304 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe' 305 | } 306 | }, 307 | 308 | uglify: { 309 | options: { 310 | mangle: false, 311 | compress: { 312 | warnings: true 313 | } 314 | }, 315 | dist: { 316 | src: [ 317 | 'app/bower_components/SimpleSlider/dist/simpleslider.js', 318 | 'app/scripts/app.js', 319 | 'app/scripts/services/simplesliderservice.js', 320 | 'app/scripts/directives/simple-slider.js' 321 | ], 322 | dest: 'dist/angular-simple-slider.min.js' 323 | } 324 | }, 325 | 326 | concat: { 327 | options: { 328 | separator: ';', 329 | }, 330 | dist: { 331 | src: [ 332 | 'app/bower_components/SimpleSlider/dist/simpleslider.js', 333 | 'app/scripts/app.js', 334 | 'app/scripts/services/simplesliderservice.js', 335 | 'app/scripts/directives/simple-slider.js' 336 | ], 337 | dest: 'dist/angular-simple-slider.js' }, 338 | }, 339 | 340 | // Test settings 341 | karma: { 342 | unit: { 343 | configFile: 'karma.conf.js', 344 | singleRun: true 345 | } 346 | } 347 | }); 348 | 349 | 350 | grunt.registerTask('serve', function (target) { 351 | if (target === 'dist') { 352 | return grunt.task.run(['build', 'connect:dist:keepalive']); 353 | } 354 | 355 | grunt.task.run([ 356 | 'clean:server', 357 | 'bower-install', 358 | 'concurrent:server', 359 | 'autoprefixer', 360 | 'connect:livereload', 361 | 'watch' 362 | ]); 363 | }); 364 | 365 | grunt.registerTask('server', function () { 366 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); 367 | grunt.task.run(['serve']); 368 | }); 369 | 370 | grunt.registerTask('test', [ 371 | 'clean:server', 372 | 'concurrent:test', 373 | 'autoprefixer', 374 | 'connect:test', 375 | 'karma' 376 | ]); 377 | 378 | grunt.registerTask('release', [ 379 | 'uglify:dist', 380 | 'concat:dist', 381 | 'bump' 382 | ]); 383 | 384 | }; 385 | -------------------------------------------------------------------------------- /dist/angular-simple-slider.js: -------------------------------------------------------------------------------- 1 | (function (context, definition) { 2 | 3 | 'use strict'; 4 | 5 | if (typeof module != 'undefined' && module.exports) { 6 | module.exports = definition(); 7 | } else if (typeof define == 'function' && define.amd) { 8 | define(function() { 9 | return (window.SimpleSlider = definition()); 10 | }); 11 | } else { 12 | context.SimpleSlider = definition(); 13 | } 14 | 15 | })(this, function () { 16 | 17 | 'use strict'; 18 | 19 | // requestAnimationFrame polyfill 20 | 21 | if (!Date.now) 22 | Date.now = function() { return new Date().getTime(); }; 23 | 24 | var vendors = ['webkit', 'moz']; 25 | for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { 26 | var vp = vendors[i]; 27 | window.requestAnimationFrame = window[vp+'RequestAnimationFrame']; 28 | window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame'] || window[vp+'CancelRequestAnimationFrame']); 29 | } 30 | 31 | if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || // iOS6 is buggy 32 | !window.requestAnimationFrame || !window.cancelAnimationFrame) { 33 | var lastTime = 0; 34 | window.requestAnimationFrame = function(callback) { 35 | var now = Date.now(); 36 | var nextTime = Math.max(lastTime + 16, now); 37 | return setTimeout(function() { callback(lastTime = nextTime); }, nextTime - now); 38 | }; 39 | window.cancelAnimationFrame = clearTimeout; 40 | } 41 | 42 | // visibilitychange setup, from: https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API 43 | var hidden, visibilityChange, hasVisibilityHandler; 44 | if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 45 | hidden = "hidden"; 46 | visibilityChange = "visibilitychange"; 47 | } else if (typeof document.mozHidden !== "undefined") { 48 | hidden = "mozHidden"; 49 | visibilityChange = "mozvisibilitychange"; 50 | } else if (typeof document.msHidden !== "undefined") { 51 | hidden = "msHidden"; 52 | visibilityChange = "msvisibilitychange"; 53 | } else if (typeof document.webkitHidden !== "undefined") { 54 | hidden = "webkitHidden"; 55 | visibilityChange = "webkitvisibilitychange"; 56 | } 57 | 58 | // ------------------ 59 | 60 | function getdef(val, def){ 61 | return val===undefined || val===null || val==='' ? def : val; 62 | } 63 | 64 | // Extracts the unit from a css value 65 | function getUnit(args, transitionProperty) { 66 | 67 | var item; 68 | var count = args.length; 69 | var unit = ''; 70 | 71 | while (--count >= 0) { 72 | item = args[count]; 73 | if (typeof item === 'string') { 74 | unit = item 75 | .replace(parseInt(item, 10) + '', ''); 76 | } 77 | } 78 | 79 | // Defaults unit to px if transition property isn't opacity 80 | if (transitionProperty !== 'opacity' && unit === '') { 81 | unit = 'px'; 82 | } 83 | 84 | return unit; 85 | 86 | } 87 | 88 | // Test if have children and throw warning otherwise 89 | function testChildrenNum(value) { 90 | 91 | if (value <= 0) { 92 | try { 93 | console.warn( 94 | 'A SimpleSlider main container element' + 95 | 'should have at least one child.' 96 | ); 97 | } catch(e) {} 98 | 99 | return true; 100 | 101 | } else { 102 | 103 | return false; 104 | } 105 | 106 | } 107 | 108 | function anim(target, prop, unit, transitionDuration, startTime, elapsedTime, fromValue, toValue, easeFunc){ 109 | 110 | function loop() { 111 | 112 | window.requestAnimationFrame(function requestAnimationFunction(time){ 113 | 114 | // Starts time in the first anim iteration 115 | if (startTime === 0) { 116 | startTime = time; 117 | } 118 | 119 | anim(target, prop, unit, transitionDuration, startTime, time, fromValue, toValue, easeFunc); 120 | 121 | }); 122 | } 123 | 124 | var newValue; 125 | 126 | if (startTime === 0) { 127 | 128 | return loop(); 129 | 130 | } else { 131 | 132 | newValue = easeFunc(elapsedTime - startTime, fromValue, toValue - fromValue, transitionDuration); 133 | 134 | if (elapsedTime - startTime <= transitionDuration) { 135 | 136 | target[prop] = newValue + unit; 137 | 138 | loop(); 139 | 140 | } else { 141 | 142 | target[prop] = (toValue) + unit; 143 | } 144 | } 145 | 146 | } 147 | 148 | function startSlides(container, unit, startValue, visibleValue, transitionProperty) { 149 | 150 | var imgs = []; 151 | var i = container.children.length; 152 | 153 | while (--i >= 0) { 154 | imgs[i] = container.children[i]; 155 | imgs[i].style.position = 'absolute'; 156 | imgs[i].style.top = '0' + unit; 157 | imgs[i].style.left = '0' + unit; 158 | imgs[i].style[transitionProperty] = startValue + unit; 159 | imgs[i].style.zIndex = 0; 160 | } 161 | 162 | imgs[0].style[transitionProperty] = visibleValue + unit; 163 | imgs[0].style.zIndex = 1; 164 | 165 | return imgs; 166 | 167 | } 168 | 169 | function manageRemovingSlideOrder(oldSlide, newSlide) { 170 | 171 | newSlide.style.zIndex = 3; 172 | 173 | if (oldSlide) { 174 | oldSlide.style.zIndex = 1; 175 | } 176 | 177 | return newSlide; 178 | } 179 | 180 | function manageInsertingSlideOrder(oldSlide, newSlide) { 181 | 182 | newSlide.style.zIndex = 4; 183 | 184 | if (oldSlide) { 185 | oldSlide.style.zIndex = 2; 186 | } 187 | 188 | return newSlide; 189 | } 190 | 191 | function parseStringToBoolean(value) { 192 | 193 | if (value === 'false') { 194 | return false; 195 | } else { 196 | return value; 197 | } 198 | 199 | } 200 | 201 | function updateVisibility(slider) { 202 | if (document[hidden]) { 203 | slider.pauseAutoPlay(); 204 | } else { 205 | slider.resumeAutoPlay(); 206 | } 207 | } 208 | 209 | // ------------------ 210 | 211 | var SimpleSlider = function(containerElem, options){ 212 | 213 | this.containerElem = containerElem; 214 | this.interval = null; 215 | 216 | // User might not send any custom options at all 217 | if( !options ) { 218 | options = {}; 219 | } 220 | 221 | var width = parseInt(this.containerElem.style.width || this.containerElem.offsetWidth, 10); 222 | 223 | // Get user defined options or its default values 224 | this.trProp = getdef(options.transitionProperty, 'left'); 225 | this.trTime = getdef(options.transitionDuration, 0.5); 226 | this.delay = getdef(options.transitionDelay, 3) * 1000; 227 | this.unit = getUnit([options.startValue, options.visibleValue, options.endValue], this.trProp); 228 | this.startVal = parseInt(getdef(options.startValue, -width + this.unit), 10); 229 | this.visVal = parseInt(getdef(options.visibleValue, '0' + this.unit), 10); 230 | this.endVal = parseInt(getdef(options.endValue, width + this.unit), 10); 231 | this.autoPlay = getdef(parseStringToBoolean(options.autoPlay), true); 232 | this.ease = getdef(options.ease, SimpleSlider.defaultEase); 233 | this.onChange = getdef(options.onChange, null); 234 | 235 | this.init(); 236 | }; 237 | 238 | SimpleSlider.defaultEase = function (time, begin, change, duration) { 239 | 240 | if ((time = time / (duration / 2)) < 1) { 241 | return change / 2 * time * time * time + begin; 242 | } else { 243 | return change / 2 * ((time -= 2) * time * time + 2) + begin; 244 | } 245 | 246 | }; 247 | 248 | SimpleSlider.easeNone = function(time, begin, change, duration) { 249 | 250 | return change * time / duration + begin; 251 | 252 | }; 253 | 254 | SimpleSlider.prototype.init = function() { 255 | 256 | this.reset(); 257 | this.configSlideshow(); 258 | 259 | }; 260 | 261 | SimpleSlider.prototype.reset = function() { 262 | 263 | if (testChildrenNum(this.containerElem.children.length)) { 264 | return; // Skip reset logic if don't have children 265 | } 266 | 267 | this.containerElem.style.position = 'relative'; 268 | this.containerElem.style.overflow = 'hidden'; 269 | this.containerElem.style.display = 'block'; 270 | 271 | this.imgs = startSlides(this.containerElem, this.unit, this.startVal, this.visVal, this.trProp); 272 | 273 | this.actualIndex = 0; 274 | this.inserted = null; 275 | this.removed = null; 276 | this.remainingTime = this.delay; 277 | 278 | }; 279 | 280 | SimpleSlider.prototype.configSlideshow = function() { 281 | 282 | if (!this.imgs) { 283 | return false; 284 | } 285 | 286 | this.startInterval(); 287 | 288 | }; 289 | 290 | SimpleSlider.prototype.startInterval = function () { 291 | 292 | var self = this; 293 | 294 | if (!this.isAutoPlayable()) { 295 | return; 296 | } 297 | 298 | if (this.interval) { 299 | window.clearTimeout(this.interval); 300 | } 301 | 302 | // Slideshow/autoPlay timing logic 303 | (function setInterval() { 304 | self.intervalStartTime = Date.now(); 305 | self.interval = window.setTimeout(function(){ 306 | 307 | self.intervalStartTime = Date.now(); 308 | self.remainingTime = self.delay; // resets time, used by pause/resume logic 309 | 310 | self.change(self.nextIndex()); 311 | 312 | // loops 313 | setInterval(); 314 | 315 | }, self.remainingTime); 316 | })(); 317 | 318 | // Handles user leaving/activating the current page/tab 319 | (function handleVisibilityChange() { 320 | 321 | if (!hasVisibilityHandler && typeof document.addEventListener !== "undefined") { 322 | 323 | document.addEventListener(visibilityChange, function onVisibilityChange() { 324 | 325 | updateVisibility(self); 326 | }, false); 327 | 328 | // only assign handler once 329 | hasVisibilityHandler = true; 330 | } 331 | })(); 332 | 333 | }; 334 | 335 | SimpleSlider.prototype.isAutoPlayable = function () { 336 | return this.autoPlay && this.imgs.length > 1; 337 | }; 338 | 339 | SimpleSlider.prototype.pauseAutoPlay = function () { 340 | 341 | if (!this.isAutoPlayable()) { 342 | return; 343 | } 344 | 345 | this.remainingTime = (this.delay) - (Date.now() - this.intervalStartTime); 346 | 347 | window.clearTimeout(this.interval); 348 | this.interval = null; 349 | 350 | }; 351 | 352 | SimpleSlider.prototype.resumeAutoPlay = function () { 353 | 354 | this.startInterval(); 355 | 356 | }; 357 | 358 | SimpleSlider.prototype.startAnim = function(target, fromValue, toValue){ 359 | 360 | anim(target.style, this.trProp, this.unit, this.trTime * 1000, 0, 0, fromValue, toValue, this.ease); 361 | 362 | }; 363 | 364 | SimpleSlider.prototype.remove = function(index){ 365 | 366 | this.removed = manageRemovingSlideOrder(this.removed, this.imgs[index]); 367 | 368 | this.startAnim(this.imgs[index], this.visVal, this.endVal); 369 | 370 | }; 371 | 372 | SimpleSlider.prototype.insert = function(index){ 373 | 374 | this.inserted = manageInsertingSlideOrder(this.inserted, this.imgs[index]); 375 | 376 | this.startAnim(this.imgs[index], this.startVal, this.visVal); 377 | 378 | }; 379 | 380 | SimpleSlider.prototype.change = function(newIndex){ 381 | 382 | var prevIndex = this.actualIndex; 383 | 384 | this.remove(this.actualIndex); 385 | this.insert(newIndex); 386 | 387 | this.actualIndex = newIndex; 388 | 389 | if (this.onChange || 390 | Object.prototype.toString.call(this.onChange) == '[object Function]') { 391 | 392 | this.onChange(prevIndex, this.actualIndex); 393 | } 394 | 395 | }; 396 | 397 | SimpleSlider.prototype.next = function(){ 398 | 399 | this.change(this.nextIndex()); 400 | 401 | this.startInterval(); 402 | 403 | }; 404 | 405 | SimpleSlider.prototype.prev = function(){ 406 | 407 | this.change(this.prevIndex()); 408 | 409 | this.startInterval(); 410 | 411 | }; 412 | 413 | SimpleSlider.prototype.nextIndex = function(){ 414 | 415 | var newIndex = this.actualIndex+1; 416 | 417 | if (newIndex >= this.imgs.length) { 418 | newIndex = 0; 419 | } 420 | 421 | return newIndex; 422 | 423 | }; 424 | 425 | SimpleSlider.prototype.prevIndex = function(){ 426 | 427 | var newIndex = this.actualIndex-1; 428 | 429 | if (newIndex < 0) { 430 | newIndex = this.imgs.length-1; 431 | } 432 | 433 | return newIndex; 434 | 435 | }; 436 | 437 | SimpleSlider.prototype.dispose = function(){ 438 | 439 | window.clearTimeout(this.interval); 440 | 441 | if (this.imgs) { 442 | var i = this.imgs.length; 443 | while (--i >= 0) { 444 | this.imgs.pop(); 445 | } 446 | this.imgs = null; 447 | } 448 | 449 | this.containerElem = null; 450 | this.interval = null; 451 | this.trProp = null; 452 | this.trTime = null; 453 | this.delay = null; 454 | this.startVal = null; 455 | this.endVal = null; 456 | this.autoPlay = null; 457 | this.actualIndex = null; 458 | this.inserted = null; 459 | this.removed = null; 460 | this.remainingTime = null; 461 | }; 462 | 463 | return SimpleSlider; 464 | 465 | }); 466 | 467 | ;'use strict'; 468 | 469 | angular.module('angularSimpleSlider', []); 470 | ;var context = this; 471 | 472 | angular.module('angularSimpleSlider') 473 | .factory('SimpleSliderService', function () { 474 | 475 | 'use strict'; 476 | 477 | return typeof module != 'undefined' && module.exports ? // jshint ignore:line 478 | module.exports : 479 | context.SimpleSlider; 480 | }); 481 | ;angular.module('angularSimpleSlider') 482 | .directive('simpleSlider', ['SimpleSliderService', '$timeout', function (SimpleSliderService, $timeout) { 483 | 484 | 'use strict'; 485 | 486 | return { 487 | 488 | restrict: 'AE', 489 | scope: { 490 | onChange: '&', 491 | current: '=?currentSlide', 492 | slider: '=?sliderInstance' 493 | }, 494 | 495 | link: function postLink(scope, element, attrs) { 496 | var options = attrs, disposeWatcher; 497 | 498 | if (attrs.onChange) { 499 | options.onChange = scope.onChange; 500 | } else { 501 | options.onChange = function (prev, next) { 502 | if (parseInt(scope.current) !== next) { 503 | $timeout(function () { 504 | scope.$apply(function () { 505 | scope.current = next; 506 | }); 507 | }); 508 | } 509 | }; 510 | } 511 | 512 | if (element[0].children.length === 0) { 513 | disposeWatcher = scope.$watch(function () { 514 | return element[0].children.length > 0; 515 | }, function (hasChildren) { 516 | if (hasChildren) { 517 | scope.slider = new SimpleSliderService(element[0], options); 518 | disposeWatcher(); 519 | } 520 | }); 521 | } else { 522 | scope.slider = new SimpleSliderService(element[0], options); 523 | } 524 | 525 | scope.$watch('current', function(next, prev) { 526 | if (next !== undefined && next !== prev) { 527 | scope.slider.change(parseInt(next)); 528 | } 529 | }); 530 | 531 | } 532 | }; 533 | }]); 534 | --------------------------------------------------------------------------------