├── .codeclimate.yml
├── .csslintrc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .jshintrc
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── bower.json
├── dist
├── fonts
│ ├── ui-carousel.eot
│ ├── ui-carousel.svg
│ ├── ui-carousel.ttf
│ └── ui-carousel.woff
├── ui-carousel.css
├── ui-carousel.js
├── ui-carousel.min.css
└── ui-carousel.min.js
├── gulpfile.js
├── karma-dist-concatenated.conf.js
├── karma-dist-minified.conf.js
├── karma-src.conf.js
├── package.json
├── src
├── demo
│ ├── index.pug
│ ├── main.js
│ └── style.scss
└── ui-carousel
│ ├── controllers
│ └── carousel.controller.js
│ ├── directives
│ └── carousel.directive.js
│ ├── fonts
│ ├── ui-carousel.eot
│ ├── ui-carousel.svg
│ ├── ui-carousel.ttf
│ └── ui-carousel.woff
│ ├── providers
│ └── carousel.provider.js
│ ├── scss
│ ├── _fonts.scss
│ ├── base.scss
│ ├── carousel.scss
│ ├── mixin.scss
│ ├── ui-carousel.scss
│ └── variables.scss
│ ├── templates
│ └── carousel.template.pug
│ └── uiCarousel.module.js
└── test
└── unit
└── ui-carousel
├── configs
└── test.utils.js
├── controllers
└── carousel.controller.js
├── directives
└── carousel.directive.js
├── providers
└── carousel.provider.js
└── uiCarouselSpec.js
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | csslint:
4 | enabled: true
5 | duplication:
6 | enabled: true
7 | config:
8 | languages:
9 | - javascript
10 | eslint:
11 | enabled: true
12 | checks:
13 | complexity:
14 | enabled: false
15 | fixme:
16 | enabled: false
17 | ratings:
18 | paths:
19 | - "**.js"
20 | exclude_paths:
21 | - dist/
22 | - node_modules/
23 | - bower_components/
24 | - _gh_pages/
25 | - .tmp/
26 | - test/
27 | - src/demo/
28 | - gulpfile.js
29 |
--------------------------------------------------------------------------------
/.csslintrc:
--------------------------------------------------------------------------------
1 | --exclude-exts=.min.css
2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
3 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*{.,-}min.js
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ecmaFeatures:
2 | modules: true
3 | jsx: true
4 |
5 | env:
6 | amd: true
7 | browser: true
8 | es6: true
9 | jquery: true
10 | node: true
11 |
12 | # http://eslint.org/docs/rules/
13 | rules:
14 | # Possible Errors
15 | comma-dangle: [2, never]
16 | no-cond-assign: 2
17 | no-console: 0
18 | no-constant-condition: 2
19 | no-control-regex: 2
20 | no-debugger: 2
21 | no-dupe-args: 2
22 | no-dupe-keys: 2
23 | no-duplicate-case: 2
24 | no-empty: 2
25 | no-empty-character-class: 2
26 | no-ex-assign: 2
27 | no-extra-boolean-cast: 2
28 | no-extra-parens: 0
29 | no-extra-semi: 2
30 | no-func-assign: 2
31 | no-inner-declarations: [2, functions]
32 | no-invalid-regexp: 2
33 | no-irregular-whitespace: 2
34 | no-negated-in-lhs: 2
35 | no-obj-calls: 2
36 | no-regex-spaces: 2
37 | no-sparse-arrays: 2
38 | no-unexpected-multiline: 2
39 | no-unreachable: 2
40 | use-isnan: 2
41 | valid-jsdoc: 0
42 | valid-typeof: 2
43 |
44 | # Best Practices
45 | accessor-pairs: 2
46 | block-scoped-var: 0
47 | complexity: [2, 6]
48 | consistent-return: 0
49 | curly: 0
50 | default-case: 0
51 | dot-location: 0
52 | dot-notation: 0
53 | eqeqeq: 2
54 | guard-for-in: 2
55 | no-alert: 2
56 | no-caller: 2
57 | no-case-declarations: 2
58 | no-div-regex: 2
59 | no-else-return: 0
60 | no-empty-label: 2
61 | no-empty-pattern: 2
62 | no-eq-null: 2
63 | no-eval: 2
64 | no-extend-native: 2
65 | no-extra-bind: 2
66 | no-fallthrough: 2
67 | no-floating-decimal: 0
68 | no-implicit-coercion: 0
69 | no-implied-eval: 2
70 | no-invalid-this: 0
71 | no-iterator: 2
72 | no-labels: 0
73 | no-lone-blocks: 2
74 | no-loop-func: 2
75 | no-magic-number: 0
76 | no-multi-spaces: 0
77 | no-multi-str: 0
78 | no-native-reassign: 2
79 | no-new-func: 2
80 | no-new-wrappers: 2
81 | no-new: 2
82 | no-octal-escape: 2
83 | no-octal: 2
84 | no-proto: 2
85 | no-redeclare: 2
86 | no-return-assign: 2
87 | no-script-url: 2
88 | no-self-compare: 2
89 | no-sequences: 0
90 | no-throw-literal: 0
91 | no-unused-expressions: 2
92 | no-useless-call: 2
93 | no-useless-concat: 2
94 | no-void: 2
95 | no-warning-comments: 0
96 | no-with: 2
97 | radix: 2
98 | vars-on-top: 0
99 | wrap-iife: 2
100 | yoda: 0
101 |
102 | # Strict
103 | strict: 0
104 |
105 | # Variables
106 | init-declarations: 0
107 | no-catch-shadow: 2
108 | no-delete-var: 2
109 | no-label-var: 2
110 | no-shadow-restricted-names: 2
111 | no-shadow: 0
112 | no-undef-init: 2
113 | no-undef: 0
114 | no-undefined: 0
115 | no-unused-vars: 0
116 | no-use-before-define: 0
117 |
118 | # Node.js and CommonJS
119 | callback-return: 2
120 | global-require: 2
121 | handle-callback-err: 2
122 | no-mixed-requires: 0
123 | no-new-require: 0
124 | no-path-concat: 2
125 | no-process-exit: 2
126 | no-restricted-modules: 0
127 | no-sync: 0
128 |
129 | # Stylistic Issues
130 | array-bracket-spacing: 0
131 | block-spacing: 0
132 | brace-style: 0
133 | camelcase: 0
134 | comma-spacing: 0
135 | comma-style: 0
136 | computed-property-spacing: 0
137 | consistent-this: 0
138 | eol-last: 0
139 | func-names: 0
140 | func-style: 0
141 | id-length: 0
142 | id-match: 0
143 | indent: 0
144 | jsx-quotes: 0
145 | key-spacing: 0
146 | linebreak-style: 0
147 | lines-around-comment: 0
148 | max-depth: 0
149 | max-len: 0
150 | max-nested-callbacks: 0
151 | max-params: 0
152 | max-statements: [2, 30]
153 | new-cap: 0
154 | new-parens: 0
155 | newline-after-var: 0
156 | no-array-constructor: 0
157 | no-bitwise: 0
158 | no-continue: 0
159 | no-inline-comments: 0
160 | no-lonely-if: 0
161 | no-mixed-spaces-and-tabs: 0
162 | no-multiple-empty-lines: 0
163 | no-negated-condition: 0
164 | no-nested-ternary: 0
165 | no-new-object: 0
166 | no-plusplus: 0
167 | no-restricted-syntax: 0
168 | no-spaced-func: 0
169 | no-ternary: 0
170 | no-trailing-spaces: 0
171 | no-underscore-dangle: 0
172 | no-unneeded-ternary: 0
173 | object-curly-spacing: 0
174 | one-var: 0
175 | operator-assignment: 0
176 | operator-linebreak: 0
177 | padded-blocks: 0
178 | quote-props: 0
179 | quotes: 0
180 | require-jsdoc: 0
181 | semi-spacing: 0
182 | semi: 0
183 | sort-vars: 0
184 | space-after-keywords: 0
185 | space-before-blocks: 0
186 | space-before-function-paren: 0
187 | space-before-keywords: 0
188 | space-in-parens: 0
189 | space-infix-ops: 0
190 | space-return-throw-case: 0
191 | space-unary-ops: 0
192 | spaced-comment: 0
193 | wrap-regex: 0
194 |
195 | # ECMAScript 6
196 | arrow-body-style: 0
197 | arrow-parens: 0
198 | arrow-spacing: 0
199 | constructor-super: 0
200 | generator-star-spacing: 0
201 | no-arrow-condition: 0
202 | no-class-assign: 0
203 | no-const-assign: 0
204 | no-dupe-class-members: 0
205 | no-this-before-super: 0
206 | no-var: 0
207 | object-shorthand: 0
208 | prefer-arrow-callback: 0
209 | prefer-const: 0
210 | prefer-reflect: 0
211 | prefer-spread: 0
212 | prefer-template: 0
213 | require-yield: 0
214 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ._*
2 | .~lock.*
3 | .buildpath
4 | .DS_Store
5 | .idea
6 | .project
7 | .settings
8 |
9 | # Ignore node stuff
10 | node_modules/
11 | npm-debug.log
12 | libpeerconnection.log
13 |
14 | pakmanaged.js
15 |
16 | # OS-specific
17 | .DS_Store
18 |
19 | # Bower components
20 | bower_components
21 |
22 | # Demo and Github pages
23 | /demo/
24 | _gh-pages/
25 | .tmp/
26 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "bitwise": true,
3 | "camelcase": true,
4 | "curly": true,
5 | "eqeqeq": true,
6 | "es3": false,
7 | "forin": true,
8 | "freeze": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": "nofunc",
12 | "newcap": true,
13 | "noarg": true,
14 | "noempty": true,
15 | "nonbsp": true,
16 | "nonew": true,
17 | "plusplus": false,
18 | "quotmark": "single",
19 | "undef": true,
20 | "unused": false,
21 | "strict": false,
22 | "maxparams": 10,
23 | "maxdepth": 5,
24 | "maxstatements": 40,
25 | "maxcomplexity": 20,
26 | "maxlen": 120,
27 |
28 | "asi": false,
29 | "boss": false,
30 | "debug": false,
31 | "eqnull": true,
32 | "esnext": false,
33 | "evil": false,
34 | "expr": false,
35 | "funcscope": false,
36 | "globalstrict": false,
37 | "iterator": false,
38 | "lastsemic": false,
39 | "laxbreak": true,
40 | "laxcomma": true,
41 | "loopfunc": true,
42 | "maxerr": false,
43 | "moz": false,
44 | "multistr": true,
45 | "notypeof": false,
46 | "proto": false,
47 | "scripturl": false,
48 | "shadow": false,
49 | "sub": true,
50 | "supernew": false,
51 | "validthis": false,
52 | "noyield": false,
53 |
54 | "browser": true,
55 | "node": true,
56 | "esversion": 6,
57 |
58 | "globals": {
59 | "angular": false,
60 | "$": false
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Any hidden files
2 | **/.*
3 |
4 | # Build related stuff
5 | /src
6 | /test
7 | /demo
8 | /_gh-pages
9 | /.tmp
10 | /bower_components
11 | /node_modules
12 | gulpfile.js
13 | pakmanaged.js
14 | karma-dist-concatenated.conf.js
15 | karma-dist-minified.conf.js
16 | karma-src.conf.js
17 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: ["6.7.0"]
3 | before_script:
4 | - npm install -g bower
5 | - bower install
6 | - gulp build
7 |
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 mihnsen
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ui-carousel ([live demo](http://mihnsen.github.io/ui-carousel/)) [](https://badge.fury.io/js/angular-ui-carousel) [](https://badge.fury.io/bo/angular-ui-carousel) [](https://travis-ci.org/mihnsen/ui-carousel) [](https://codeclimate.com/github/mihnsen/ui-carousel)
2 | =========
3 |
4 | A simple, lightweight module for carousel in your AngularJS app, Inspired from [http://kenwheeler.github.io/slick/](http://kenwheeler.github.io/slick/). No Jquery required.
5 |
6 | [](http://mihnsen.github.io/ui-carousel)
7 |
8 | IE9+ (AngularJS v1.3.x no longer supports IE8) and the latest versions of Chrome, FireFox and Safari have been tested and are supported. If you do run across any issues, please submit a [new issue](https://github.com/mihnsen/ui-carousel/issues) and I'll take a look - or better yet - submit a PR with the bug fix and I'll merge it in.
9 |
10 | You can check out basic options and demo here: [http://mihnsen.github.io/ui-carousel](http://mihnsen.github.io/ui-carousel)
11 |
12 | #### First version
13 | With first version, we provide a directive ui-carousel. Basic support like slick carousel
14 | - arrows
15 | - autoplay
16 | - autoplaySpeed
17 | - cssEase
18 | - dots
19 | - fade
20 | - infinite
21 | - initialSlide
22 | - slidesToShow
23 | - slidesToScroll
24 | - speed
25 | - onBeforeChange
26 | - onAfterChange
27 | - onInit
28 |
29 | And with angularjs it also contain
30 | - Filtering
31 |
32 | #### Comming soon
33 | With next version we will provide:
34 |
35 | - Lazy loading
36 | - Vertical
37 | - Mouse swipe event
38 | - Touch swipe event
39 | - Responsive config
40 | - Variable width
41 | - Adaptive height
42 | - rtl
43 |
44 |
45 | Implementation
46 | ==============
47 |
48 | ### Requirements
49 |
50 | AngularJS is the only dependency. Animation is achieved with pure JS, jQuery not necessary.
51 |
52 | ### Installation
53 |
54 | You can install ui-carousel with Bower.
55 |
56 | bower install angular-ui-carousel --save
57 |
58 | You can also install ui-carousel with npm.
59 |
60 | npm install angular-ui-carousel --save
61 |
62 |
63 | And as always, you can download the source files straight from this repo - they're located in the `dist` dir. Be sure to include the minified version of both js and css files.
64 |
65 | ### Usage
66 | Inject module
67 | ```javascript
68 | angular.module('App', ['ui.carousel']);
69 | ```
70 |
71 | Directive configuration.
72 |
73 | ```javascript
74 |
82 |
83 |
84 | {{ item + 1 }}
85 |
86 |
87 | ```
88 |
89 | Provide Configuration:
90 | You can also using global configuration on angular setup like this:
91 |
92 | ```javascript
93 | app.run(['Carousel', (Carousel) => {
94 | Carousel.setOptions({
95 | arrows: true,
96 | autoplay: false,
97 | autoplaySpeed: 3000,
98 | cssEase: 'ease',
99 | dots: false,
100 |
101 | easing: 'linear',
102 | fade: false,
103 | infinite: true,
104 | initialSlide: 0,
105 |
106 | slidesToShow: 1,
107 | slidesToScroll: 1,
108 | speed: 500,
109 | });
110 | }]);
111 | ```
112 |
113 | ### Advanced customize
114 |
115 | ```javascript
116 |
123 |
124 |
125 |
126 |
127 |
128 | {{ item.name }}
129 | {{ item.description }}
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | ```
149 |
150 | Definitions
151 | ===========
152 |
153 | ### Settings
154 |
155 | Option | Type | Default | Description
156 | ------ | ---- | ------- | -----------
157 | autoplay | boolean | false | Enables auto play of slides
158 | autoplaySpeed | int | 3000 | Auto play change interval
159 | cssEase | string | 'ease' | CSS3 easing
160 | dots | boolean | false | Current slide indicator dots
161 | easing | string | 'linear' | animate() fallback easing
162 | fade | boolean | false | Enables fade
163 | arrows | boolean | true | Enable Next/Prev arrows
164 | infinite | boolean | true | Infinite looping
165 | initialSlide | integer | 0 | Slide to start on
166 | slidesToShow | int | 1 | # of slides to show at a time
167 | slidesToScroll | int | 1 | # of slides to scroll at a time
168 | speed | int | 300 | Transition speed
169 |
170 | ### Callbacks
171 |
172 | #### onInit()
173 | On carousel initialized
174 |
175 | #### onBeforeChange(currentSlide, nextSlide)
176 | Fires before slide change
177 |
178 | #### onAfterChange(currentSlide)
179 | Fires after slide change
180 |
181 | ```javascript
182 |
189 |
190 |
191 | {{ item + 1 }}
192 |
193 |
194 | ```
195 |
196 |
197 |
198 | Development
199 | ===========
200 |
201 | If you've forked or cloned the project and would like to make any sort of adjustments, there are few items to make note of. First, your system will need to have the following bits in place:
202 |
203 | - Node & NPM
204 | - gulp
205 | - karma
206 | - Scss
207 |
208 | Second, there are a few gulp tasks that you'll be able to leverage to help validate and prepare your changes for use.
209 |
210 | You can fire off a `gulp` or `gulp build` command manually at any time to lint, minify, and setup your demo (built in the _gh-pages dir) for testing.
211 |
212 | ```console
213 | gulp (or gulp build)
214 | ```
215 |
216 | Also, you can run `gulp dev` to lint, minify, and prep your demo for testing. Once the build is complete, it'll also fire off a `watch` so that any changes that are made to the the sass, js, and demo files will automatically trigger the build script to update your project.
217 |
218 | ```console
219 | gulp
220 | ```
221 |
222 | To run through the configured unit tests, you can run `gulp test`. This will fire off a series of tests that check that all default options are set correctly, all configurable options are able to be set correctly, and that all methods carry out the functionality that they're supposed to. These tests should let you know if any of the updates that you've made have negatively effected any preexisting functionality. Also, when the tests complete, there will be a test coverage report generated and stored in the `coverage` directory.
223 |
224 | ```console
225 | gulp test
226 | ```
227 |
228 | To public gh-pages you can using command bellow. A folder with name _gh-pages contain all file in your gh-pages repo will be generated.
229 | Read here to config your gh-pages:
230 | - https://help.github.com/articles/creating-project-pages-from-the-command-line/
231 | - https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/
232 | ```console
233 | gulp gh-pages
234 | ```
235 |
236 | Next, you'll want to do all of your development within three locations. If you add changes anywhere else, they're likely to be overwritten during the build process. These locations are:
237 |
238 | `src/ui-carousel/*.js` - for any script modifications.
239 |
240 | `src/ui-carousel/scss/*.scss` - for any style modifications.
241 |
242 | `src/demo/*` - for any modifications to the demo.
243 |
244 | Lastly, once you've made your changes and run through the appropriate gulp tasks, your changes should be baked and ready for you to consume - located in the `dist` directory as minified js and css files.
245 |
246 |
247 |
248 | ## Authors
249 | **Minh Nguyen**
250 |
251 | + [https://twitter.com/mihnsen](https://twitter.com/mihnsen)
252 |
253 | ## Credits
254 | UI-Carousel by [mihnsen](https://github.com/mihnsen) inspired by http://kenwheeler.github.io/slick/
255 |
256 | ## Copyright
257 | Copyright © 2016
258 |
259 | ## License
260 | UI-Carousel is under MIT license - http://www.opensource.org/licenses/mit-license.php
261 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-ui-carousel",
3 | "version": "0.1.10",
4 | "authors": [
5 | {
6 | "name": "mihnsen",
7 | "email": "minhnt.hut@gmail.com"
8 | }
9 | ],
10 | "description": "A simple, lightweight carousel for angularjs.",
11 | "main": [
12 | "dist/ui-carousel.js",
13 | "dist/ui-carousel.css"
14 | ],
15 | "keywords": [
16 | "ui-carousel",
17 | "carousel",
18 | "carousel",
19 | "angular-carousel",
20 | "angular-carousel",
21 | "angular-ui-carousel",
22 | "ng-carousel"
23 | ],
24 | "ignore": [
25 | "src",
26 | "test",
27 | "demo",
28 | ".tmp",
29 | "_gh-pages",
30 | "gulpfile.js",
31 | "karma-*.conf.js",
32 | "**/.*"
33 | ],
34 | "license": "MIT",
35 | "homepage": "https://mihnsen.github.com/ui-carousel",
36 | "dependencies": {},
37 | "devDependencies": {
38 | "angular-mocks": ">=1.2.0",
39 | "angular": "1.6",
40 | "angular-sanitize": ">=1.2.0",
41 | "prism": "^1.5.1"
42 | },
43 | "resolutions": {
44 | "angular": "1.6.3"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/dist/fonts/ui-carousel.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mihnsen/ui-carousel/2fea2a6e7e7b9d98434f49a420e261490ec87627/dist/fonts/ui-carousel.eot
--------------------------------------------------------------------------------
/dist/fonts/ui-carousel.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/dist/fonts/ui-carousel.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mihnsen/ui-carousel/2fea2a6e7e7b9d98434f49a420e261490ec87627/dist/fonts/ui-carousel.ttf
--------------------------------------------------------------------------------
/dist/fonts/ui-carousel.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mihnsen/ui-carousel/2fea2a6e7e7b9d98434f49a420e261490ec87627/dist/fonts/ui-carousel.woff
--------------------------------------------------------------------------------
/dist/ui-carousel.css:
--------------------------------------------------------------------------------
1 | .v-middle, .ui-carousel .carousel-btn {
2 | display: block;
3 | position: absolute;
4 | top: 50%;
5 | -webkit-transform: translate(0, -50%);
6 | -ms-transform: translate(0, -50%);
7 | -o-transform: translate(0, -50%);
8 | transform: translate(0, -50%); }
9 |
10 | @font-face {
11 | font-family: "ui-carousel";
12 | src: url("fonts/ui-carousel.eot");
13 | src: url("fonts/ui-carousel.eot?#iefix") format("embedded-opentype"), url("fonts/ui-carousel.woff") format("woff"), url("fonts/ui-carousel.ttf") format("truetype"), url("fonts/ui-carousel.svg#ui-carousel") format("svg");
14 | font-weight: normal;
15 | font-style: normal; }
16 |
17 | [data-icon]:before {
18 | font-family: "ui-carousel" !important;
19 | content: attr(data-icon);
20 | font-style: normal !important;
21 | font-weight: normal !important;
22 | font-variant: normal !important;
23 | text-transform: none !important;
24 | speak: none;
25 | line-height: 1;
26 | -webkit-font-smoothing: antialiased;
27 | -moz-osx-font-smoothing: grayscale; }
28 |
29 | [class^="ui-icon-"]:before,
30 | [class*=" ui-icon-"]:before {
31 | font-family: "ui-carousel" !important;
32 | font-style: normal !important;
33 | font-weight: normal !important;
34 | font-variant: normal !important;
35 | text-transform: none !important;
36 | speak: none;
37 | line-height: 1;
38 | -webkit-font-smoothing: antialiased;
39 | -moz-osx-font-smoothing: grayscale; }
40 |
41 | .ui-icon-prev:before {
42 | content: "\61"; }
43 |
44 | .ui-icon-next:before {
45 | content: "\62"; }
46 |
47 | .ui-icon-dot:before {
48 | content: "\63"; }
49 |
50 | .ui-carousel {
51 | display: block;
52 | margin-bottom: 30px; }
53 | .ui-carousel .carousel-wrapper {
54 | position: relative; }
55 | .ui-carousel .track-wrapper {
56 | position: relative;
57 | display: block;
58 | overflow: hidden;
59 | margin: 0;
60 | padding: 0; }
61 | .ui-carousel .track {
62 | position: relative;
63 | display: block;
64 | float: left; }
65 | .ui-carousel .slide {
66 | float: left;
67 | height: 100%;
68 | min-height: 1px; }
69 | .ui-carousel .carousel-btn {
70 | position: absolute;
71 | z-index: 10;
72 | background-color: transparent;
73 | outline: none;
74 | border: none;
75 | font-size: 20px;
76 | opacity: .75; }
77 | .ui-carousel .carousel-btn:hover {
78 | opacity: 1; }
79 | .ui-carousel .carousel-prev .carousel-btn {
80 | left: -25px; }
81 | .ui-carousel .carousel-next .carousel-btn {
82 | right: -25px; }
83 | .ui-carousel .carousel-disable {
84 | opacity: 0.5; }
85 | .ui-carousel .carousel-disable .carousel-btn:hover {
86 | opacity: .75; }
87 |
88 | .carousel-dots {
89 | position: absolute;
90 | bottom: -30px;
91 | display: block;
92 | width: 100%;
93 | padding: 0;
94 | margin: 0;
95 | list-style: none;
96 | text-align: center; }
97 | .carousel-dots li {
98 | position: relative;
99 | display: inline-block;
100 | width: 15px;
101 | height: 15px;
102 | margin: 0 5px;
103 | padding: 0;
104 | cursor: pointer; }
105 | .carousel-dots li button {
106 | font-size: 0;
107 | line-height: 0;
108 | display: block;
109 | width: 15px;
110 | height: 15px;
111 | padding: 5px;
112 | cursor: pointer;
113 | color: transparent;
114 | border: 0;
115 | outline: none;
116 | background: transparent; }
117 | .carousel-dots li button:before {
118 | font-family: ui-carousel;
119 | font-size: 9px;
120 | line-height: 15px;
121 | position: absolute;
122 | top: 0px;
123 | left: 0px;
124 | width: 15px;
125 | height: 15px;
126 | content: "\63";
127 | text-align: center;
128 | opacity: 0.25;
129 | color: black;
130 | -webkit-font-smoothing: antialiased; }
131 | .carousel-dots li.carousel-active button:before {
132 | opacity: .75; }
133 |
--------------------------------------------------------------------------------
/dist/ui-carousel.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | (function (angular) {
4 | // Create all modules and define dependencies to make sure they exist
5 | // and are loaded in the correct order to satisfy dependency injection
6 | // before all nested files are concatenated by Gulp
7 |
8 | // Config
9 | angular.module('ui.carousel.config', []).value('ui.carousel.config', {
10 | debug: true
11 | });
12 |
13 | // Modules
14 | angular.module('ui.carousel.providers', []);
15 | angular.module('ui.carousel.controllers', []);
16 | angular.module('ui.carousel.directives', []);
17 | angular.module('ui.carousel', ['ui.carousel.config', 'ui.carousel.directives', 'ui.carousel.controllers', 'ui.carousel.providers']);
18 | })(angular);
19 | 'use strict';
20 |
21 | /**
22 | * angular-ui-carousel
23 | * for example:
24 | * length = 8, show = 4, scroll = 3, current = 0
25 | * ---------
26 | * | |
27 | * |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
28 | * | |
29 | * ---------
30 | * rectangle is visible for users
31 | */
32 | angular.module('ui.carousel.controllers').controller('CarouselController', ['$scope', '$element', '$timeout', '$q', 'Carousel', '$window', function ($scope, $element, $timeout, $q, Carousel, $window) {
33 | var _this = this;
34 |
35 | /**
36 | * Initial carousel
37 | *
38 | * Mirgate to angularjs 1.6
39 | * @see https://docs.angularjs.org/guide/migration#commit-bcd0d4
40 | */
41 | this.$onInit = function () {
42 | _this.initOptions();
43 | _this.initRanges();
44 | _this.setProps();
45 | _this.setupInfinite();
46 | };
47 |
48 | /**
49 | * Init option based on directive config
50 | */
51 | this.initOptions = function () {
52 | _this.options = angular.extend({}, Carousel.getOptions());
53 |
54 | // TODO customize attribute from directive
55 | if (_this.initialSlide !== undefined) {
56 | _this.options.initialSlide = _this.initialSlide;
57 | }
58 | if (_this.fade !== undefined) {
59 | _this.options.fade = _this.fade;
60 | }
61 | if (_this.autoplay !== undefined) {
62 | _this.options.autoplay = _this.autoplay;
63 | }
64 | if (_this.autoplaySpeed !== undefined) {
65 | _this.options.autoplaySpeed = _this.autoplaySpeed;
66 | }
67 | if (_this.cssEase !== undefined) {
68 | _this.options.cssEase = _this.cssEase;
69 | }
70 | if (_this.speed !== undefined) {
71 | _this.options.speed = _this.speed;
72 | }
73 | if (_this.infinite !== undefined) {
74 | _this.options.infinite = _this.infinite;
75 | }
76 | if (_this.arrows !== undefined) {
77 | _this.options.arrows = _this.arrows;
78 | }
79 | if (_this.dots !== undefined) {
80 | _this.options.dots = _this.dots;
81 | }
82 | if (_this.visiblePrev !== undefined) {
83 | _this.options.visiblePrev = _this.visiblePrev;
84 | }
85 | if (_this.visibleNext !== undefined) {
86 | _this.options.visibleNext = _this.visibleNext;
87 | }
88 |
89 | // TODO write more options for fade mode
90 | // In fade mode we have to setting slides-to-show and slides-to-scroll
91 | // to 1 slide
92 | if (_this.options.fade) {
93 | _this.options.slidesToShow = 1;
94 | _this.options.slidesToScroll = 1;
95 | } else {
96 | if (_this.show) {
97 | _this.options.slidesToShow = _this.show;
98 | }
99 | if (_this.scroll) {
100 | _this.options.slidesToScroll = _this.scroll;
101 | }
102 | }
103 | };
104 |
105 | /**
106 | * init variables, slides, ..
107 | */
108 | this.initRanges = function () {
109 | if (!_this.slides) {
110 | _this.slides = [];
111 | }
112 |
113 | _this.isCarouselReady = false;
114 | _this.isTrackMoving = false;
115 | _this.track = $element.find('.track');
116 | _this.width = 1; // Fake width
117 | _this.currentSlide = _this.options.initialSlide;
118 | _this.trackStyle = {};
119 | _this.slideStyle = {};
120 |
121 | _this.isVisibleDots = false;
122 | _this.isVisiblePrev = _this.options.visiblePrev;
123 | _this.isVisibleNext = _this.options.visibleNext;
124 |
125 | _this.isClickablePrev = false;
126 | _this.isClickableNext = false;
127 |
128 | _this.animType = null;
129 | _this.transformType = null;
130 | _this.transitionType = null;
131 | };
132 |
133 | /**
134 | * Init UI and carousel track
135 | */
136 | this.initUI = function () {
137 | _this.width = $element[0].clientWidth;
138 |
139 | // Update track width first
140 | _this.initTrack();
141 |
142 | // Then item style
143 | $timeout(function () {
144 | _this.updateItemStyle();
145 | }, 200);
146 | };
147 |
148 | /**
149 | * update common style for each carousel item
150 | */
151 | this.updateItemStyle = function () {
152 | _this.itemWidth = _this.width / _this.options.slidesToShow;
153 | _this.slideStyle = {
154 | 'width': _this.itemWidth + 'px'
155 | };
156 | };
157 |
158 | /**
159 | * init carousel track
160 | * also make Carousel is Ready
161 | */
162 | this.initTrack = function () {
163 | var itemWidth = _this.width / _this.options.slidesToShow;
164 | var trackWidth = itemWidth * _this.slidesInTrack.length;
165 |
166 | _this.trackStyle.width = trackWidth + 'px';
167 |
168 | _this.slideHandler(_this.currentSlide).finally(function () {
169 | _this.isCarouselReady = true;
170 |
171 | if (!_this.options.fade) {
172 | _this.refreshTrackStyle();
173 | }
174 |
175 | // onInit callback
176 | if (_this.onInit) {
177 | _this.onInit();
178 | }
179 | }).catch(function () {
180 | // Catch err
181 | });
182 | };
183 |
184 | /**
185 | * @see https://github.com/kenwheeler/slick/blob/master/slick/slick.js#L680
186 | *
187 | * Sync slide to place it should be
188 | * for example:
189 | * - 9 total, 3 show, 3 scroll, current 1
190 | * => next index = 3 (previous index counted = 0)
191 | *
192 | * and scroll to next page:
193 | * - 6 total, 1 show, 1 scroll, current 0 => next index = 1
194 | * - 9 total, 3 show, 3 scroll, current 1 => next index = 3
195 | * - 9 total, 3 show, 3 scroll, current 3 => next index = 6
196 | * - 9 total, 3 show, 3 scroll, current 8 => next index = 3
197 | * - 8 total, 4 show, 3 scroll, current 1 => next index = 4
198 | */
199 | this.next = function () {
200 | if (!_this.isClickableNext) {
201 | return false;
202 | }
203 |
204 | var indexOffset = _this.getIndexOffset();
205 | var slideOffset = indexOffset === 0 ? _this.options.slidesToScroll : indexOffset;
206 |
207 | _this.slideHandler(_this.currentSlide + slideOffset).catch(function () {
208 | // Catch err
209 | });
210 | };
211 |
212 | /**
213 | * move to previous slide
214 | * same calculate with next
215 | * @see next function
216 | */
217 | this.prev = function () {
218 | if (!_this.isClickablePrev) {
219 | return false;
220 | }
221 |
222 | var indexOffset = _this.getIndexOffset();
223 | var slideOffset = indexOffset === 0 ? _this.options.slidesToScroll : _this.options.slidesToShow - indexOffset;
224 |
225 | _this.slideHandler(_this.currentSlide - slideOffset).catch(function () {
226 | // Catch err
227 | });
228 | };
229 |
230 | /**
231 | * Get index offset
232 | */
233 | this.getIndexOffset = function () {
234 | var scrollOffset = _this.slides.length % _this.options.slidesToScroll !== 0;
235 | var indexOffset = scrollOffset ? 0 : (_this.slides.length - _this.currentSlide) % _this.options.slidesToScroll;
236 |
237 | return indexOffset;
238 | };
239 |
240 | /**
241 | * move to page
242 | * @params int page
243 | * Page counter from 0 (start = 0)
244 | */
245 | this.movePage = function (page) {
246 | var target = _this.options.slidesToScroll * page;
247 | _this.slideHandler(target).catch(function () {
248 | // Catch err
249 | });
250 | };
251 |
252 | /**
253 | * hanlder carousel
254 | * @description move carousel to correct page
255 | *
256 | * @params int index
257 | */
258 | this.slideHandler = function (index) {
259 | // TODO prevent when slides not exists
260 | if (!_this.slides) {
261 | return $q.reject('Carousel not fully setup');
262 | }
263 |
264 | // TODO Prevent when track is moving
265 | if (_this.isTrackMoving) {
266 | return $q.reject('Track is moving');
267 | }
268 |
269 | var len = _this.slides.length;
270 | var show = _this.options.slidesToShow;
271 |
272 | if (len <= show) {
273 | _this.correctTrack();
274 | return $q.reject('Length of slides smaller than slides to show');
275 | }
276 |
277 | // We need target to destination
278 | // and a anim slide to translate track
279 | //
280 | // anim = animSlide (which we use to move)
281 | // target = targetSlide
282 | var anim = index;
283 | var target = null;
284 |
285 | if (anim < 0) {
286 | if (len % _this.options.slidesToScroll !== 0) {
287 | target = len - len % _this.options.slidesToScroll;
288 | } else {
289 | target = len + anim;
290 | }
291 | } else if (anim >= len) {
292 | if (len % _this.options.slidesToScroll !== 0) {
293 | target = 0;
294 | } else {
295 | target = anim - len;
296 | }
297 | } else {
298 | target = anim;
299 | }
300 |
301 | if (_this.onBeforeChange) {
302 | // @see https://docs.angularjs.org/guide/directive
303 | _this.onBeforeChange({ currentSlide: _this.currentSlide, target: target });
304 | }
305 |
306 | // Fade handler
307 | if (_this.options.fade) {
308 | _this.currentSlide = target;
309 |
310 | // XXX
311 | // afterChange method
312 | // fire after faded
313 | // Should be revised
314 | $timeout(function () {
315 | _this.autoplayTrack();
316 |
317 | if (_this.onAfterChange) {
318 | _this.onAfterChange({ currentSlide: _this.currentSlide });
319 | }
320 | }, _this.options.speed);
321 | return $q.when('Handler fade');
322 | }
323 |
324 | // No-fade handler
325 | var itemWidth = _this.width / _this.options.slidesToShow;
326 | var left = -1 * target * itemWidth;
327 | if (_this.options.infinite) {
328 | left = -1 * (anim + show) * itemWidth;
329 | }
330 |
331 | _this.isTrackMoving = true;
332 | return _this.moveTrack(left).then(function () {
333 | _this.isTrackMoving = false;
334 | _this.currentSlide = target;
335 | _this.autoplayTrack();
336 |
337 | if (target !== anim) {
338 | _this.correctTrack();
339 | }
340 |
341 | if (!_this.options.infinite) {
342 | if (_this.currentSlide === 0) {
343 | _this.isClickablePrev = false;
344 | _this.isClickableNext = true;
345 | } else if (_this.currentSlide === _this.slidesInTrack.length - _this.options.slidesToShow) {
346 | _this.isClickableNext = false;
347 | _this.isClickablePrev = true;
348 | } else {
349 | _this.isClickablePrev = true;
350 | _this.isClickableNext = true;
351 | }
352 | }
353 |
354 | // XXX
355 | // afterChange method
356 | // fire after 200ms wakeup and correct track
357 | // Should be revised
358 | $timeout(function () {
359 | if (_this.onAfterChange) {
360 | _this.onAfterChange({ currentSlide: _this.currentSlide });
361 | }
362 | }, 200);
363 | });
364 | };
365 |
366 | /**
367 | * moveTrack
368 | * move track to left position using css3 translate
369 | * for example left: -1000px
370 | */
371 | this.moveTrack = function (left) {
372 | var deferred = $q.defer();
373 | if (_this.options.vertical === false) {
374 | _this.trackStyle[_this.animType] = 'translate3d(' + left + 'px, 0px, 0px)';
375 | } else {
376 | _this.trackStyle[_this.animType] = 'translate3d(0px, ' + left + 'px, 0px)';
377 | }
378 |
379 | $timeout(function () {
380 | deferred.resolve('Track moved');
381 | }, _this.options.speed);
382 |
383 | return deferred.promise;
384 | };
385 |
386 | /**
387 | * correctTrack
388 | * @description correct track after move to animSlide we have to move track
389 | * to exactly its position
390 | */
391 | this.correctTrack = function () {
392 | if (_this.options.infinite) {
393 | (function () {
394 | var left = 0;
395 | if (_this.slides.length > _this.options.slidesToShow) {
396 | left = -1 * (_this.currentSlide + _this.options.slidesToShow) * _this.itemWidth;
397 | }
398 |
399 | // Move without anim
400 | _this.trackStyle[_this.transitionType] = _this.transformType + ' ' + 0 + 'ms ' + _this.options.cssEase;
401 |
402 | _this.isTrackMoving = true;
403 | $timeout(function () {
404 | _this.trackStyle[_this.animType] = 'translate3d(' + left + 'px, 0, 0px)';
405 |
406 | // Revert animation
407 | $timeout(function () {
408 | _this.refreshTrackStyle();
409 | _this.isTrackMoving = false;
410 | }, 200);
411 | });
412 | })();
413 | }
414 | };
415 |
416 | /**
417 | * Refresh track style
418 | */
419 | this.refreshTrackStyle = function () {
420 | _this.trackStyle[_this.transitionType] = _this.transformType + ' ' + _this.options.speed + 'ms ' + _this.options.cssEase;
421 | };
422 |
423 | /**
424 | * autoplay track
425 | * @description autoplay = true
426 | */
427 | this.autoplayTrack = function () {
428 | if (_this.options.autoplay) {
429 | if (_this.timeout) {
430 | $timeout.cancel(_this.timeout);
431 | }
432 |
433 | _this.timeout = $timeout(function () {
434 | _this.next();
435 |
436 | $timeout.cancel(_this.timeout);
437 | _this.timeout = null;
438 | }, _this.options.autoplaySpeed);
439 | }
440 | };
441 |
442 | this.getSlideStyle = function (index) {
443 | var style = _this.slideStyle;
444 | if (_this.options.fade) {
445 | var left = -1 * index * _this.itemWidth;
446 | var uniqueStyle = {
447 | position: 'relative',
448 | top: '0px',
449 | left: left + 'px',
450 | 'z-index': index === _this.currentSlide ? 10 : 9,
451 | opacity: index === _this.currentSlide ? 1 : 0
452 | };
453 |
454 | if (index >= _this.currentSlide - 1 && index <= _this.currentSlide + 1) {
455 | uniqueStyle.transition = 'opacity 250ms linear';
456 | }
457 |
458 | style = angular.extend(style, uniqueStyle);
459 | }
460 |
461 | return style;
462 | };
463 |
464 | /**
465 | * setupInfinite
466 | * To make carouse infinite we need close number of slidesToShow elements to
467 | * previous elements and to after elements
468 | *
469 | * length = 8, show = 4, scroll = 3, current = 0
470 | * ---------
471 | * | |
472 | * |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
473 | * | |
474 | * ---------
475 | */
476 | this.setupInfinite = function () {
477 | // Clone
478 | var len = _this.slides.length;
479 | var show = _this.options.slidesToShow;
480 |
481 | var tmpTrack = angular.copy(_this.slides);
482 |
483 | if (_this.options.infinite && _this.options.fade === false) {
484 | if (len > show) {
485 | var number = show;
486 | for (var i = 0; i < number; i++) {
487 | tmpTrack.push(angular.copy(_this.slides[i]));
488 | }
489 | for (var _i = len - 1; _i >= len - show; _i--) {
490 | tmpTrack.unshift(angular.copy(_this.slides[_i]));
491 | }
492 | }
493 | }
494 |
495 | _this.slidesInTrack = tmpTrack;
496 | };
497 |
498 | /**
499 | * get number of dosts
500 | *
501 | * @return Array
502 | */
503 | this.getDots = function () {
504 | if (!_this.slides) {
505 | return [];
506 | }
507 |
508 | var dots = Math.ceil(_this.slides.length / _this.options.slidesToScroll);
509 |
510 | var res = [];
511 | for (var i = 0; i < dots; i++) {
512 | res.push(i);
513 | }
514 | return res;
515 | };
516 |
517 | /**
518 | * set carousel property
519 | *
520 | * - animType
521 | * - transformType
522 | * - transitionType
523 | */
524 | this.setProps = function () {
525 | var bodyStyle = document.body.style;
526 |
527 | /* eslint-disable */
528 | if (bodyStyle.OTransform !== undefined) {
529 | _this.animType = 'OTransform';
530 | _this.transformType = '-o-transform';
531 | _this.transitionType = 'OTransition';
532 | }
533 | if (bodyStyle.MozTransform !== undefined) {
534 | _this.animType = 'MozTransform';
535 | _this.transformType = '-moz-transform';
536 | _this.transitionType = 'MozTransition';
537 | }
538 | if (bodyStyle.webkitTransform !== undefined) {
539 | _this.animType = 'webkitTransform';
540 | _this.transformType = '-webkit-transform';
541 | _this.transitionType = 'webkitTransition';
542 | }
543 | if (bodyStyle.msTransform !== undefined) {
544 | _this.animType = 'msTransform';
545 | _this.transformType = '-ms-transform';
546 | _this.transitionType = 'msTransition';
547 | }
548 | if (bodyStyle.transform !== undefined && _this.animType !== false) {
549 | _this.animType = 'transform';
550 | _this.transformType = 'transform';
551 | _this.transitionType = 'transition';
552 | }
553 | /* eslint-enable */
554 |
555 | _this.transformsEnabled = true;
556 | };
557 |
558 | /**
559 | * Refresh carousel
560 | */
561 | this.refreshCarousel = function () {
562 | if (_this.slides && _this.slides.length && _this.slides.length > _this.options.slidesToShow) {
563 | _this.isVisibleDots = true;
564 | _this.isVisiblePrev = true;
565 | _this.isVisibleNext = true;
566 | _this.isClickablePrev = true;
567 | _this.isClickableNext = true;
568 | } else {
569 | _this.isVisibleDots = false;
570 | _this.isVisiblePrev = _this.options.visiblePrev || false;
571 | _this.isVisibleNext = _this.options.visibleNext || false;
572 | _this.isClickablePrev = false;
573 | _this.isClickableNext = false;
574 | }
575 |
576 | // Re-init UI
577 | _this.initUI();
578 | };
579 |
580 | /**
581 | * refresh model
582 | */
583 | $scope.$watchCollection('ctrl.slides', function (slides) {
584 | if (!slides) {
585 | return;
586 | }
587 |
588 | // Init carousel
589 | if (_this.currentSlide > slides.length - 1) {
590 | _this.currentSlide = slides.length - 1;
591 | }
592 |
593 | _this.setupInfinite();
594 | _this.refreshCarousel();
595 | });
596 |
597 | /**
598 | * update when resize
599 | *
600 | * @see https://github.com/mihnsen/ui-carousel/issues/10
601 | * @author tarkant
602 | */
603 | angular.element($window).on('resize', this.refreshCarousel);
604 |
605 | /**
606 | * cleanup when done
607 | *
608 | * @see https://github.com/mihnsen/ui-carousel/issues/10
609 | * @author tarkant
610 | */
611 | $scope.$on('$destroy', function () {
612 | angular.element($window).off('resize');
613 | });
614 |
615 | // Prior to v1.5, we need to call `$onInit()` manually.
616 | // (Bindings will always be pre-assigned in these versions.)
617 | if (angular.version.major === 1 && angular.version.minor < 5) {
618 | this.$onInit();
619 | }
620 | }]);
621 | 'use strict';
622 |
623 | angular.module('ui.carousel.directives').directive('uiCarousel', ['$compile', '$templateCache', '$sce', function ($compile, $templateCache, $sce) {
624 |
625 | return { restrict: 'AE',
626 | bindToController: true,
627 | scope: {
628 | name: '=?',
629 | slides: '=',
630 | show: '=?slidesToShow',
631 | scroll: '=?slidesToScroll',
632 | classes: '@',
633 | fade: '=?',
634 | onChange: '=?',
635 | disableArrow: '=?',
636 | autoplay: '=?',
637 | autoplaySpeed: '=?',
638 | cssEase: '=?',
639 | speed: '=?',
640 | infinite: '=?',
641 | arrows: '=?',
642 | dots: '=?',
643 | initialSlide: '=?',
644 | visibleNext: '=?',
645 | visiblePrev: '=?',
646 |
647 | // Method
648 | onBeforeChange: '&',
649 | onAfterChange: '&',
650 | onInit: '&'
651 | },
652 | link: function link($scope, el) {
653 | var template = angular.element($templateCache.get('ui-carousel/carousel.template.html'));
654 |
655 | // dynamic injections to override the inner layers' components
656 | var injectComponentMap = {
657 | 'carousel-item': '.carousel-item',
658 | 'carousel-prev': '.carousel-prev',
659 | 'carousel-next': '.carousel-next'
660 | };
661 |
662 | var templateInstance = template.clone();
663 | angular.forEach(injectComponentMap, function (innerSelector, outerSelector) {
664 | var outerElement = el[0].querySelector(outerSelector);
665 | if (outerElement) {
666 | angular.element(templateInstance[0].querySelector(innerSelector)).html(outerElement.innerHTML);
667 | }
668 | });
669 |
670 | var compiledElement = $compile(templateInstance)($scope);
671 | el.addClass('ui-carousel').html('').append(compiledElement);
672 | },
673 |
674 |
675 | controller: 'CarouselController',
676 | controllerAs: 'ctrl'
677 | };
678 | }]);
679 | 'use strict';
680 |
681 | angular.module('ui.carousel.providers').provider('Carousel', function () {
682 | var _this = this;
683 |
684 | this.options = {
685 | // Init like Slick carousel
686 | // XXX Should be revised
687 | arrows: true,
688 | autoplay: false,
689 | autoplaySpeed: 3000,
690 | cssEase: 'ease',
691 | dots: false,
692 |
693 | easing: 'linear',
694 | fade: false,
695 | infinite: true,
696 | initialSlide: 0,
697 |
698 | slidesToShow: 1,
699 | slidesToScroll: 1,
700 | speed: 500,
701 |
702 | visiblePrev: false,
703 | visibleNext: false,
704 |
705 | // Not available right now
706 | draggable: true,
707 |
708 | lazyLoad: 'ondemand',
709 |
710 | swipe: true,
711 | swipeToSlide: false,
712 | touchMove: true,
713 |
714 | vertical: false,
715 | verticalSwiping: false
716 | };
717 | this.$get = [function () {
718 | return {
719 | setOptions: function setOptions(options) {
720 | _this.options = angular.extend(_this.options, options);
721 | },
722 | getOptions: function getOptions() {
723 | return _this.options;
724 | }
725 | };
726 | }];
727 | });
728 | 'use strict';
729 |
730 | (function (module) {
731 | try {
732 | module = angular.module('ui.carousel');
733 | } catch (e) {
734 | module = angular.module('ui.carousel', []);
735 | }
736 | module.run(['$templateCache', function ($templateCache) {
737 | $templateCache.put('ui-carousel/carousel.template.html', '
');
738 | }]);
739 | })();
--------------------------------------------------------------------------------
/dist/ui-carousel.min.css:
--------------------------------------------------------------------------------
1 | [class*=" ui-icon-"]:before,[class^=ui-icon-]:before,[data-icon]:before{font-family:ui-carousel!important;font-style:normal!important;font-weight:400!important;font-variant:normal!important;text-transform:none!important;speak:none;line-height:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.ui-carousel .carousel-btn,.v-middle{display:block;position:absolute;top:50%;-webkit-transform:translate(0,-50%);-ms-transform:translate(0,-50%);-o-transform:translate(0,-50%);transform:translate(0,-50%)}@font-face{font-family:ui-carousel;src:url(fonts/ui-carousel.eot);src:url(fonts/ui-carousel.eot?#iefix) format("embedded-opentype"),url(fonts/ui-carousel.woff) format("woff"),url(fonts/ui-carousel.ttf) format("truetype"),url(fonts/ui-carousel.svg#ui-carousel) format("svg");font-weight:400;font-style:normal}[data-icon]:before{content:attr(data-icon)}.ui-icon-prev:before{content:"\61"}.ui-icon-next:before{content:"\62"}.carousel-dots li button:before,.ui-icon-dot:before{content:"\63"}.ui-carousel{display:block;margin-bottom:30px}.ui-carousel .carousel-wrapper{position:relative}.ui-carousel .track-wrapper{position:relative;display:block;overflow:hidden;margin:0;padding:0}.ui-carousel .track{position:relative;display:block;float:left}.ui-carousel .slide{float:left;height:100%;min-height:1px}.ui-carousel .carousel-btn{position:absolute;z-index:10;background-color:transparent;outline:0;border:none;font-size:20px;opacity:.75}.ui-carousel .carousel-btn:hover{opacity:1}.ui-carousel .carousel-prev .carousel-btn{left:-25px}.ui-carousel .carousel-next .carousel-btn{right:-25px}.ui-carousel .carousel-disable{opacity:.5}.ui-carousel .carousel-disable .carousel-btn:hover{opacity:.75}.carousel-dots{position:absolute;bottom:-30px;display:block;width:100%;padding:0;margin:0;list-style:none;text-align:center}.carousel-dots li{position:relative;display:inline-block;width:15px;height:15px;margin:0 5px;padding:0;cursor:pointer}.carousel-dots li button{font-size:0;line-height:0;display:block;width:15px;height:15px;padding:5px;cursor:pointer;color:transparent;border:0;outline:0;background:0 0}.carousel-dots li button:before{font-family:ui-carousel;font-size:9px;line-height:15px;position:absolute;top:0;left:0;width:15px;height:15px;text-align:center;opacity:.25;color:#000;-webkit-font-smoothing:antialiased}.carousel-dots li.carousel-active button:before{opacity:.75}
2 | /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInVpLWNhcm91c2VsLmNzcyIsIl9mb250cy5zY3NzIiwiY2Fyb3VzZWwuc2NzcyIsIm1peGluLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBNkJBLDRCQURBLHlCQVpBLG1CQ2FFLFlBQWEsc0JBQ2IsV0FBWSxpQkFDWixZQUFhLGNBQ2IsYUFBYyxpQkFDZCxlQUFnQixlQUNoQixNQUFPLEtBQ1AsWUFBYSxFQUViLHdCQUF5QixVQ29FbkIsdUJBQXdCLFlDekVoQywyQkFBQSxVQUNFLFFBQVMsTUFDVCxTQUFVLFNBQ1YsSUFBSyxJQWZMLGtCQUFtQixrQkFDZixjQUFlLGtCQUNkLGFBQWMsa0JBQ1gsVUFBVyxrQkZyQnJCLFdBQ0UsWUFBYSxZQUNiLElBQUksMkJBQ0osSUFBSSxrQ0FBQSw0QkFBb0MsNEJBQ3RDLGVBQThCLDJCQUM5QixtQkFBNkIsdUNBQzdCLGNBQ0YsWUFBYSxJQUNiLFdBQVksT0RNZCxtQkNBRSxRQUFTLGdCQXdCWCxxQkFDRSxRQUFTLE1BRVgscUJBQ0UsUUFBUyxNQ2dCWCxnQ0RkQSxvQkN1RFEsUUFBUyxNQXJHakIsYUFDRSxRQUFTLE1BQ1QsY0FBZSxLQUZqQiwrQkFLSSxTQUFVLFNBTGQsNEJBUUksU0FBVSxTQUNWLFFBQVMsTUFDVCxTQUFVLE9BQ1YsT0FBUSxFQUNSLFFBQVMsRUFaYixvQkFlSSxTQUFVLFNBQ1YsUUFBUyxNQUNULE1BQU8sS0FqQlgsb0JBb0JJLE1BQU8sS0FDUCxPQUFRLEtBQ1IsV0FBWSxJQXRCaEIsMkJBeUJJLFNBQVUsU0FDVixRQUFTLEdBRVQsaUJBQWtCLFlBQ2xCLFFBQVMsRUFDVCxZQUNBLFVBQVcsS0FDWCxRQUFTLElBaENiLGlDQW1DTSxRQUFTLEVBbkNmLDBDQXlDTSxLQUFNLE1BekNaLDBDQThDTSxNQUFPLE1BOUNiLCtCQWtESSxRQUFTLEdBbERiLG1EQXNEUSxRQUFTLElBTWpCLGVBQ0UsU0FBVSxTQUNWLE9BQVEsTUFDUixRQUFTLE1BQ1QsTUFBTyxLQUNQLFFBQVMsRUFDVCxPQUFRLEVBQ1IsV0FBWSxLQUNaLFdBQVksT0FSZCxrQkFXSSxTQUFVLFNBQ1YsUUFBUyxhQUNULE1BQU8sS0FDUCxPQUFRLEtBQ1IsT0FBUSxFQUFBLElBQ1IsUUFBUyxFQUNULE9BQVEsUUFqQloseUJBb0JNLFVBQVcsRUFDWCxZQUFhLEVBQ2IsUUFBUyxNQUNULE1BQU8sS0FDUCxPQUFRLEtBQ1IsUUFBUyxJQUNULE9BQVEsUUFDUixNQUFPLFlBQ1AsT0FBUSxFQUNSLFFBQVMsRUFDVCxlQTlCTixnQ0FpQ1EsWUFBYSxZQUNiLFVBQVcsSUFDWCxZQUFhLEtBQ2IsU0FBVSxTQUNWLElBQUssRUFDTCxLQUFNLEVBQ04sTUFBTyxLQUNQLE9BQVEsS0FFUixXQUFZLE9BQ1osUUFBUyxJQUNULE1BQU8sS0FDUCx1QkFBd0IsWUE3Q2hDLGdEQW9EVSxRQUFTIiwiZmlsZSI6InVpLWNhcm91c2VsLm1pbi5jc3MiLCJzb3VyY2VzQ29udGVudCI6WyIudi1taWRkbGUsIC51aS1jYXJvdXNlbCAuY2Fyb3VzZWwtYnRuIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiA1MCU7XG4gIC13ZWJraXQtdHJhbnNmb3JtOiB0cmFuc2xhdGUoMCwgLTUwJSk7XG4gIC1tcy10cmFuc2Zvcm06IHRyYW5zbGF0ZSgwLCAtNTAlKTtcbiAgLW8tdHJhbnNmb3JtOiB0cmFuc2xhdGUoMCwgLTUwJSk7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlKDAsIC01MCUpOyB9XG5cbkBmb250LWZhY2Uge1xuICBmb250LWZhbWlseTogXCJ1aS1jYXJvdXNlbFwiO1xuICBzcmM6IHVybChcImZvbnRzL3VpLWNhcm91c2VsLmVvdFwiKTtcbiAgc3JjOiB1cmwoXCJmb250cy91aS1jYXJvdXNlbC5lb3Q/I2llZml4XCIpIGZvcm1hdChcImVtYmVkZGVkLW9wZW50eXBlXCIpLCB1cmwoXCJmb250cy91aS1jYXJvdXNlbC53b2ZmXCIpIGZvcm1hdChcIndvZmZcIiksIHVybChcImZvbnRzL3VpLWNhcm91c2VsLnR0ZlwiKSBmb3JtYXQoXCJ0cnVldHlwZVwiKSwgdXJsKFwiZm9udHMvdWktY2Fyb3VzZWwuc3ZnI3VpLWNhcm91c2VsXCIpIGZvcm1hdChcInN2Z1wiKTtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbDtcbiAgZm9udC1zdHlsZTogbm9ybWFsOyB9XG5cbltkYXRhLWljb25dOmJlZm9yZSB7XG4gIGZvbnQtZmFtaWx5OiBcInVpLWNhcm91c2VsXCIgIWltcG9ydGFudDtcbiAgY29udGVudDogYXR0cihkYXRhLWljb24pO1xuICBmb250LXN0eWxlOiBub3JtYWwgIWltcG9ydGFudDtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbCAhaW1wb3J0YW50O1xuICBmb250LXZhcmlhbnQ6IG5vcm1hbCAhaW1wb3J0YW50O1xuICB0ZXh0LXRyYW5zZm9ybTogbm9uZSAhaW1wb3J0YW50O1xuICBzcGVhazogbm9uZTtcbiAgbGluZS1oZWlnaHQ6IDE7XG4gIC13ZWJraXQtZm9udC1zbW9vdGhpbmc6IGFudGlhbGlhc2VkO1xuICAtbW96LW9zeC1mb250LXNtb290aGluZzogZ3JheXNjYWxlOyB9XG5cbltjbGFzc149XCJ1aS1pY29uLVwiXTpiZWZvcmUsXG5bY2xhc3MqPVwiIHVpLWljb24tXCJdOmJlZm9yZSB7XG4gIGZvbnQtZmFtaWx5OiBcInVpLWNhcm91c2VsXCIgIWltcG9ydGFudDtcbiAgZm9udC1zdHlsZTogbm9ybWFsICFpbXBvcnRhbnQ7XG4gIGZvbnQtd2VpZ2h0OiBub3JtYWwgIWltcG9ydGFudDtcbiAgZm9udC12YXJpYW50OiBub3JtYWwgIWltcG9ydGFudDtcbiAgdGV4dC10cmFuc2Zvcm06IG5vbmUgIWltcG9ydGFudDtcbiAgc3BlYWs6IG5vbmU7XG4gIGxpbmUtaGVpZ2h0OiAxO1xuICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTsgfVxuXG4udWktaWNvbi1wcmV2OmJlZm9yZSB7XG4gIGNvbnRlbnQ6IFwiXFw2MVwiOyB9XG5cbi51aS1pY29uLW5leHQ6YmVmb3JlIHtcbiAgY29udGVudDogXCJcXDYyXCI7IH1cblxuLnVpLWljb24tZG90OmJlZm9yZSB7XG4gIGNvbnRlbnQ6IFwiXFw2M1wiOyB9XG5cbi51aS1jYXJvdXNlbCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBtYXJnaW4tYm90dG9tOiAzMHB4OyB9XG4gIC51aS1jYXJvdXNlbCAuY2Fyb3VzZWwtd3JhcHBlciB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlOyB9XG4gIC51aS1jYXJvdXNlbCAudHJhY2std3JhcHBlciB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgbWFyZ2luOiAwO1xuICAgIHBhZGRpbmc6IDA7IH1cbiAgLnVpLWNhcm91c2VsIC50cmFjayB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZsb2F0OiBsZWZ0OyB9XG4gIC51aS1jYXJvdXNlbCAuc2xpZGUge1xuICAgIGZsb2F0OiBsZWZ0O1xuICAgIGhlaWdodDogMTAwJTtcbiAgICBtaW4taGVpZ2h0OiAxcHg7IH1cbiAgLnVpLWNhcm91c2VsIC5jYXJvdXNlbC1idG4ge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB6LWluZGV4OiAxMDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBvdXRsaW5lOiBub25lO1xuICAgIGJvcmRlcjogbm9uZTtcbiAgICBmb250LXNpemU6IDIwcHg7XG4gICAgb3BhY2l0eTogLjc1OyB9XG4gICAgLnVpLWNhcm91c2VsIC5jYXJvdXNlbC1idG46aG92ZXIge1xuICAgICAgb3BhY2l0eTogMTsgfVxuICAudWktY2Fyb3VzZWwgLmNhcm91c2VsLXByZXYgLmNhcm91c2VsLWJ0biB7XG4gICAgbGVmdDogLTI1cHg7IH1cbiAgLnVpLWNhcm91c2VsIC5jYXJvdXNlbC1uZXh0IC5jYXJvdXNlbC1idG4ge1xuICAgIHJpZ2h0OiAtMjVweDsgfVxuICAudWktY2Fyb3VzZWwgLmNhcm91c2VsLWRpc2FibGUge1xuICAgIG9wYWNpdHk6IDAuNTsgfVxuICAgIC51aS1jYXJvdXNlbCAuY2Fyb3VzZWwtZGlzYWJsZSAuY2Fyb3VzZWwtYnRuOmhvdmVyIHtcbiAgICAgIG9wYWNpdHk6IC43NTsgfVxuXG4uY2Fyb3VzZWwtZG90cyB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgYm90dG9tOiAtMzBweDtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHdpZHRoOiAxMDAlO1xuICBwYWRkaW5nOiAwO1xuICBtYXJnaW46IDA7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG4gIHRleHQtYWxpZ246IGNlbnRlcjsgfVxuICAuY2Fyb3VzZWwtZG90cyBsaSB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICB3aWR0aDogMTVweDtcbiAgICBoZWlnaHQ6IDE1cHg7XG4gICAgbWFyZ2luOiAwIDVweDtcbiAgICBwYWRkaW5nOiAwO1xuICAgIGN1cnNvcjogcG9pbnRlcjsgfVxuICAgIC5jYXJvdXNlbC1kb3RzIGxpIGJ1dHRvbiB7XG4gICAgICBmb250LXNpemU6IDA7XG4gICAgICBsaW5lLWhlaWdodDogMDtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgd2lkdGg6IDE1cHg7XG4gICAgICBoZWlnaHQ6IDE1cHg7XG4gICAgICBwYWRkaW5nOiA1cHg7XG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICBjb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgICBib3JkZXI6IDA7XG4gICAgICBvdXRsaW5lOiBub25lO1xuICAgICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7IH1cbiAgICAgIC5jYXJvdXNlbC1kb3RzIGxpIGJ1dHRvbjpiZWZvcmUge1xuICAgICAgICBmb250LWZhbWlseTogdWktY2Fyb3VzZWw7XG4gICAgICAgIGZvbnQtc2l6ZTogOXB4O1xuICAgICAgICBsaW5lLWhlaWdodDogMTVweDtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDBweDtcbiAgICAgICAgbGVmdDogMHB4O1xuICAgICAgICB3aWR0aDogMTVweDtcbiAgICAgICAgaGVpZ2h0OiAxNXB4O1xuICAgICAgICBjb250ZW50OiBcIlxcNjNcIjtcbiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICBvcGFjaXR5OiAwLjI1O1xuICAgICAgICBjb2xvcjogYmxhY2s7XG4gICAgICAgIC13ZWJraXQtZm9udC1zbW9vdGhpbmc6IGFudGlhbGlhc2VkOyB9XG4gICAgLmNhcm91c2VsLWRvdHMgbGkuY2Fyb3VzZWwtYWN0aXZlIGJ1dHRvbjpiZWZvcmUge1xuICAgICAgb3BhY2l0eTogLjc1OyB9XG4iLCJAY2hhcnNldCBcIlVURi04XCI7XG5cbkBmb250LWZhY2Uge1xuICBmb250LWZhbWlseTogXCJ1aS1jYXJvdXNlbFwiO1xuICBzcmM6dXJsKFwiZm9udHMvdWktY2Fyb3VzZWwuZW90XCIpO1xuICBzcmM6dXJsKFwiZm9udHMvdWktY2Fyb3VzZWwuZW90PyNpZWZpeFwiKSBmb3JtYXQoXCJlbWJlZGRlZC1vcGVudHlwZVwiKSxcbiAgICB1cmwoXCJmb250cy91aS1jYXJvdXNlbC53b2ZmXCIpIGZvcm1hdChcIndvZmZcIiksXG4gICAgdXJsKFwiZm9udHMvdWktY2Fyb3VzZWwudHRmXCIpIGZvcm1hdChcInRydWV0eXBlXCIpLFxuICAgIHVybChcImZvbnRzL3VpLWNhcm91c2VsLnN2ZyN1aS1jYXJvdXNlbFwiKSBmb3JtYXQoXCJzdmdcIik7XG4gIGZvbnQtd2VpZ2h0OiBub3JtYWw7XG4gIGZvbnQtc3R5bGU6IG5vcm1hbDtcblxufVxuXG5bZGF0YS1pY29uXTpiZWZvcmUge1xuICBmb250LWZhbWlseTogXCJ1aS1jYXJvdXNlbFwiICFpbXBvcnRhbnQ7XG4gIGNvbnRlbnQ6IGF0dHIoZGF0YS1pY29uKTtcbiAgZm9udC1zdHlsZTogbm9ybWFsICFpbXBvcnRhbnQ7XG4gIGZvbnQtd2VpZ2h0OiBub3JtYWwgIWltcG9ydGFudDtcbiAgZm9udC12YXJpYW50OiBub3JtYWwgIWltcG9ydGFudDtcbiAgdGV4dC10cmFuc2Zvcm06IG5vbmUgIWltcG9ydGFudDtcbiAgc3BlYWs6IG5vbmU7XG4gIGxpbmUtaGVpZ2h0OiAxO1xuICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbiAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbn1cblxuW2NsYXNzXj1cInVpLWljb24tXCJdOmJlZm9yZSxcbltjbGFzcyo9XCIgdWktaWNvbi1cIl06YmVmb3JlIHtcbiAgZm9udC1mYW1pbHk6IFwidWktY2Fyb3VzZWxcIiAhaW1wb3J0YW50O1xuICBmb250LXN0eWxlOiBub3JtYWwgIWltcG9ydGFudDtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbCAhaW1wb3J0YW50O1xuICBmb250LXZhcmlhbnQ6IG5vcm1hbCAhaW1wb3J0YW50O1xuICB0ZXh0LXRyYW5zZm9ybTogbm9uZSAhaW1wb3J0YW50O1xuICBzcGVhazogbm9uZTtcbiAgbGluZS1oZWlnaHQ6IDE7XG4gIC13ZWJraXQtZm9udC1zbW9vdGhpbmc6IGFudGlhbGlhc2VkO1xuICAtbW96LW9zeC1mb250LXNtb290aGluZzogZ3JheXNjYWxlO1xufVxuXG4udWktaWNvbi1wcmV2OmJlZm9yZSB7XG4gIGNvbnRlbnQ6IFwiXFw2MVwiO1xufVxuLnVpLWljb24tbmV4dDpiZWZvcmUge1xuICBjb250ZW50OiBcIlxcNjJcIjtcbn1cbi51aS1pY29uLWRvdDpiZWZvcmUge1xuICBjb250ZW50OiBcIlxcNjNcIjtcbn1cbiIsIi51aS1jYXJvdXNlbCB7XG4gIGRpc3BsYXk6IGJsb2NrO1xuICBtYXJnaW4tYm90dG9tOiAzMHB4O1xuXG4gIC5jYXJvdXNlbC13cmFwcGVyIHtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIH1cbiAgLnRyYWNrLXdyYXBwZXIge1xuICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIG1hcmdpbjogMDtcbiAgICBwYWRkaW5nOiAwO1xuICB9XG4gIC50cmFjayB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZsb2F0OiBsZWZ0O1xuICB9XG4gIC5zbGlkZSB7XG4gICAgZmxvYXQ6IGxlZnQ7XG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIG1pbi1oZWlnaHQ6IDFweDtcbiAgfVxuICAuY2Fyb3VzZWwtYnRuIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgei1pbmRleDogMTA7XG4gICAgQGV4dGVuZCAudi1taWRkbGU7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICBib3JkZXI6IG5vbmU7XG4gICAgZm9udC1zaXplOiAyMHB4O1xuICAgIG9wYWNpdHk6IC43NTtcblxuICAgICY6aG92ZXIge1xuICAgICAgb3BhY2l0eTogMTtcbiAgICB9XG4gIH1cblxuICAuY2Fyb3VzZWwtcHJldiB7XG4gICAgLmNhcm91c2VsLWJ0biB7XG4gICAgICBsZWZ0OiAtMjVweDtcbiAgICB9XG4gIH1cbiAgLmNhcm91c2VsLW5leHQge1xuICAgIC5jYXJvdXNlbC1idG4ge1xuICAgICAgcmlnaHQ6IC0yNXB4O1xuICAgIH1cbiAgfVxuICAuY2Fyb3VzZWwtZGlzYWJsZSB7XG4gICAgb3BhY2l0eTogMC41O1xuXG4gICAgLmNhcm91c2VsLWJ0biB7XG4gICAgICAmOmhvdmVyIHtcbiAgICAgICAgb3BhY2l0eTogLjc1O1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4uY2Fyb3VzZWwtZG90cyB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgYm90dG9tOiAtMzBweDtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHdpZHRoOiAxMDAlO1xuICBwYWRkaW5nOiAwO1xuICBtYXJnaW46IDA7XG4gIGxpc3Qtc3R5bGU6IG5vbmU7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcblxuICBsaSB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICB3aWR0aDogMTVweDtcbiAgICBoZWlnaHQ6IDE1cHg7XG4gICAgbWFyZ2luOiAwIDVweDtcbiAgICBwYWRkaW5nOiAwO1xuICAgIGN1cnNvcjogcG9pbnRlcjtcblxuICAgIGJ1dHRvbiB7XG4gICAgICBmb250LXNpemU6IDA7XG4gICAgICBsaW5lLWhlaWdodDogMDtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgd2lkdGg6IDE1cHg7XG4gICAgICBoZWlnaHQ6IDE1cHg7XG4gICAgICBwYWRkaW5nOiA1cHg7XG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICBjb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgICBib3JkZXI6IDA7XG4gICAgICBvdXRsaW5lOiBub25lO1xuICAgICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG5cbiAgICAgICY6YmVmb3JlIHtcbiAgICAgICAgZm9udC1mYW1pbHk6IHVpLWNhcm91c2VsO1xuICAgICAgICBmb250LXNpemU6IDlweDtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDE1cHg7XG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgdG9wOiAwcHg7XG4gICAgICAgIGxlZnQ6IDBweDtcbiAgICAgICAgd2lkdGg6IDE1cHg7XG4gICAgICAgIGhlaWdodDogMTVweDtcbiAgICAgICAgY29udGVudDogXCJcXDYzXCI7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgICAgb3BhY2l0eTogMC4yNTtcbiAgICAgICAgY29sb3I6IGJsYWNrO1xuICAgICAgICAtd2Via2l0LWZvbnQtc21vb3RoaW5nOiBhbnRpYWxpYXNlZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAmLmNhcm91c2VsLWFjdGl2ZSB7XG4gICAgICBidXR0b24ge1xuICAgICAgICAmOmJlZm9yZSB7XG4gICAgICAgICAgb3BhY2l0eTogLjc1O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iLCJAbWl4aW4gdHJhbnNpdGlvbi10cmFuc2Zvcm0oJGR1cmF0aW9uOiAyMDBtcywgJGVhc2luZzogbGluZWFyKSB7XG4gIC13ZWJraXQtdHJhbnNpdGlvbjogLXdlYmtpdC10cmFuc2Zvcm0gJGR1cmF0aW9uICRlYXNpbmc7XG4gIC1tb3otdHJhbnNpdGlvbjogLW1vei10cmFuc2Zvcm0gJGR1cmF0aW9uICRlYXNpbmc7XG4gIHRyYW5zaXRpb246IHRyYW5zZm9ybSAkZHVyYXRpb24gJGVhc2luZztcbn1cbkBtaXhpbiB0cmFuc2Zvcm0oJHAuLi4pIHtcbiAgLXdlYmtpdC10cmFuc2Zvcm06ICRwO1xuICAtbW96LXRyYW5zZm9ybTogJHA7XG4gIHRyYW5zZm9ybTogJHA7XG59XG5cbkBtaXhpbiB0cmFuc2l0aW9uLW11bHRpKCR2YWx1ZS4uLikge1xuICAtd2Via2l0LXRyYW5zaXRpb246ICR2YWx1ZTtcbiAgLW1vei10cmFuc2l0aW9uOiAkdmFsdWU7XG4gIC1tcy10cmFuc2l0aW9uOiAkdmFsdWU7XG4gIC1vLXRyYW5zaXRpb246ICR2YWx1ZTtcbiAgdHJhbnNpdGlvbjogJHZhbHVlO1xufVxuXG5AbWl4aW4gdHJhbnNsYXRlKCR4LCAkeSkge1xuICAtd2Via2l0LXRyYW5zZm9ybTogdHJhbnNsYXRlKCR4LCAkeSk7XG4gICAgICAtbXMtdHJhbnNmb3JtOiB0cmFuc2xhdGUoJHgsICR5KTsgLy8gSUU5IG9ubHlcbiAgICAgICAtby10cmFuc2Zvcm06IHRyYW5zbGF0ZSgkeCwgJHkpO1xuICAgICAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKCR4LCAkeSk7XG59XG5AbWl4aW4gdHJhbnNpdGlvbigkdHJhbnNpdGlvbi4uLikge1xuICAtd2Via2l0LXRyYW5zaXRpb246ICR0cmFuc2l0aW9uO1xuICAgICAgIC1vLXRyYW5zaXRpb246ICR0cmFuc2l0aW9uO1xuICAgICAgICAgIHRyYW5zaXRpb246ICR0cmFuc2l0aW9uO1xufVxuXG4vLyBQb3NpdGlvblxuLnYtbWlkZGxlIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiA1MCU7XG4gIEBpbmNsdWRlIHRyYW5zbGF0ZSgwLCAtNTAlKTtcbn1cbiJdfQ== */
3 |
--------------------------------------------------------------------------------
/dist/ui-carousel.min.js:
--------------------------------------------------------------------------------
1 | "use strict";!function(e){e.module("ui.carousel.config",[]).value("ui.carousel.config",{debug:!0}),e.module("ui.carousel.providers",[]),e.module("ui.carousel.controllers",[]),e.module("ui.carousel.directives",[]),e.module("ui.carousel",["ui.carousel.config","ui.carousel.directives","ui.carousel.controllers","ui.carousel.providers"])}(angular),angular.module("ui.carousel.controllers").controller("CarouselController",["$scope","$element","$timeout","$q","Carousel","$window",function(e,i,t,s,o,n){var r=this;this.$onInit=function(){r.initOptions(),r.initRanges(),r.setProps(),r.setupInfinite()},this.initOptions=function(){r.options=angular.extend({},o.getOptions()),void 0!==r.initialSlide&&(r.options.initialSlide=r.initialSlide),void 0!==r.fade&&(r.options.fade=r.fade),void 0!==r.autoplay&&(r.options.autoplay=r.autoplay),void 0!==r.autoplaySpeed&&(r.options.autoplaySpeed=r.autoplaySpeed),void 0!==r.cssEase&&(r.options.cssEase=r.cssEase),void 0!==r.speed&&(r.options.speed=r.speed),void 0!==r.infinite&&(r.options.infinite=r.infinite),void 0!==r.arrows&&(r.options.arrows=r.arrows),void 0!==r.dots&&(r.options.dots=r.dots),void 0!==r.visiblePrev&&(r.options.visiblePrev=r.visiblePrev),void 0!==r.visibleNext&&(r.options.visibleNext=r.visibleNext),r.options.fade?(r.options.slidesToShow=1,r.options.slidesToScroll=1):(r.show&&(r.options.slidesToShow=r.show),r.scroll&&(r.options.slidesToScroll=r.scroll))},this.initRanges=function(){r.slides||(r.slides=[]),r.isCarouselReady=!1,r.isTrackMoving=!1,r.track=i.find(".track"),r.width=1,r.currentSlide=r.options.initialSlide,r.trackStyle={},r.slideStyle={},r.isVisibleDots=!1,r.isVisiblePrev=r.options.visiblePrev,r.isVisibleNext=r.options.visibleNext,r.isClickablePrev=!1,r.isClickableNext=!1,r.animType=null,r.transformType=null,r.transitionType=null},this.initUI=function(){r.width=i[0].clientWidth,r.initTrack(),t(function(){r.updateItemStyle()},200)},this.updateItemStyle=function(){r.itemWidth=r.width/r.options.slidesToShow,r.slideStyle={width:r.itemWidth+"px"}},this.initTrack=function(){var e=r.width/r.options.slidesToShow,i=e*r.slidesInTrack.length;r.trackStyle.width=i+"px",r.slideHandler(r.currentSlide).finally(function(){r.isCarouselReady=!0,r.options.fade||r.refreshTrackStyle(),r.onInit&&r.onInit()}).catch(function(){})},this.next=function(){if(!r.isClickableNext)return!1;var e=r.getIndexOffset(),i=0===e?r.options.slidesToScroll:e;r.slideHandler(r.currentSlide+i).catch(function(){})},this.prev=function(){if(!r.isClickablePrev)return!1;var e=r.getIndexOffset(),i=0===e?r.options.slidesToScroll:r.options.slidesToShow-e;r.slideHandler(r.currentSlide-i).catch(function(){})},this.getIndexOffset=function(){var e=r.slides.length%r.options.slidesToScroll!==0,i=e?0:(r.slides.length-r.currentSlide)%r.options.slidesToScroll;return i},this.movePage=function(e){var i=r.options.slidesToScroll*e;r.slideHandler(i).catch(function(){})},this.slideHandler=function(e){if(!r.slides)return s.reject("Carousel not fully setup");if(r.isTrackMoving)return s.reject("Track is moving");var i=r.slides.length,o=r.options.slidesToShow;if(o>=i)return r.correctTrack(),s.reject("Length of slides smaller than slides to show");var n=e,l=null;if(l=0>n?i%r.options.slidesToScroll!==0?i-i%r.options.slidesToScroll:i+n:n>=i?i%r.options.slidesToScroll!==0?0:n-i:n,r.onBeforeChange&&r.onBeforeChange({currentSlide:r.currentSlide,target:l}),r.options.fade)return r.currentSlide=l,t(function(){r.autoplayTrack(),r.onAfterChange&&r.onAfterChange({currentSlide:r.currentSlide})},r.options.speed),s.when("Handler fade");var a=r.width/r.options.slidesToShow,c=-1*l*a;return r.options.infinite&&(c=-1*(n+o)*a),r.isTrackMoving=!0,r.moveTrack(c).then(function(){r.isTrackMoving=!1,r.currentSlide=l,r.autoplayTrack(),l!==n&&r.correctTrack(),r.options.infinite||(0===r.currentSlide?(r.isClickablePrev=!1,r.isClickableNext=!0):r.currentSlide===r.slidesInTrack.length-r.options.slidesToShow?(r.isClickableNext=!1,r.isClickablePrev=!0):(r.isClickablePrev=!0,r.isClickableNext=!0)),t(function(){r.onAfterChange&&r.onAfterChange({currentSlide:r.currentSlide})},200)})},this.moveTrack=function(e){var i=s.defer();return r.trackStyle[r.animType]=r.options.vertical===!1?"translate3d("+e+"px, 0px, 0px)":"translate3d(0px, "+e+"px, 0px)",t(function(){i.resolve("Track moved")},r.options.speed),i.promise},this.correctTrack=function(){r.options.infinite&&!function(){var e=0;r.slides.length>r.options.slidesToShow&&(e=-1*(r.currentSlide+r.options.slidesToShow)*r.itemWidth),r.trackStyle[r.transitionType]=r.transformType+" 0ms "+r.options.cssEase,r.isTrackMoving=!0,t(function(){r.trackStyle[r.animType]="translate3d("+e+"px, 0, 0px)",t(function(){r.refreshTrackStyle(),r.isTrackMoving=!1},200)})}()},this.refreshTrackStyle=function(){r.trackStyle[r.transitionType]=r.transformType+" "+r.options.speed+"ms "+r.options.cssEase},this.autoplayTrack=function(){r.options.autoplay&&(r.timeout&&t.cancel(r.timeout),r.timeout=t(function(){r.next(),t.cancel(r.timeout),r.timeout=null},r.options.autoplaySpeed))},this.getSlideStyle=function(e){var i=r.slideStyle;if(r.options.fade){var t=-1*e*r.itemWidth,s={position:"relative",top:"0px",left:t+"px","z-index":e===r.currentSlide?10:9,opacity:e===r.currentSlide?1:0};e>=r.currentSlide-1&&e<=r.currentSlide+1&&(s.transition="opacity 250ms linear"),i=angular.extend(i,s)}return i},this.setupInfinite=function(){var e=r.slides.length,i=r.options.slidesToShow,t=angular.copy(r.slides);if(r.options.infinite&&r.options.fade===!1&&e>i){for(var s=i,o=0;s>o;o++)t.push(angular.copy(r.slides[o]));for(var n=e-1;n>=e-i;n--)t.unshift(angular.copy(r.slides[n]))}r.slidesInTrack=t},this.getDots=function(){if(!r.slides)return[];for(var e=Math.ceil(r.slides.length/r.options.slidesToScroll),i=[],t=0;e>t;t++)i.push(t);return i},this.setProps=function(){var e=document.body.style;void 0!==e.OTransform&&(r.animType="OTransform",r.transformType="-o-transform",r.transitionType="OTransition"),void 0!==e.MozTransform&&(r.animType="MozTransform",r.transformType="-moz-transform",r.transitionType="MozTransition"),void 0!==e.webkitTransform&&(r.animType="webkitTransform",r.transformType="-webkit-transform",r.transitionType="webkitTransition"),void 0!==e.msTransform&&(r.animType="msTransform",r.transformType="-ms-transform",r.transitionType="msTransition"),void 0!==e.transform&&r.animType!==!1&&(r.animType="transform",r.transformType="transform",r.transitionType="transition"),r.transformsEnabled=!0},this.refreshCarousel=function(){r.slides&&r.slides.length&&r.slides.length>r.options.slidesToShow?(r.isVisibleDots=!0,r.isVisiblePrev=!0,r.isVisibleNext=!0,r.isClickablePrev=!0,r.isClickableNext=!0):(r.isVisibleDots=!1,r.isVisiblePrev=r.options.visiblePrev||!1,r.isVisibleNext=r.options.visibleNext||!1,r.isClickablePrev=!1,r.isClickableNext=!1),r.initUI()},e.$watchCollection("ctrl.slides",function(e){e&&(r.currentSlide>e.length-1&&(r.currentSlide=e.length-1),r.setupInfinite(),r.refreshCarousel())}),angular.element(n).on("resize",this.refreshCarousel),e.$on("$destroy",function(){angular.element(n).off("resize")}),1===angular.version.major&&angular.version.minor<5&&this.$onInit()}]),angular.module("ui.carousel.directives").directive("uiCarousel",["$compile","$templateCache","$sce",function(e,i){return{restrict:"AE",bindToController:!0,scope:{name:"=?",slides:"=",show:"=?slidesToShow",scroll:"=?slidesToScroll",classes:"@",fade:"=?",onChange:"=?",disableArrow:"=?",autoplay:"=?",autoplaySpeed:"=?",cssEase:"=?",speed:"=?",infinite:"=?",arrows:"=?",dots:"=?",initialSlide:"=?",visibleNext:"=?",visiblePrev:"=?",onBeforeChange:"&",onAfterChange:"&",onInit:"&"},link:function(t,s){var o=angular.element(i.get("ui-carousel/carousel.template.html")),n={"carousel-item":".carousel-item","carousel-prev":".carousel-prev","carousel-next":".carousel-next"},r=o.clone();angular.forEach(n,function(e,i){var t=s[0].querySelector(i);t&&angular.element(r[0].querySelector(e)).html(t.innerHTML)});var l=e(r)(t);s.addClass("ui-carousel").html("").append(l)},controller:"CarouselController",controllerAs:"ctrl"}}]),angular.module("ui.carousel.providers").provider("Carousel",function(){var e=this;this.options={arrows:!0,autoplay:!1,autoplaySpeed:3e3,cssEase:"ease",dots:!1,easing:"linear",fade:!1,infinite:!0,initialSlide:0,slidesToShow:1,slidesToScroll:1,speed:500,visiblePrev:!1,visibleNext:!1,draggable:!0,lazyLoad:"ondemand",swipe:!0,swipeToSlide:!1,touchMove:!0,vertical:!1,verticalSwiping:!1},this.$get=[function(){return{setOptions:function(i){e.options=angular.extend(e.options,i)},getOptions:function(){return e.options}}}]}),function(e){try{e=angular.module("ui.carousel")}catch(i){e=angular.module("ui.carousel",[])}e.run(["$templateCache",function(e){e.put("ui-carousel/carousel.template.html",'')}])}();
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp')
2 | , karma = require('karma').server
3 | , concat = require('gulp-concat')
4 | , rename = require('gulp-rename')
5 | , path = require('path')
6 | , plumber = require('gulp-plumber')
7 | , runSequence = require('run-sequence')
8 | , jshint = require('gulp-jshint')
9 | , babel = require('gulp-babel')
10 | , sass = require('gulp-sass')
11 | , pug = require('gulp-pug')
12 | , ngHtml2Js = require('gulp-ng-html2js')
13 | , sourcemaps = require('gulp-sourcemaps')
14 | , usemin = require('gulp-usemin')
15 | , uglify = require('gulp-uglify')
16 | , minifyCss = require('gulp-minify-css')
17 | , minifyHtml = require('gulp-minify-html');
18 |
19 |
20 | /**
21 | * File patterns
22 | **/
23 |
24 | // Root directory
25 | var rootDirectory = path.resolve('./');
26 |
27 | // Source directory for build process
28 | var sourceDirectory = path.join(rootDirectory, './src');
29 |
30 | // tests
31 | var testDirectory = path.join(rootDirectory, './test/unit');
32 |
33 | var sourceFiles = [
34 |
35 | // Make sure module files are handled first
36 | path.join(sourceDirectory, '/**/*.module.js'),
37 |
38 | // Then add all JavaScript files
39 | path.join(sourceDirectory, 'ui-carousel/**/*.js')
40 | ];
41 |
42 | var cssFiles = path.join(sourceDirectory, '/ui-carousel/scss/ui-carousel.scss');
43 | var pugFiles = path.join(sourceDirectory, '/ui-carousel/templates/**/*.pug');
44 | var demoFiles = path.join(sourceDirectory, '/demo');
45 |
46 | var lintFiles = [
47 | 'gulpfile.js',
48 | // Karma configuration
49 | 'karma-*.conf.js'
50 | ].concat(sourceFiles);
51 |
52 | gulp.task('build', ['pug'], function() {
53 | gulp.src(sourceFiles.concat([ './.tmp/carousel.template.js' ]))
54 | .pipe(plumber())
55 | .pipe(babel({
56 | presets: ['es2015']
57 | }))
58 | .pipe(concat('ui-carousel.js'))
59 | .pipe(gulp.dest('./dist/'))
60 | .pipe(uglify())
61 | .pipe(rename('ui-carousel.min.js'))
62 | .pipe(gulp.dest('./dist'));
63 | });
64 |
65 | /**
66 | * Process
67 | */
68 | gulp.task('process-all', function (done) {
69 | runSequence('pug', 'demo', 'jshint', 'build', 'test', done);
70 | });
71 |
72 | /**
73 | * Watch task
74 | */
75 | gulp.task('watch', function () {
76 |
77 | // Watch JavaScript files
78 | gulp.watch(sourceFiles, ['process-all']);
79 | gulp.watch(pugFiles, ['process-all']);
80 | gulp.watch(path.join(sourceDirectory, '/**/*.scss'), ['scss']);
81 | gulp.watch(path.join(sourceDirectory, '/ui-carousel/fonts/**/*'), ['other']);
82 | gulp.watch(path.join(demoFiles, '/**/*'), ['demo']);
83 |
84 | // watch test files and re-run unit tests when changed
85 | gulp.watch(path.join(testDirectory, '/**/*.js'), ['test']);
86 | });
87 |
88 | /**
89 | * stylesheet
90 | */
91 | gulp.task('scss', function() {
92 | return gulp.src(cssFiles)
93 | .pipe(sourcemaps.init())
94 | .pipe(sass().on('error', sass.logError))
95 | .pipe(gulp.dest('./dist'))
96 | .pipe(minifyCss())
97 | .pipe(rename('ui-carousel.min.css'))
98 | .pipe(sourcemaps.write())
99 | .pipe(gulp.dest('./dist'));
100 | });
101 |
102 | gulp.task('other', function () {
103 | return gulp.src(sourceDirectory + '/ui-carousel/fonts/**/*')
104 | .pipe(gulp.dest('./dist/fonts'));
105 | });
106 |
107 | gulp.task('pug', function() {
108 | return gulp.src(pugFiles)
109 | .pipe(pug({}))
110 | .pipe(gulp.dest('./.tmp'))
111 | .pipe(ngHtml2Js({
112 | moduleName: 'ui.carousel',
113 | prefix: 'ui-carousel/'
114 | }))
115 | .pipe(gulp.dest('./.tmp'));
116 | });
117 |
118 | gulp.task('demo', function() {
119 | gulp.src(demoFiles + '/*.pug')
120 | .pipe(pug({ pretty: true }))
121 | .pipe(gulp.dest('./demo'));
122 |
123 | gulp.src(demoFiles + '/*.scss')
124 | .pipe(sass().on('error', sass.logError))
125 | .pipe(gulp.dest('./demo'));
126 |
127 | gulp.src(demoFiles + '/*.js')
128 | .pipe(babel({
129 | presets: ['es2015']
130 | }))
131 | .pipe(concat('main.js'))
132 | .pipe(gulp.dest('./demo'));
133 | });
134 |
135 | /**
136 | * Validate source JavaScript
137 | */
138 | gulp.task('jshint', function () {
139 | return gulp.src(lintFiles)
140 | .pipe(plumber())
141 | .pipe(jshint())
142 | .pipe(jshint.reporter('jshint-stylish'))
143 | .pipe(jshint.reporter('fail'));
144 | });
145 |
146 | /**
147 | * Run test once and exit
148 | */
149 | gulp.task('test', function (done) {
150 | karma.start({
151 | configFile: __dirname + '/karma-src.conf.js',
152 | singleRun: true
153 | }, done);
154 | });
155 |
156 | /**
157 | * Run test once and exit
158 | */
159 | gulp.task('test-dist-concatenated', function (done) {
160 | karma.start({
161 | configFile: __dirname + '/karma-dist-concatenated.conf.js',
162 | singleRun: true
163 | }, done);
164 | });
165 |
166 | /**
167 | * Run test once and exit
168 | */
169 | gulp.task('test-dist-minified', function (done) {
170 | karma.start({
171 | configFile: __dirname + '/karma-dist-minified.conf.js',
172 | singleRun: true
173 | }, done);
174 | });
175 |
176 |
177 | /**
178 | * gh-pages pubish
179 | */
180 | gulp.task('gh-pages', ['build'], function() {
181 | gulp.src('./demo/index.html')
182 | .pipe(usemin({
183 | css: [ minifyCss(), 'concat' ],
184 | html: [ minifyHtml({ empty: true }) ],
185 | js: [ uglify() ],
186 | }))
187 | .pipe(gulp.dest('_gh-pages/'));
188 |
189 | gulp.src('./demo/hero.png')
190 | .pipe(gulp.dest('_gh-pages/'));
191 | });
192 |
193 | gulp.task('default', function () {
194 | runSequence('watch');
195 | });
196 |
--------------------------------------------------------------------------------
/karma-dist-concatenated.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 |
7 | // base path that will be used to resolve all patterns (eg. files, exclude)
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13 | frameworks: ['jasmine'],
14 |
15 | plugins: [
16 | 'karma-jasmine',
17 | 'karma-phantomjs-launcher'
18 | ],
19 |
20 | // list of files / patterns to load in the browser
21 | files: [
22 | 'bower_components/angular/angular.js',
23 | 'bower_components/angular-sanitize/angular-sanitize.js',
24 | 'bower_components/angular-mocks/angular-mocks.js',
25 | 'dist/ui-carousel.js',
26 | 'test/unit/**/*.js'
27 | ],
28 |
29 |
30 | // list of files to exclude
31 | exclude: [
32 | ],
33 |
34 |
35 | // preprocess matching files before serving them to the browser
36 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
37 | preprocessors: {
38 | },
39 |
40 |
41 | // test results reporter to use
42 | // possible values: 'dots', 'progress'
43 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
44 | reporters: ['progress'],
45 |
46 |
47 | // web server port
48 | port: 9876,
49 |
50 |
51 | // enable / disable colors in the output (reporters and logs)
52 | colors: true,
53 |
54 |
55 | // level of logging
56 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
57 | logLevel: config.LOG_INFO,
58 |
59 |
60 | // enable / disable watching file and executing tests whenever any file changes
61 | autoWatch: true,
62 |
63 |
64 | // start these browsers
65 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
66 | browsers: ['PhantomJS'],
67 |
68 |
69 | // Continuous Integration mode
70 | // if true, Karma captures browsers, runs the tests and exits
71 | singleRun: false
72 | });
73 | };
74 |
--------------------------------------------------------------------------------
/karma-dist-minified.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 |
7 | // base path that will be used to resolve all patterns (eg. files, exclude)
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13 | frameworks: ['jasmine'],
14 |
15 | plugins: [
16 | 'karma-jasmine',
17 | 'karma-phantomjs-launcher'
18 | ],
19 |
20 | // list of files / patterns to load in the browser
21 | files: [
22 | 'bower_components/angular/angular.js',
23 | 'bower_components/angular-sanitize/angular-sanitize.js',
24 | 'bower_components/angular-mocks/angular-mocks.js',
25 | 'dist/ui-carousel.min.js',
26 | 'test/unit/**/*.js'
27 | ],
28 |
29 |
30 | // list of files to exclude
31 | exclude: [
32 | ],
33 |
34 |
35 | // preprocess matching files before serving them to the browser
36 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
37 | preprocessors: {
38 | },
39 |
40 |
41 | // test results reporter to use
42 | // possible values: 'dots', 'progress'
43 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
44 | reporters: ['progress'],
45 |
46 |
47 | // web server port
48 | port: 9876,
49 |
50 |
51 | // enable / disable colors in the output (reporters and logs)
52 | colors: true,
53 |
54 |
55 | // level of logging
56 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
57 | logLevel: config.LOG_INFO,
58 |
59 |
60 | // enable / disable watching file and executing tests whenever any file changes
61 | autoWatch: true,
62 |
63 |
64 | // start these browsers
65 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
66 | browsers: ['PhantomJS'],
67 |
68 |
69 | // Continuous Integration mode
70 | // if true, Karma captures browsers, runs the tests and exits
71 | singleRun: false
72 | });
73 | };
74 |
--------------------------------------------------------------------------------
/karma-src.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 |
7 | // base path that will be used to resolve all patterns (eg. files, exclude)
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
13 | frameworks: ['jasmine'],
14 |
15 | plugins: [
16 | 'karma-jasmine',
17 | 'karma-phantomjs-launcher',
18 | 'karma-babel-preprocessor',
19 | 'karma-spec-reporter'
20 | ],
21 |
22 | // list of files / patterns to load in the browser
23 | files: [
24 | 'bower_components/angular/angular.js',
25 | 'bower_components/angular-sanitize/angular-sanitize.js',
26 | 'bower_components/angular-mocks/angular-mocks.js',
27 | 'src/**/*.module.js',
28 | 'src/**/*.js',
29 | 'test/unit/**/*.js'
30 | ],
31 |
32 | usePolling: true,
33 |
34 |
35 | // list of files to exclude
36 | exclude: [
37 | ],
38 |
39 |
40 | // preprocess matching files before serving them to the browser
41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
42 | preprocessors: {
43 | 'src/**/*.js': ['babel'],
44 | 'test/**/*.js': ['babel']
45 | },
46 |
47 | babelPreprocessor: {
48 | options: {
49 | presets: ['es2015'],
50 | sourceMap: 'inline'
51 | },
52 | filename: function(file) {
53 | return file.originalPath.replace(/\.js$/, '.es5.js');
54 | },
55 | sourceFileName: function(file) {
56 | return file.originalPath;
57 | }
58 | },
59 |
60 |
61 | // test results reporter to use
62 | // possible values: 'dots', 'progress'
63 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
64 | reporters: ['progress', 'spec'],
65 |
66 |
67 | // web server port
68 | port: 9876,
69 |
70 |
71 | // enable / disable colors in the output (reporters and logs)
72 | colors: true,
73 |
74 |
75 | // level of logging
76 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
77 | logLevel: config.LOG_INFO,
78 |
79 |
80 | // enable / disable watching file and executing tests whenever any file changes
81 | autoWatch: true,
82 |
83 |
84 | // start these browsers
85 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
86 | browsers: ['PhantomJS'],
87 |
88 |
89 | // Continuous Integration mode
90 | // if true, Karma captures browsers, runs the tests and exits
91 | singleRun: false
92 | });
93 | };
94 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-ui-carousel",
3 | "version": "0.1.10",
4 | "author": {
5 | "name": "mihnsen",
6 | "email": "minhnt.hut@gmail.com"
7 | },
8 | "description": "A simple, lightweight carousel for angularjs",
9 | "license": "MIT License",
10 | "homepage": "https://mihnsen.github.io/ui-carousel/",
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/mihnsen/ui-carousel.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/mihnsen/ui-carousel/issues"
17 | },
18 | "scripts": {
19 | "test": "gulp test"
20 | },
21 | "main": "dist/ui-carousel.js",
22 | "keywords": [
23 | "ui-carousel",
24 | "carousel",
25 | "carousel",
26 | "angular-carousel",
27 | "angular-carousel",
28 | "angular-ui-carousel",
29 | "ng-carousel"
30 | ],
31 | "dependencies": { },
32 | "devDependencies": {
33 | "babel-preset-es2015": "^6.16.0",
34 | "gulp": "^3.8.7",
35 | "gulp-babel": "^6.1.2",
36 | "gulp-concat": "^2.3.4",
37 | "gulp-jshint": "^1.8.4",
38 | "gulp-minify-css": "^1.2.4",
39 | "gulp-minify-html": "^1.0.6",
40 | "gulp-ng-html2js": "^0.2.2",
41 | "gulp-plumber": "^0.6.6",
42 | "gulp-pug": "^3.0.4",
43 | "gulp-rename": "^1.2.0",
44 | "gulp-sass": "^2.3.2",
45 | "gulp-sourcemaps": "^1.6.0",
46 | "gulp-uglify": "^0.3.1",
47 | "gulp-usemin": "^0.3.24",
48 | "jasmine-core": "^2.5.2",
49 | "jshint-stylish": "^0.4.0",
50 | "karma": "^1.3.0",
51 | "karma-babel-preprocessor": "^6.0.1",
52 | "karma-jasmine": "^1.0.2",
53 | "karma-phantomjs-launcher": "^1.0.2",
54 | "karma-spec-reporter": "0.0.26",
55 | "pug": "^2.0.0-beta6",
56 | "run-sequence": "^1.0.2"
57 | },
58 | "engines": {
59 | "node": ">=0.8.0"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/demo/index.pug:
--------------------------------------------------------------------------------
1 | doctype html
2 | html(ng-app="App")
3 | head
4 | meta(charset='utf-8')
5 | meta(http-equiv='X-UA-Compatible', content='chrome=1')
6 | meta(name='description', content='UI-Carousel lightweight module')
7 | link(rel='icon', type='image/x-icon', href='https://assets-cdn.github.com/favicon.ico')
8 |
9 | link(href='https://fonts.googleapis.com/css?family=Lato:400,500,700,900', rel='stylesheet')
10 | link(href='https://fonts.googleapis.com/css?family=Pacifico', rel='stylesheet')
11 |
12 | link(rel='stylesheet', type='text/css', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.css')
13 |
14 | // build:css style.css
15 | link(rel='stylesheet', type='text/css', href='../bower_components/prism/themes/prism-okaidia.css')
16 | link(rel='stylesheet', type='text/css', href='../dist/ui-carousel.css')
17 | link(rel='stylesheet', type='text/css', href='style.css')
18 | // endbuild
19 |
20 | title UI-Carousel - simple lightweight carousel for angular app
21 | script.
22 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
23 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
24 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
25 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
26 | ga('create', 'UA-85040392-2', 'auto');
27 | ga('send', 'pageview');
28 |
29 | body(ng-controller="CarouselDemoCtrl as DemoCtrl")
30 | header.header
31 | .container
32 | h1 UI-Carousel
33 | p A simple, lightweight carousel for AngularJS app.
34 | p
35 | | Inspired by
36 | a(href='http://kenwheeler.github.io/slick/', target='_blank') Slick carousel
37 | main.main(role='main')
38 | section.screen
39 | .container
40 | .content-box
41 | h2.title Features
42 | ul.features
43 | //li Fully responsive. Scales with its container.
44 | //li Separate settings per breakpoint
45 | //-li Uses CSS3 when available. Fully functional when not.
46 | //-li Swipe enabled. Or disabled, if you prefer.
47 | //-li Desktop mouse dragging
48 | //-li Fully accessible with arrow key navigation
49 | //-li Add, remove, filter & unfilter slides
50 | li CSS3 (IE9+ will working good, lower IE version not tested)
51 | li Infinite looping.
52 | li Autoplay, dots, arrows, callbacks, etc...
53 | .divider
54 | .content-box
55 | h2.title Single Item
56 | ui-carousel(slides="DemoCtrl.single.slides", dots="true", on-init="DemoCtrl.singleInit()", infinite="false" on-after-change="DemoCtrl.singleAfter(currentSlide)")
57 | carousel-item
58 | h3 {{ item + 1 }}
59 | pre
60 | code.language-html(prism="")
61 | | {{ DemoCtrl.single.source }}
62 |
63 | .divider
64 | .content-box
65 | h2.title Multiple Item
66 | ui-carousel(
67 | slides="DemoCtrl.multiple.slides",
68 | slides-to-show="3",
69 | slides-to-scroll="3",
70 | dots="true"
71 | )
72 | carousel-item
73 | h3 {{ item + 1 }}
74 | pre
75 | code.language-html(prism="")
76 | | {{ DemoCtrl.multiple.source }}
77 | .divider
78 | .content-box
79 | h2.title Autoplay
80 | ui-carousel(
81 | slides="DemoCtrl.autoplay.slides",
82 | slides-to-show="3",
83 | slides-to-scroll="1",
84 | initial-slide="1",
85 | autoplay="true",
86 | autoplay-speed="2000",
87 | dots="true"
88 | )
89 | carousel-item
90 | h3 {{ item + 1 }}
91 | pre
92 | code.language-html(prism="")
93 | | {{ DemoCtrl.autoplay.source }}
94 | .divider
95 | .content-box
96 | h2.title Fade
97 | ui-carousel(
98 | slides="DemoCtrl.fade.slides",
99 | slides-to-show="3",
100 | slides-to-scroll="2",
101 | fade="true",
102 | dots="true",
103 | )
104 | carousel-item
105 | .image
106 | img(src="{{ item }}")
107 | pre
108 | code.language-html(prism="")
109 | | {{ DemoCtrl.fade.source }}
110 | .divider
111 | .content-box
112 | h2.title Add & remove
113 | ui-carousel(
114 | slides="DemoCtrl.add.slides",
115 | slides-to-show="3",
116 | slides-to-scroll="1",
117 | dots="true",
118 | )
119 | carousel-item
120 | h3 {{ item + 1 }}
121 | .buttons
122 | a.button(ng-click="DemoCtrl.addItem()") Add Slide
123 | a.button(ng-click="DemoCtrl.removeItem()") Remove Slide
124 | pre
125 | code.language-html(prism="")
126 | | {{ DemoCtrl.add.source }}
127 | .divider
128 | .content-box
129 | h2.title Customzie
130 | pre
131 | code.language-html(prism="")
132 | | {{ DemoCtrl.customize }}
133 |
134 | section.screen.extra
135 | .divider
136 | h2.title Follow & Share
137 | .text-center
138 | // Place this tag where you want the button to render.
139 | a.github-button(href='https://github.com/mihnsen', aria-label='Follow @mihnsen on GitHub') Follow @mihnsen
140 | // Place this tag where you want the button to render.
141 | a.github-button(href='https://github.com/mihnsen/ui-carousel', data-icon='octicon-star', data-count-href='/mihnsen/ui-carousel/stargazers', data-count-api='/repos/mihnsen/ui-carousel#stargazers_count', data-count-aria-label='# stargazers on GitHub', aria-label='Star mihnsen/ui-carousel on GitHub') Star
142 | .divider
143 | h2.title Issues tracker
144 | .text-center
145 | // Place this tag where you want the button to render.
146 | a.github-button(href='https://github.com/mihnsen/ui-carousel/issues', data-icon='octicon-issue-opened', data-style='mega', data-count-api='/repos/mihnsen/ui-carousel#open_issues_count', data-count-aria-label='# issues on GitHub', aria-label='Issue mihnsen/ui-carousel on GitHub') Issue
147 |
148 |
149 | footer.footer
150 | .container
151 | ul.footer-links
152 | li
153 | a(href='http://github.com/mihnsen/ui-carousel', target='_blank') Github
154 | li
155 | a(href='http://ownego.com', target='_blank') About
156 | p
157 | | Designed and built with love by
158 | a(href='http://www.github.com/mihnsen', target='_blank') @mihnsen
159 | p
160 | | Code licensed
161 | a(href='https://github.com/twbs/bootstrap/blob/master/LICENSE', target='_blank') MIT
162 | a(href='https://github.com/mihnsen/ui-carousel')
163 | img(style='position: fixed; top: 0; right: 0; border: 0;', src='https://camo.githubusercontent.com/52760788cde945287fbb584134c4cbc2bc36f904/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f77686974655f6666666666662e706e67', alt='Fork me on GitHub', data-canonical-src='https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png')
164 |
165 | script(async='', defer='', src='https://buttons.github.io/buttons.js')
166 |
167 | // build:js main.js
168 | script(src='../bower_components/angular/angular.js')
169 | script(src='../bower_components/angular-sanitize/angular-sanitize.js')
170 | script(src='../bower_components/prism/prism.js')
171 | script(type='text/javascript', src='../dist/ui-carousel.js')
172 | script(type='text/javascript', src='main.js')
173 | // endbuild
174 |
--------------------------------------------------------------------------------
/src/demo/main.js:
--------------------------------------------------------------------------------
1 | var app = angular.module('App', ['ui.carousel', 'ngSanitize']);
2 |
3 | app.run(['Carousel', (Carousel) => {
4 | Carousel.setOptions({});
5 | }]);
6 |
7 | app.controller('CarouselDemoCtrl', ['$scope', 'Carousel', function($scope, Carousel) {
8 | 'use strict';
9 |
10 | this.singleInit = () => {
11 | console.log('single init');
12 | };
13 |
14 | this.singleAfter = (currentSlide) => {
15 | console.log(currentSlide);
16 | };
17 |
18 | this.single = {
19 | slides: [...Array(6).keys()],
20 | source: '\n' +
21 | ' \n' +
22 | ' {{ item + 1 }}
\n' +
23 | ' \n' +
24 | ''
25 | };
26 | this.multiple = {
27 | slides: [...Array(9).keys()],
28 | source: '\n' +
29 | ' \n' +
30 | ' {{ item + 1 }}
\n' +
31 | ' \n' +
32 | ''
33 | };
34 |
35 | this.autoplay = {
36 | slides: [...Array(6).keys()],
37 | source: '\n' +
38 | ' \n' +
39 | ' {{ item + 1 }}
\n' +
40 | ' \n' +
41 | ''
42 | };
43 |
44 | this.fade = {
45 | slides: [
46 | 'http://lorempixel.com/560/400/sports/1',
47 | 'http://lorempixel.com/560/400/sports/2',
48 | 'http://lorempixel.com/560/400/sports/3',
49 | ],
50 | source: '\n' +
51 | ' \n' +
52 | ' \n' +
53 | ' \n' +
54 | ''
55 | };
56 |
57 | this.addIndex = 1;
58 | this.addItem = () => {
59 | this.add.slides.push(this.addIndex++);
60 | };
61 | this.removeItem = () => {
62 | if (this.add.slides.length <= 1) {
63 | return;
64 | }
65 | this.add.slides.splice(-1, 1);
66 | this.addIndex--;
67 | };
68 | this.add = {
69 | slides: [...Array(1).keys()],
70 | source: '\n' +
71 | ' \n' +
72 | ' {{ item + 1 }}
\n' +
73 | ' \n' +
74 | ''
75 | };
76 |
77 | this.customize=
78 | '\n' +
79 | ' \n' +
80 | ' \n' +
81 | ' \n' +
82 | '
\n' +
83 | ' {{ item.name }}
\n' +
84 | ' {{ item.description }} \n' +
85 | ' \n' +
86 | '
\n' +
87 | ' \n' +
88 | ' \n' +
89 | ' \n' +
90 | ' \n' +
91 | ' \n' +
92 | ' \n' +
93 | ' \n' +
94 | ' \n' +
95 | ' \n' +
96 | ' \n' +
97 | ' \n' +
98 | ' \n' +
99 | ' \n' +
100 | ''
101 | ;
102 | }]);
103 |
104 | app.directive('prism', [function() {
105 | return {
106 | restrict: 'A',
107 | link: function ($scope, element, attrs) {
108 | element.ready(function() {
109 | Prism.highlightElement(element[0]);
110 | });
111 | }
112 | }
113 | }]);
114 |
--------------------------------------------------------------------------------
/src/demo/style.scss:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 16px;
3 | line-height: 20px;
4 | font-family: 'Roboto', sans-serif;
5 | background-color: #fafafa;
6 | }
7 | .container {
8 | max-width: 560px;
9 | }
10 | .header {
11 | padding: 50px 0 10px;
12 | color: #3498db;
13 | background: #fff;
14 | text-align: center;
15 |
16 | h1 {
17 | margin-bottom: 40px;
18 | }
19 | }
20 | h1 {
21 | font-weight: 400;
22 | font-family: 'Pacifico', cursive;
23 | font-size: 70px;
24 | }
25 | h2.title {
26 | font-weight: bold;
27 | font-size: 40px;
28 | font-family: 'Pacifico', cursive;
29 | margin-bottom: 40px;
30 | }
31 |
32 | .footer {
33 | font-size: 14px;
34 | padding: 30px 0;
35 | color: #99979c;
36 | background-color: #2a2730;
37 | }
38 | .footer p {
39 | margin-bottom: 0;
40 | }
41 | .footer-links {
42 | padding: 0;
43 | list-style: none;
44 | }
45 | .footer-links li {
46 | display: inline;
47 | margin-right: 15px;
48 | }
49 | .footer a {
50 | color: #fff;
51 | }
52 | .main {
53 | background-color: #3498db;
54 | color: #fff;
55 | padding: 30px 0 50px;
56 | position: relative;
57 | min-height: 500px;
58 | text-align: center;
59 | }
60 | .divider {
61 | display: block;
62 | float: none;
63 | max-width: 500px;
64 | height: 1px;
65 | margin: 40px auto;
66 | clear: both;
67 | float: none;
68 | background-color: #fff;
69 | }
70 | ul.features {
71 | padding: 0;
72 | list-style: none;
73 |
74 | li {
75 | padding: 7px 0;
76 | }
77 | }
78 |
79 | h3 {
80 | font-weight: 700;
81 | background: #fff;
82 | color: #3498db;
83 | font-size: 36px;
84 | line-height: 100px;
85 | margin: 10px;
86 | padding: 10px;
87 | position: relative;
88 | text-align: center;
89 | }
90 | .ui-carousel {
91 | margin-bottom: 50px;
92 | .image {
93 | padding: 10px;
94 |
95 | img {
96 | display: block;
97 | border: 5px solid #FFF;
98 | width: 100%;
99 | }
100 | }
101 | }
102 | pre[class*="language-"] {
103 | background-color: #fdfdfd;
104 | margin-bottom: 1em;
105 | margin-left: 10px;
106 | margin-right: 10px;
107 | border-radius: 0;
108 | }
109 | code[class*="language"] {
110 | background: black;
111 | max-height: inherit;
112 | padding: 15px;
113 | display: block;
114 | overflow: auto;
115 | text-shadow: none;
116 | }
117 |
118 | .buttons {
119 | padding: 0 20px 20px;
120 | margin-bottom: 10px;
121 | }
122 |
123 | .button {
124 | float: left;
125 | background: #fff;
126 | color: #3498db;
127 | display: block;
128 | font-size: 16px;
129 | margin: 20px auto;
130 | padding: 20px;
131 | text-align: center;
132 | text-decoration: none;
133 | width: 48%;
134 | margin-right: 2%;
135 | cursor: pointer;
136 | }
137 |
138 | .button:hover {
139 | text-decoration: none;
140 | }
141 |
--------------------------------------------------------------------------------
/src/ui-carousel/controllers/carousel.controller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * angular-ui-carousel
3 | * for example:
4 | * length = 8, show = 4, scroll = 3, current = 0
5 | * ---------
6 | * | |
7 | * |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
8 | * | |
9 | * ---------
10 | * rectangle is visible for users
11 | */
12 | angular.module('ui.carousel.controllers')
13 | .controller('CarouselController', [
14 | '$scope', '$element', '$timeout', '$q', 'Carousel', '$window',
15 | function ($scope, $element, $timeout, $q, Carousel, $window) {
16 |
17 | /**
18 | * Initial carousel
19 | *
20 | * Mirgate to angularjs 1.6
21 | * @see https://docs.angularjs.org/guide/migration#commit-bcd0d4
22 | */
23 | this.$onInit = () => {
24 | this.initOptions();
25 | this.initRanges();
26 | this.setProps();
27 | this.setupInfinite();
28 | };
29 |
30 | /**
31 | * Init option based on directive config
32 | */
33 | this.initOptions = () => {
34 | this.options = angular.extend({}, Carousel.getOptions());
35 |
36 | // TODO customize attribute from directive
37 | if (this.initialSlide !== undefined) {
38 | this.options.initialSlide = this.initialSlide;
39 | }
40 | if (this.fade !== undefined) {
41 | this.options.fade = this.fade;
42 | }
43 | if (this.autoplay !== undefined) {
44 | this.options.autoplay = this.autoplay;
45 | }
46 | if (this.autoplaySpeed !== undefined) {
47 | this.options.autoplaySpeed = this.autoplaySpeed;
48 | }
49 | if (this.cssEase !== undefined) {
50 | this.options.cssEase = this.cssEase;
51 | }
52 | if (this.speed !== undefined) {
53 | this.options.speed = this.speed;
54 | }
55 | if (this.infinite !== undefined) {
56 | this.options.infinite = this.infinite;
57 | }
58 | if (this.arrows !== undefined) {
59 | this.options.arrows = this.arrows;
60 | }
61 | if (this.dots !== undefined) {
62 | this.options.dots = this.dots;
63 | }
64 | if (this.visiblePrev !== undefined) {
65 | this.options.visiblePrev = this.visiblePrev;
66 | }
67 | if (this.visibleNext !== undefined) {
68 | this.options.visibleNext = this.visibleNext;
69 | }
70 |
71 | // TODO write more options for fade mode
72 | // In fade mode we have to setting slides-to-show and slides-to-scroll
73 | // to 1 slide
74 | if (this.options.fade) {
75 | this.options.slidesToShow = 1;
76 | this.options.slidesToScroll = 1;
77 | } else {
78 | if (this.show) {
79 | this.options.slidesToShow = this.show;
80 | }
81 | if (this.scroll) {
82 | this.options.slidesToScroll = this.scroll;
83 | }
84 | }
85 | };
86 |
87 | /**
88 | * init variables, slides, ..
89 | */
90 | this.initRanges = () => {
91 | if (!this.slides) {
92 | this.slides = [];
93 | }
94 |
95 | this.isCarouselReady = false;
96 | this.isTrackMoving = false;
97 | this.track = $element.find('.track');
98 | this.width = 1; // Fake width
99 | this.currentSlide = this.options.initialSlide;
100 | this.trackStyle = {};
101 | this.slideStyle = {};
102 |
103 | this.isVisibleDots = false;
104 | this.isVisiblePrev = this.options.visiblePrev;
105 | this.isVisibleNext = this.options.visibleNext;
106 |
107 | this.isClickablePrev = false;
108 | this.isClickableNext = false;
109 |
110 | this.animType = null;
111 | this.transformType = null;
112 | this.transitionType = null;
113 | };
114 |
115 | /**
116 | * Init UI and carousel track
117 | */
118 | this.initUI = () => {
119 | this.width = $element[0].clientWidth;
120 |
121 | // Update track width first
122 | this.initTrack();
123 |
124 | // Then item style
125 | $timeout(() => {
126 | this.updateItemStyle();
127 | }, 200);
128 | };
129 |
130 | /**
131 | * update common style for each carousel item
132 | */
133 | this.updateItemStyle = () => {
134 | this.itemWidth = this.width / this.options.slidesToShow;
135 | this.slideStyle = {
136 | 'width': this.itemWidth + 'px'
137 | };
138 | };
139 |
140 | /**
141 | * init carousel track
142 | * also make Carousel is Ready
143 | */
144 | this.initTrack = () => {
145 | const itemWidth = this.width / this.options.slidesToShow;
146 | const trackWidth = itemWidth * this.slidesInTrack.length;
147 |
148 | this.trackStyle.width = trackWidth + 'px';
149 |
150 | this
151 | .slideHandler(this.currentSlide)
152 | .finally(() => {
153 | this.isCarouselReady = true;
154 |
155 | if (!this.options.fade) {
156 | this.refreshTrackStyle();
157 | }
158 |
159 | // onInit callback
160 | if (this.onInit) {
161 | this.onInit();
162 | }
163 | })
164 | .catch(() => {
165 | // Catch err
166 | });
167 | };
168 |
169 | /**
170 | * @see https://github.com/kenwheeler/slick/blob/master/slick/slick.js#L680
171 | *
172 | * Sync slide to place it should be
173 | * for example:
174 | * - 9 total, 3 show, 3 scroll, current 1
175 | * => next index = 3 (previous index counted = 0)
176 | *
177 | * and scroll to next page:
178 | * - 6 total, 1 show, 1 scroll, current 0 => next index = 1
179 | * - 9 total, 3 show, 3 scroll, current 1 => next index = 3
180 | * - 9 total, 3 show, 3 scroll, current 3 => next index = 6
181 | * - 9 total, 3 show, 3 scroll, current 8 => next index = 3
182 | * - 8 total, 4 show, 3 scroll, current 1 => next index = 4
183 | */
184 | this.next = () => {
185 | if (!this.isClickableNext) {
186 | return false;
187 | }
188 |
189 | const indexOffset = this.getIndexOffset();
190 | const slideOffset = indexOffset === 0
191 | ? this.options.slidesToScroll
192 | : indexOffset;
193 |
194 | this
195 | .slideHandler(this.currentSlide + slideOffset)
196 | .catch(() => {
197 | // Catch err
198 | });
199 | };
200 |
201 | /**
202 | * move to previous slide
203 | * same calculate with next
204 | * @see next function
205 | */
206 | this.prev = () => {
207 | if (!this.isClickablePrev) {
208 | return false;
209 | }
210 |
211 | const indexOffset = this.getIndexOffset();
212 | const slideOffset = indexOffset === 0
213 | ? this.options.slidesToScroll
214 | : this.options.slidesToShow - indexOffset;
215 |
216 | this
217 | .slideHandler(this.currentSlide - slideOffset)
218 | .catch(() => {
219 | // Catch err
220 | });
221 | };
222 |
223 | /**
224 | * Get index offset
225 | */
226 | this.getIndexOffset = () => {
227 | const scrollOffset = this.slides.length % this.options.slidesToScroll !== 0;
228 | const indexOffset = scrollOffset
229 | ? 0
230 | : (this.slides.length - this.currentSlide) % this.options.slidesToScroll;
231 |
232 | return indexOffset;
233 | };
234 |
235 | /**
236 | * move to page
237 | * @params int page
238 | * Page counter from 0 (start = 0)
239 | */
240 | this.movePage = (page) => {
241 | const target = this.options.slidesToScroll * page;
242 | this
243 | .slideHandler(target)
244 | .catch(() => {
245 | // Catch err
246 | });
247 | };
248 |
249 | /**
250 | * hanlder carousel
251 | * @description move carousel to correct page
252 | *
253 | * @params int index
254 | */
255 | this.slideHandler = (index) => {
256 | // TODO prevent when slides not exists
257 | if (!this.slides) {
258 | return $q.reject('Carousel not fully setup');
259 | }
260 |
261 | // TODO Prevent when track is moving
262 | if (this.isTrackMoving) {
263 | return $q.reject('Track is moving');
264 | }
265 |
266 | const len = this.slides.length;
267 | const show = this.options.slidesToShow;
268 |
269 | if (len <= show) {
270 | this.correctTrack();
271 | return $q.reject('Length of slides smaller than slides to show');
272 | }
273 |
274 | // We need target to destination
275 | // and a anim slide to translate track
276 | //
277 | // anim = animSlide (which we use to move)
278 | // target = targetSlide
279 | const anim = index;
280 | let target = null;
281 |
282 | if (anim < 0) {
283 | if (len % this.options.slidesToScroll !== 0) {
284 | target = len - (len % this.options.slidesToScroll);
285 | } else {
286 | target = len + anim;
287 | }
288 | } else if (anim >= len) {
289 | if (len % this.options.slidesToScroll !== 0) {
290 | target = 0;
291 | } else {
292 | target = anim - len;
293 | }
294 | } else {
295 | target = anim;
296 | }
297 |
298 | if (this.onBeforeChange) {
299 | // @see https://docs.angularjs.org/guide/directive
300 | this.onBeforeChange({ currentSlide: this.currentSlide, target: target });
301 | }
302 |
303 | // Fade handler
304 | if (this.options.fade) {
305 | this.currentSlide = target;
306 |
307 | // XXX
308 | // afterChange method
309 | // fire after faded
310 | // Should be revised
311 | $timeout(() => {
312 | this.autoplayTrack();
313 |
314 | if (this.onAfterChange) {
315 | this.onAfterChange({ currentSlide: this.currentSlide });
316 | }
317 | }, this.options.speed);
318 | return $q.when('Handler fade');
319 | }
320 |
321 | // No-fade handler
322 | const itemWidth = this.width / this.options.slidesToShow;
323 | let left = -1 * target * itemWidth;
324 | if (this.options.infinite) {
325 | left = -1 * (anim + show) * itemWidth;
326 | }
327 |
328 | this.isTrackMoving = true;
329 | return this
330 | .moveTrack(left)
331 | .then(() => {
332 | this.isTrackMoving = false;
333 | this.currentSlide = target;
334 | this.autoplayTrack();
335 |
336 | if (target !== anim) {
337 | this.correctTrack();
338 | }
339 |
340 | if (!this.options.infinite) {
341 | if (this.currentSlide === 0) {
342 | this.isClickablePrev = false;
343 | this.isClickableNext = true;
344 | } else if (this.currentSlide === this.slidesInTrack.length - this.options.slidesToShow) {
345 | this.isClickableNext = false;
346 | this.isClickablePrev = true;
347 | } else {
348 | this.isClickablePrev = true;
349 | this.isClickableNext = true;
350 | }
351 | }
352 |
353 | // XXX
354 | // afterChange method
355 | // fire after 200ms wakeup and correct track
356 | // Should be revised
357 | $timeout(() => {
358 | if (this.onAfterChange) {
359 | this.onAfterChange({ currentSlide: this.currentSlide });
360 | }
361 | }, 200);
362 | });
363 | };
364 |
365 |
366 | /**
367 | * moveTrack
368 | * move track to left position using css3 translate
369 | * for example left: -1000px
370 | */
371 | this.moveTrack = (left) => {
372 | const deferred = $q.defer();
373 | if (this.options.vertical === false) {
374 | this.trackStyle[this.animType] = 'translate3d(' + left + 'px, 0px, 0px)';
375 | } else {
376 | this.trackStyle[this.animType] = 'translate3d(0px, ' + left + 'px, 0px)';
377 | }
378 |
379 | $timeout(() => {
380 | deferred.resolve('Track moved');
381 | }, this.options.speed);
382 |
383 | return deferred.promise;
384 | };
385 |
386 | /**
387 | * correctTrack
388 | * @description correct track after move to animSlide we have to move track
389 | * to exactly its position
390 | */
391 | this.correctTrack = () => {
392 | if (this.options.infinite) {
393 | let left = 0;
394 | if ( this.slides.length > this.options.slidesToShow ) {
395 | left = -1 * (this.currentSlide + this.options.slidesToShow) * this.itemWidth;
396 | }
397 |
398 | // Move without anim
399 | this.trackStyle[this.transitionType] =
400 | this.transformType + ' ' + 0 + 'ms ' + this.options.cssEase;
401 |
402 | this.isTrackMoving = true;
403 | $timeout(() => {
404 | this.trackStyle[this.animType] = 'translate3d(' + left + 'px, 0, 0px)';
405 |
406 | // Revert animation
407 | $timeout(() => {
408 | this.refreshTrackStyle();
409 | this.isTrackMoving = false;
410 | }, 200);
411 | });
412 | }
413 | };
414 |
415 | /**
416 | * Refresh track style
417 | */
418 | this.refreshTrackStyle = () => {
419 | this.trackStyle[this.transitionType] =
420 | this.transformType + ' ' + this.options.speed + 'ms ' + this.options.cssEase;
421 | };
422 |
423 | /**
424 | * autoplay track
425 | * @description autoplay = true
426 | */
427 | this.autoplayTrack = () => {
428 | if (this.options.autoplay) {
429 | if (this.timeout) {
430 | $timeout.cancel(this.timeout);
431 | }
432 |
433 | this.timeout = $timeout(() => {
434 | this.next();
435 |
436 | $timeout.cancel(this.timeout);
437 | this.timeout = null;
438 | }, this.options.autoplaySpeed);
439 | }
440 | };
441 |
442 | this.getSlideStyle = index => {
443 | let style = this.slideStyle;
444 | if (this.options.fade) {
445 | const left = -1 * index * this.itemWidth;
446 | const uniqueStyle = {
447 | position: 'relative',
448 | top: '0px',
449 | left: left + 'px',
450 | 'z-index': index === this.currentSlide? 10 : 9,
451 | opacity: index === this.currentSlide? 1 : 0
452 | };
453 |
454 | if (index >= this.currentSlide - 1 && index <= this.currentSlide + 1) {
455 | uniqueStyle.transition = 'opacity 250ms linear';
456 | }
457 |
458 | style = angular.extend(style, uniqueStyle);
459 | }
460 |
461 | return style;
462 | };
463 |
464 |
465 | /**
466 | * setupInfinite
467 | * To make carouse infinite we need close number of slidesToShow elements to
468 | * previous elements and to after elements
469 | *
470 | * length = 8, show = 4, scroll = 3, current = 0
471 | * ---------
472 | * | |
473 | * |4|5|6|7|0|1|2|3|4|5|6|7|1|2|3|4
474 | * | |
475 | * ---------
476 | */
477 | this.setupInfinite = () => {
478 | // Clone
479 | const len = this.slides.length;
480 | const show = this.options.slidesToShow;
481 |
482 | let tmpTrack = angular.copy(this.slides);
483 |
484 | if (this.options.infinite && this.options.fade === false) {
485 | if (len > show) {
486 | const number = show;
487 | for (let i = 0; i < number; i++) {
488 | tmpTrack.push(angular.copy(this.slides[i]));
489 | }
490 | for (let i = len -1; i >= len - show; i--) {
491 | tmpTrack.unshift(angular.copy(this.slides[i]));
492 | }
493 | }
494 | }
495 |
496 | this.slidesInTrack = tmpTrack;
497 | };
498 |
499 | /**
500 | * get number of dosts
501 | *
502 | * @return Array
503 | */
504 | this.getDots = () => {
505 | if (!this.slides) {
506 | return [];
507 | }
508 |
509 | const dots = Math.ceil(this.slides.length / this.options.slidesToScroll);
510 |
511 | let res = [];
512 | for (let i = 0; i < dots; i++) {
513 | res.push(i);
514 | }
515 | return res;
516 | };
517 |
518 | /**
519 | * set carousel property
520 | *
521 | * - animType
522 | * - transformType
523 | * - transitionType
524 | */
525 | this.setProps = () => {
526 | const bodyStyle = document.body.style;
527 |
528 | /* eslint-disable */
529 | if (bodyStyle.OTransform !== undefined) {
530 | this.animType = 'OTransform';
531 | this.transformType = '-o-transform';
532 | this.transitionType = 'OTransition';
533 | }
534 | if (bodyStyle.MozTransform !== undefined) {
535 | this.animType = 'MozTransform';
536 | this.transformType = '-moz-transform';
537 | this.transitionType = 'MozTransition';
538 | }
539 | if (bodyStyle.webkitTransform !== undefined) {
540 | this.animType = 'webkitTransform';
541 | this.transformType = '-webkit-transform';
542 | this.transitionType = 'webkitTransition';
543 | }
544 | if (bodyStyle.msTransform !== undefined) {
545 | this.animType = 'msTransform';
546 | this.transformType = '-ms-transform';
547 | this.transitionType = 'msTransition';
548 | }
549 | if (bodyStyle.transform !== undefined && this.animType !== false) {
550 | this.animType = 'transform';
551 | this.transformType = 'transform';
552 | this.transitionType = 'transition';
553 | }
554 | /* eslint-enable */
555 |
556 | this.transformsEnabled = true;
557 | };
558 |
559 | /**
560 | * Refresh carousel
561 | */
562 | this.refreshCarousel = () => {
563 | if (this.slides && this.slides.length && this.slides.length > this.options.slidesToShow) {
564 | this.isVisibleDots = true;
565 | this.isVisiblePrev = true;
566 | this.isVisibleNext = true;
567 | this.isClickablePrev = true;
568 | this.isClickableNext = true;
569 | } else {
570 | this.isVisibleDots = false;
571 | this.isVisiblePrev = this.options.visiblePrev || false;
572 | this.isVisibleNext = this.options.visibleNext || false;
573 | this.isClickablePrev = false;
574 | this.isClickableNext = false;
575 | }
576 |
577 | // Re-init UI
578 | this.initUI();
579 | };
580 |
581 | /**
582 | * refresh model
583 | */
584 | $scope.$watchCollection('ctrl.slides', slides => {
585 | if (!slides) {
586 | return;
587 | }
588 |
589 | // Init carousel
590 | if (this.currentSlide > slides.length - 1) {
591 | this.currentSlide = slides.length - 1;
592 | }
593 |
594 | this.setupInfinite();
595 | this.refreshCarousel();
596 | });
597 |
598 | /**
599 | * update when resize
600 | *
601 | * @see https://github.com/mihnsen/ui-carousel/issues/10
602 | * @author tarkant
603 | */
604 | angular.element($window).on('resize', this.refreshCarousel);
605 |
606 | /**
607 | * cleanup when done
608 | *
609 | * @see https://github.com/mihnsen/ui-carousel/issues/10
610 | * @author tarkant
611 | */
612 | $scope.$on('$destroy', function () {
613 | angular.element($window).off('resize');
614 | });
615 |
616 | // Prior to v1.5, we need to call `$onInit()` manually.
617 | // (Bindings will always be pre-assigned in these versions.)
618 | if (angular.version.major === 1 && angular.version.minor < 5) {
619 | this.$onInit();
620 | }
621 | }]);
622 |
--------------------------------------------------------------------------------
/src/ui-carousel/directives/carousel.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('ui.carousel.directives')
2 | .directive('uiCarousel', ['$compile', '$templateCache', '$sce',
3 | function($compile, $templateCache, $sce) {
4 |
5 | return { restrict: 'AE',
6 | bindToController: true,
7 | scope: {
8 | name: '=?',
9 | slides: '=',
10 | show: '=?slidesToShow',
11 | scroll: '=?slidesToScroll',
12 | classes: '@',
13 | fade: '=?',
14 | onChange: '=?',
15 | disableArrow: '=?',
16 | autoplay: '=?',
17 | autoplaySpeed: '=?',
18 | cssEase: '=?',
19 | speed: '=?',
20 | infinite: '=?',
21 | arrows: '=?',
22 | dots: '=?',
23 | initialSlide: '=?',
24 | visibleNext: '=?',
25 | visiblePrev: '=?',
26 |
27 | // Method
28 | onBeforeChange: '&',
29 | onAfterChange: '&',
30 | onInit: '&',
31 | },
32 | link($scope, el) {
33 | const template = angular.element(
34 | $templateCache.get('ui-carousel/carousel.template.html')
35 | );
36 |
37 | // dynamic injections to override the inner layers' components
38 | const injectComponentMap = {
39 | 'carousel-item': '.carousel-item',
40 | 'carousel-prev': '.carousel-prev',
41 | 'carousel-next': '.carousel-next',
42 | };
43 |
44 | const templateInstance = template.clone();
45 | angular.forEach(injectComponentMap, (innerSelector, outerSelector) => {
46 | const outerElement = el[0].querySelector(outerSelector);
47 | if (outerElement) {
48 | angular
49 | .element(templateInstance[0].querySelector(innerSelector))
50 | .html(outerElement.innerHTML);
51 | }
52 | });
53 |
54 | const compiledElement = $compile(templateInstance)($scope);
55 | el.addClass('ui-carousel').html('').append(compiledElement);
56 | },
57 |
58 | controller: 'CarouselController',
59 | controllerAs: 'ctrl'
60 | };
61 | }]);
62 |
--------------------------------------------------------------------------------
/src/ui-carousel/fonts/ui-carousel.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mihnsen/ui-carousel/2fea2a6e7e7b9d98434f49a420e261490ec87627/src/ui-carousel/fonts/ui-carousel.eot
--------------------------------------------------------------------------------
/src/ui-carousel/fonts/ui-carousel.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/src/ui-carousel/fonts/ui-carousel.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mihnsen/ui-carousel/2fea2a6e7e7b9d98434f49a420e261490ec87627/src/ui-carousel/fonts/ui-carousel.ttf
--------------------------------------------------------------------------------
/src/ui-carousel/fonts/ui-carousel.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mihnsen/ui-carousel/2fea2a6e7e7b9d98434f49a420e261490ec87627/src/ui-carousel/fonts/ui-carousel.woff
--------------------------------------------------------------------------------
/src/ui-carousel/providers/carousel.provider.js:
--------------------------------------------------------------------------------
1 | angular.module('ui.carousel.providers').provider('Carousel', function() {
2 | this.options = {
3 | // Init like Slick carousel
4 | // XXX Should be revised
5 | arrows: true,
6 | autoplay: false,
7 | autoplaySpeed: 3000,
8 | cssEase: 'ease',
9 | dots: false,
10 |
11 | easing: 'linear',
12 | fade: false,
13 | infinite: true,
14 | initialSlide: 0,
15 |
16 | slidesToShow: 1,
17 | slidesToScroll: 1,
18 | speed: 500,
19 |
20 | visiblePrev: false,
21 | visibleNext: false,
22 |
23 | // Not available right now
24 | draggable: true,
25 |
26 | lazyLoad: 'ondemand',
27 |
28 | swipe: true,
29 | swipeToSlide: false,
30 | touchMove: true,
31 |
32 | vertical: false,
33 | verticalSwiping: false
34 | };
35 | this.$get = [() => {
36 | return {
37 | setOptions: options => {
38 | this.options = angular.extend(this.options, options);
39 | },
40 | getOptions: () => {
41 | return this.options;
42 | }
43 | };
44 | }];
45 | });
46 |
--------------------------------------------------------------------------------
/src/ui-carousel/scss/_fonts.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @font-face {
4 | font-family: "ui-carousel";
5 | src:url("fonts/ui-carousel.eot");
6 | src:url("fonts/ui-carousel.eot?#iefix") format("embedded-opentype"),
7 | url("fonts/ui-carousel.woff") format("woff"),
8 | url("fonts/ui-carousel.ttf") format("truetype"),
9 | url("fonts/ui-carousel.svg#ui-carousel") format("svg");
10 | font-weight: normal;
11 | font-style: normal;
12 |
13 | }
14 |
15 | [data-icon]:before {
16 | font-family: "ui-carousel" !important;
17 | content: attr(data-icon);
18 | font-style: normal !important;
19 | font-weight: normal !important;
20 | font-variant: normal !important;
21 | text-transform: none !important;
22 | speak: none;
23 | line-height: 1;
24 | -webkit-font-smoothing: antialiased;
25 | -moz-osx-font-smoothing: grayscale;
26 | }
27 |
28 | [class^="ui-icon-"]:before,
29 | [class*=" ui-icon-"]:before {
30 | font-family: "ui-carousel" !important;
31 | font-style: normal !important;
32 | font-weight: normal !important;
33 | font-variant: normal !important;
34 | text-transform: none !important;
35 | speak: none;
36 | line-height: 1;
37 | -webkit-font-smoothing: antialiased;
38 | -moz-osx-font-smoothing: grayscale;
39 | }
40 |
41 | .ui-icon-prev:before {
42 | content: "\61";
43 | }
44 | .ui-icon-next:before {
45 | content: "\62";
46 | }
47 | .ui-icon-dot:before {
48 | content: "\63";
49 | }
50 |
--------------------------------------------------------------------------------
/src/ui-carousel/scss/base.scss:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/ui-carousel/scss/carousel.scss:
--------------------------------------------------------------------------------
1 | .ui-carousel {
2 | display: block;
3 | margin-bottom: 30px;
4 |
5 | .carousel-wrapper {
6 | position: relative;
7 | }
8 | .track-wrapper {
9 | position: relative;
10 | display: block;
11 | overflow: hidden;
12 | margin: 0;
13 | padding: 0;
14 | }
15 | .track {
16 | position: relative;
17 | display: block;
18 | float: left;
19 | }
20 | .slide {
21 | float: left;
22 | height: 100%;
23 | min-height: 1px;
24 | }
25 | .carousel-btn {
26 | position: absolute;
27 | z-index: 10;
28 | @extend .v-middle;
29 | background-color: transparent;
30 | outline: none;
31 | border: none;
32 | font-size: 20px;
33 | opacity: .75;
34 |
35 | &:hover {
36 | opacity: 1;
37 | }
38 | }
39 |
40 | .carousel-prev {
41 | .carousel-btn {
42 | left: -25px;
43 | }
44 | }
45 | .carousel-next {
46 | .carousel-btn {
47 | right: -25px;
48 | }
49 | }
50 | .carousel-disable {
51 | opacity: 0.5;
52 |
53 | .carousel-btn {
54 | &:hover {
55 | opacity: .75;
56 | }
57 | }
58 | }
59 | }
60 |
61 | .carousel-dots {
62 | position: absolute;
63 | bottom: -30px;
64 | display: block;
65 | width: 100%;
66 | padding: 0;
67 | margin: 0;
68 | list-style: none;
69 | text-align: center;
70 |
71 | li {
72 | position: relative;
73 | display: inline-block;
74 | width: 15px;
75 | height: 15px;
76 | margin: 0 5px;
77 | padding: 0;
78 | cursor: pointer;
79 |
80 | button {
81 | font-size: 0;
82 | line-height: 0;
83 | display: block;
84 | width: 15px;
85 | height: 15px;
86 | padding: 5px;
87 | cursor: pointer;
88 | color: transparent;
89 | border: 0;
90 | outline: none;
91 | background: transparent;
92 |
93 | &:before {
94 | font-family: ui-carousel;
95 | font-size: 9px;
96 | line-height: 15px;
97 | position: absolute;
98 | top: 0px;
99 | left: 0px;
100 | width: 15px;
101 | height: 15px;
102 | content: "\63";
103 | text-align: center;
104 | opacity: 0.25;
105 | color: black;
106 | -webkit-font-smoothing: antialiased;
107 | }
108 | }
109 |
110 | &.carousel-active {
111 | button {
112 | &:before {
113 | opacity: .75;
114 | }
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/ui-carousel/scss/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin transition-transform($duration: 200ms, $easing: linear) {
2 | -webkit-transition: -webkit-transform $duration $easing;
3 | -moz-transition: -moz-transform $duration $easing;
4 | transition: transform $duration $easing;
5 | }
6 | @mixin transform($p...) {
7 | -webkit-transform: $p;
8 | -moz-transform: $p;
9 | transform: $p;
10 | }
11 |
12 | @mixin transition-multi($value...) {
13 | -webkit-transition: $value;
14 | -moz-transition: $value;
15 | -ms-transition: $value;
16 | -o-transition: $value;
17 | transition: $value;
18 | }
19 |
20 | @mixin translate($x, $y) {
21 | -webkit-transform: translate($x, $y);
22 | -ms-transform: translate($x, $y); // IE9 only
23 | -o-transform: translate($x, $y);
24 | transform: translate($x, $y);
25 | }
26 | @mixin transition($transition...) {
27 | -webkit-transition: $transition;
28 | -o-transition: $transition;
29 | transition: $transition;
30 | }
31 |
32 | // Position
33 | .v-middle {
34 | display: block;
35 | position: absolute;
36 | top: 50%;
37 | @include translate(0, -50%);
38 | }
39 |
--------------------------------------------------------------------------------
/src/ui-carousel/scss/ui-carousel.scss:
--------------------------------------------------------------------------------
1 | @import 'variables';
2 | @import 'mixin';
3 | @import 'fonts';
4 | @import 'base';
5 | @import 'carousel';
6 |
--------------------------------------------------------------------------------
/src/ui-carousel/scss/variables.scss:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/ui-carousel/templates/carousel.template.pug:
--------------------------------------------------------------------------------
1 | .carousel-wrapper(ng-show="ctrl.isCarouselReady")
2 | .track-wrapper
3 | .track(ng-style="ctrl.trackStyle")
4 | .slide(
5 | ng-repeat="item in ctrl.slidesInTrack track by $index",
6 | ng-style="ctrl.getSlideStyle($index)",
7 | )
8 | .carousel-item
9 |
10 | .carousel-prev(
11 | ng-if="!ctrl.disableArrow",
12 | ng-show="ctrl.isVisiblePrev && ctrl.options.arrows",
13 | ng-class="{'carousel-disable': !ctrl.isClickablePrev}",
14 | ng-click="ctrl.prev()"
15 | )
16 | button.carousel-btn
17 | i.ui-icon-prev
18 | .carousel-next(
19 | ng-if="!ctrl.disableArrow",
20 | ng-show="ctrl.isVisibleNext && ctrl.options.arrows",
21 | ng-class="{'carousel-disable': !ctrl.isClickableNext}",
22 | ng-click="ctrl.next()"
23 | )
24 | button.carousel-btn
25 | i.ui-icon-next
26 | ul.carousel-dots(ng-show="ctrl.isVisibleDots && ctrl.options.dots")
27 | li(
28 | ng-repeat="dot in ctrl.getDots()",
29 | ng-class="{ 'carousel-active': dot == ctrl.currentSlide/ctrl.options.slidesToScroll }",
30 | ng-click="ctrl.movePage(dot)"
31 | )
32 | button {{ dot }}
33 |
--------------------------------------------------------------------------------
/src/ui-carousel/uiCarousel.module.js:
--------------------------------------------------------------------------------
1 | (function (angular) {
2 | // Create all modules and define dependencies to make sure they exist
3 | // and are loaded in the correct order to satisfy dependency injection
4 | // before all nested files are concatenated by Gulp
5 |
6 | // Config
7 | angular.module('ui.carousel.config', [])
8 | .value('ui.carousel.config', {
9 | debug: true
10 | });
11 |
12 | // Modules
13 | angular.module('ui.carousel.providers', []);
14 | angular.module('ui.carousel.controllers', []);
15 | angular.module('ui.carousel.directives', []);
16 | angular.module('ui.carousel', [
17 | 'ui.carousel.config',
18 | 'ui.carousel.directives',
19 | 'ui.carousel.controllers',
20 | 'ui.carousel.providers'
21 | ]);
22 | })(angular);
23 |
--------------------------------------------------------------------------------
/test/unit/ui-carousel/configs/test.utils.js:
--------------------------------------------------------------------------------
1 | var TestUtil = {
2 | compile: function(html, scope) {
3 | var container;
4 |
5 | inject(function($compile, $rootScope) {
6 | if (!scope) {
7 | scope = $rootScope.$new();
8 | } else if (scope && !scope.$new) {
9 | scope = angular.extend($rootScope.$new(), scope);
10 | }
11 |
12 | const el = angular.element(html);
13 |
14 | container = $compile(el)(scope);
15 | $rootScope.$apply();
16 | $rootScope.$digest();
17 | });
18 |
19 | return container;
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/test/unit/ui-carousel/controllers/carousel.controller.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('ui.carousel.controller.CarouselController', function() {
4 | let $scope;
5 | let $rootScope;
6 | let $element;
7 | let $timeout;
8 | let $q;
9 | let CarouselCtrl;
10 | let Carousel;
11 |
12 | beforeEach(angular.mock.module('ui.carousel.controllers', 'ui.carousel.providers'));
13 |
14 | beforeEach(inject((_$rootScope_, $controller, _$timeout_, _$compile_, _$q_, _Carousel_) => {
15 | $scope = _$rootScope_.$new();
16 | $rootScope = _$rootScope_;
17 | $timeout = _$timeout_;
18 | $q = _$q_;
19 |
20 | Carousel = _Carousel_;
21 | $element = _$compile_('')($scope);
22 |
23 | CarouselCtrl = $controller('CarouselController', {
24 | $scope,
25 | $element,
26 | $timeout,
27 | $q,
28 | Carousel
29 | }, {
30 | show: 1,
31 | scroll: 1,
32 | autoplay: true
33 | });
34 | }));
35 |
36 | describe('$onInit()', () => {
37 | beforeEach(() => {
38 | spyOn(CarouselCtrl, 'initOptions');
39 | spyOn(CarouselCtrl, 'initRanges');
40 | spyOn(CarouselCtrl, 'setProps');
41 | spyOn(CarouselCtrl, 'setupInfinite');
42 | });
43 |
44 | it('should be init sequence correctly', () => {
45 | CarouselCtrl.$onInit();
46 |
47 | expect(CarouselCtrl.initOptions).toHaveBeenCalled();
48 | expect(CarouselCtrl.initRanges).toHaveBeenCalled();
49 | expect(CarouselCtrl.setProps).toHaveBeenCalled();
50 | expect(CarouselCtrl.setupInfinite).toHaveBeenCalled();
51 | });
52 | });
53 |
54 | describe('initOptions', () => {
55 | beforeEach(() => {
56 | spyOn(Carousel, 'getOptions');
57 | });
58 |
59 | it('should get options from providers, config', () => {
60 | CarouselCtrl.initOptions();
61 | expect(Carousel.getOptions).toHaveBeenCalled();
62 | });
63 |
64 | it('should get config from directive', () => {
65 | CarouselCtrl.autoplay = true;
66 | CarouselCtrl.fade = false;
67 | CarouselCtrl.show = 4;
68 | CarouselCtrl.scroll = 3;
69 | CarouselCtrl.initialSlide = 10;
70 | CarouselCtrl.initOptions();
71 |
72 | expect(CarouselCtrl.options.initialSlide).toEqual(10);
73 | expect(CarouselCtrl.options.fade).toBe(false);
74 | expect(CarouselCtrl.options.autoplay).toBe(true);
75 | expect(CarouselCtrl.options.slidesToShow).toEqual(4);
76 | expect(CarouselCtrl.options.slidesToScroll).toEqual(3);
77 | });
78 |
79 | it('should set slides to show and scroll to be 1 when fade = true', () => {
80 | CarouselCtrl.fade = true;
81 | CarouselCtrl.show = 4;
82 | CarouselCtrl.scroll = 3;
83 | CarouselCtrl.initOptions();
84 |
85 | expect(CarouselCtrl.options.slidesToShow).toEqual(1);
86 | expect(CarouselCtrl.options.slidesToScroll).toEqual(1);
87 | });
88 | });
89 |
90 | describe('initRanges()', () => {
91 | beforeEach(() => {
92 | CarouselCtrl.$onInit();
93 | });
94 |
95 | it('should init variables, slides correctly', () => {
96 | CarouselCtrl.slides = [1, 2, 3, 4, 5, 6];
97 | CarouselCtrl.initRanges();
98 |
99 | expect(CarouselCtrl.isCarouselReady).toBe(false);
100 | expect(CarouselCtrl.isTrackMoving).toBe(false);
101 | expect(CarouselCtrl.track).toBeDefined();
102 | expect(CarouselCtrl.currentSlide).toBeDefined();
103 | expect(CarouselCtrl.trackStyle).toBeDefined();
104 | expect(CarouselCtrl.slideStyle).toBeDefined();
105 | expect(CarouselCtrl.isVisibleDots).toBeDefined();
106 | expect(CarouselCtrl.isVisibleNext).toBeDefined();
107 | expect(CarouselCtrl.isVisiblePrev).toBeDefined();
108 | expect(CarouselCtrl.animType).toBeDefined();
109 | expect(CarouselCtrl.transformType).toBeDefined();
110 | expect(CarouselCtrl.transitionType).toBeDefined();
111 | });
112 | });
113 |
114 | describe('initUI()', () => {
115 | beforeEach(() => {
116 | spyOn(CarouselCtrl, 'initTrack');
117 | spyOn(CarouselCtrl, 'updateItemStyle');
118 |
119 | CarouselCtrl.$onInit();
120 | });
121 |
122 | it('should calculate track width', () => {
123 | CarouselCtrl.initUI();
124 | $timeout.flush();
125 |
126 | expect(CarouselCtrl.initTrack).toHaveBeenCalled();
127 | expect(CarouselCtrl.updateItemStyle).toHaveBeenCalled();
128 | });
129 | });
130 |
131 | describe('initTrack()', () => {
132 | beforeEach(() => {
133 | CarouselCtrl.$onInit();
134 | });
135 |
136 | it('should calculate track width and prevent transition when fade = true', () => {
137 | CarouselCtrl.slidesInTrack = [2, 0, 1, 2, 0];
138 | CarouselCtrl.width = 1;
139 | CarouselCtrl.options.fade = true;
140 | CarouselCtrl.options.slidesToShow = 2;
141 | CarouselCtrl.initTrack();
142 |
143 | expect(CarouselCtrl.trackStyle.width).toEqual('2.5px');
144 |
145 | $scope.$apply();
146 | expect(CarouselCtrl.isCarouselReady).toBe(true);
147 | expect(CarouselCtrl.trackStyle).toEqual({
148 | 'width': '2.5px',
149 | 'webkitTransition': '-webkit-transform 0ms ease',
150 | });
151 | });
152 | it('should calculate track width and init track transition', () => {
153 | CarouselCtrl.slidesInTrack = [2, 0, 1, 2, 0];
154 | CarouselCtrl.width = 1;
155 | CarouselCtrl.options.fade = false;
156 | CarouselCtrl.options.speed = 5000;
157 | CarouselCtrl.options.slidesToShow = 2;
158 | CarouselCtrl.initTrack();
159 |
160 | expect(CarouselCtrl.trackStyle.width).toEqual('2.5px');
161 |
162 | $scope.$apply();
163 | expect(CarouselCtrl.isCarouselReady).toBe(true);
164 | expect(CarouselCtrl.trackStyle).toEqual({
165 | 'width': '2.5px',
166 | 'webkitTransition': '-webkit-transform 5000ms ease'
167 | });
168 | });
169 | });
170 |
171 | describe('next()', () => {
172 | /*
173 | * - 6 total, 1 show, 1 scroll, current 0 => next index = 1
174 | * - 9 total, 3 show, 3 scroll, current 1 => next index = 3
175 | * - 9 total, 3 show, 3 scroll, current 3 => next index = 6
176 | * - 9 total, 3 show, 3 scroll, current 8 => next index = 3
177 | * - 8 total, 4 show, 3 scroll, current 1 => next index = 4
178 | */
179 | beforeEach(() => {
180 | CarouselCtrl.slideHandler = jasmine.createSpy('slideHandler').and.callFake(() => {
181 | return $q.resolve(true);
182 | });
183 | CarouselCtrl.$onInit();
184 | CarouselCtrl.isClickableNext = true;
185 | });
186 |
187 | it('should works well with normal case', () => {
188 | CarouselCtrl.slides = [...Array(5)];
189 | CarouselCtrl.options.slidesToScroll = 1;
190 | CarouselCtrl.currentSlide = 0;
191 | CarouselCtrl.next();
192 |
193 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(1);
194 | });
195 |
196 | it('should works well with infinite case and sync to page index first', () => {
197 | CarouselCtrl.slides = [...Array(9)];
198 | CarouselCtrl.options.slidesToScroll = 3;
199 | CarouselCtrl.currentSlide = 1;
200 | CarouselCtrl.next();
201 |
202 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(3);
203 | });
204 |
205 | it('should works well with infinite case and scroll to next page', () => {
206 | CarouselCtrl.slides = [...Array(9)];
207 | CarouselCtrl.options.slidesToScroll = 3;
208 | CarouselCtrl.currentSlide = 3;
209 | CarouselCtrl.next();
210 |
211 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(6);
212 | });
213 |
214 | it('should works well with infinite case and scroll to next page', () => {
215 | CarouselCtrl.slides = [...Array(8)];
216 | CarouselCtrl.options.slidesToScroll = 3;
217 | CarouselCtrl.currentSlide = 1;
218 | CarouselCtrl.next();
219 |
220 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(4);
221 | });
222 | });
223 |
224 | describe('prev()', () => {
225 | // Same with next()
226 | beforeEach(() => {
227 | CarouselCtrl.slideHandler = jasmine.createSpy('slideHandler').and.callFake(() => {
228 | return $q.resolve(true);
229 | });
230 | CarouselCtrl.$onInit();
231 | CarouselCtrl.isClickablePrev = true;
232 | });
233 |
234 | it('should works well with infinite case and sync to page index first', () => {
235 | CarouselCtrl.slides = [...Array(9)];
236 | CarouselCtrl.options.slidesToShow = 3;
237 | CarouselCtrl.options.slidesToScroll = 3;
238 | CarouselCtrl.currentSlide = 1;
239 | CarouselCtrl.prev();
240 |
241 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(0);
242 | });
243 | });
244 |
245 | describe('movePage()', () => {
246 | beforeEach(() => {
247 | CarouselCtrl.slideHandler = jasmine.createSpy('slideHandler').and.callFake(() => {
248 | return $q.resolve(true);
249 | });
250 | CarouselCtrl.$onInit();
251 | });
252 |
253 | it('should be work well', () => {
254 | CarouselCtrl.options.slidesToScroll = 1;
255 | CarouselCtrl.currentSlide = 5;
256 | expect(CarouselCtrl.currentSlide).toEqual(5);
257 |
258 | CarouselCtrl.movePage(3);
259 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(3);
260 | });
261 |
262 | it('should be work with multiple slides to scroll', () => {
263 | CarouselCtrl.options.slidesToScroll = 3;
264 | CarouselCtrl.options.currentSlide = 5;
265 | CarouselCtrl.options.fade = false;
266 |
267 | CarouselCtrl.movePage(3);
268 | expect(CarouselCtrl.slideHandler).toHaveBeenCalledWith(9);
269 | });
270 | });
271 |
272 | describe('slideHandler()', () => {
273 | beforeEach(() => {
274 | spyOn(CarouselCtrl, 'autoplayTrack');
275 | spyOn(CarouselCtrl, 'correctTrack');
276 | CarouselCtrl.slides = [...Array(6)];
277 | CarouselCtrl.$onInit();
278 | });
279 |
280 | it('should reject if track is moving', (done) => {
281 | CarouselCtrl.isTrackMoving = true;
282 | let expectMsg = '';
283 | CarouselCtrl
284 | .slideHandler(1)
285 | .catch(msg => expectMsg = msg)
286 | .finally(done);
287 |
288 | $scope.$apply();
289 | expect(expectMsg).toEqual('Track is moving');
290 | });
291 |
292 | it('should reject when length of slides is lower than slides to show', (done) => {
293 | CarouselCtrl.options.slidesToShow = 7;
294 | let expectMsg = '';
295 | CarouselCtrl
296 | .slideHandler(1)
297 | .catch(msg => expectMsg = msg)
298 | .finally(done);
299 |
300 | $scope.$apply();
301 | expect(expectMsg).toEqual('Length of slides smaller than slides to show');
302 | });
303 |
304 | it('should move to correct index when fade = true', (done) => {
305 | CarouselCtrl.fade = true;
306 | CarouselCtrl.initOptions();
307 | let expectMsg = '';
308 | CarouselCtrl
309 | .slideHandler(6)
310 | .then(msg => expectMsg = msg)
311 | .finally(done);
312 |
313 | $scope.$apply();
314 | expect(expectMsg).toEqual('Handler fade');
315 | expect(CarouselCtrl.currentSlide).toEqual(0);
316 | });
317 |
318 | it('should move track to correct position', (done) => {
319 | // XXX
320 | // see http://paulsalaets.com/posts/q-promise-chains-need-digest-cycle-to-go
321 | // Should be revised
322 | spyOn(CarouselCtrl, 'moveTrack').and.callFake(() => {
323 | return $q((resolve, reject) => {
324 | resolve();
325 | });
326 | });
327 |
328 | CarouselCtrl.fade = false;
329 | CarouselCtrl.infinite = true;
330 | CarouselCtrl.$onInit();
331 | CarouselCtrl.updateItemStyle();
332 |
333 | CarouselCtrl.slideHandler(6).finally(done);
334 |
335 | $scope.$apply();
336 | //expect(CarouselCtrl.isTrackMoving).toBe(false);
337 | expect(CarouselCtrl.currentSlide).toBe(0);
338 | expect(CarouselCtrl.autoplayTrack).toHaveBeenCalled();
339 | expect(CarouselCtrl.correctTrack).toHaveBeenCalled();
340 | expect(CarouselCtrl.moveTrack).toHaveBeenCalledWith(-7);
341 | expect(CarouselCtrl.currentSlide).toEqual(0);
342 | });
343 | });
344 |
345 | describe('moveTrack()', () => {
346 | beforeEach(() => {
347 | CarouselCtrl.$onInit();
348 | });
349 |
350 | it('should move track and resolve after speed timeout', (done) => {
351 | CarouselCtrl
352 | .moveTrack(100)
353 | .then(msg => {
354 | expect(msg).toEqual('Track moved');
355 | })
356 | .finally(done);
357 |
358 | $timeout.flush(CarouselCtrl.options.speed);
359 | });
360 |
361 | it('should update track style', () => {
362 | CarouselCtrl.moveTrack(100);
363 |
364 | expect(CarouselCtrl.trackStyle).toEqual(jasmine.objectContaining({
365 | webkitTransform: "translate3d(100px, 0px, 0px)"
366 | }));
367 | });
368 | });
369 |
370 | describe('correctTrack()', () => {
371 | beforeEach(() => {
372 | CarouselCtrl.slides = [...Array(6)];
373 | CarouselCtrl.$onInit();
374 | });
375 |
376 | it('should be working only infinite mode', () => {
377 | CarouselCtrl.isTrackMoving = false;
378 | CarouselCtrl.options.infinite = false;
379 |
380 | CarouselCtrl.correctTrack();
381 | expect(CarouselCtrl.isTrackMoving).toBe(false);
382 | expect(CarouselCtrl.trackStyle.webkitTransform).not.toBeDefined();
383 | });
384 |
385 | it('should move to correct track position and revert track style', () => {
386 | CarouselCtrl.currentSlide = 1;
387 | CarouselCtrl.options.speed = 200;
388 | CarouselCtrl.options.cssEase = 'linear';
389 |
390 | CarouselCtrl.correctTrack();
391 | expect(CarouselCtrl.isTrackMoving).toBe(true);
392 |
393 | $scope.$apply();
394 | expect(CarouselCtrl.trackStyle).toEqual(jasmine.objectContaining({
395 | webkitTransition: '-webkit-transform 0ms linear',
396 | }));
397 |
398 | $timeout.flush(200);
399 | expect(CarouselCtrl.isTrackMoving).toBe(false);
400 | expect(CarouselCtrl.trackStyle).toEqual(jasmine.objectContaining({
401 | webkitTransition: '-webkit-transform 200ms linear',
402 | }));
403 | });
404 | });
405 |
406 | describe('autoplayTrack()', () => {
407 | beforeEach(() => {
408 | spyOn(CarouselCtrl, 'next');
409 | CarouselCtrl.slides = [...Array(6)];
410 | CarouselCtrl.$onInit();
411 | });
412 |
413 | it('should autoplay when enabled in options', () => {
414 | CarouselCtrl.options.autoplay = false;
415 | CarouselCtrl.autoplayTrack();
416 | expect(CarouselCtrl.timeout).not.toBeDefined();
417 | });
418 |
419 | it('should autoplay', () => {
420 | CarouselCtrl.options.autoplay = true;
421 | CarouselCtrl.options.autoplaySpeed = 3000;
422 | CarouselCtrl.next.calls.reset();
423 | CarouselCtrl.autoplayTrack();
424 |
425 | expect(CarouselCtrl.timeout).toBeDefined();
426 | $timeout.flush(3000);
427 | expect(CarouselCtrl.next.calls.count()).toEqual(1);
428 | });
429 | });
430 |
431 | describe('getSlideStyle', () => {
432 | beforeEach(() => {
433 | CarouselCtrl.slides = [...Array(6)];
434 | CarouselCtrl.$onInit();
435 | });
436 |
437 | it('should be get correct style', () => {
438 | CarouselCtrl.updateItemStyle();
439 |
440 | CarouselCtrl.options.fade = false;
441 | expect(CarouselCtrl.getSlideStyle(1000)).toEqual({
442 | 'width': '1px'
443 | });
444 |
445 | CarouselCtrl.options.fade = true;
446 | expect(CarouselCtrl.getSlideStyle(5)).toEqual({
447 | 'width': '1px',
448 | 'position': 'relative',
449 | 'top': '0px',
450 | 'z-index': 9,
451 | 'left': '-5px',
452 | 'opacity': 0
453 | });
454 | });
455 |
456 | it('should be get correct style', () => {
457 | CarouselCtrl.width = 100;
458 | CarouselCtrl.currentSlide = 5;
459 | CarouselCtrl.options.slidesToShow = 2;
460 |
461 | CarouselCtrl.updateItemStyle();
462 | CarouselCtrl.options.fade = false;
463 | expect(CarouselCtrl.slideStyle).toEqual({
464 | 'width': '50px'
465 | });
466 |
467 | CarouselCtrl.options.fade = true;
468 | expect(CarouselCtrl.getSlideStyle(5)).toEqual({
469 | 'width': '50px',
470 | 'position': 'relative',
471 | 'top': '0px',
472 | 'z-index': 10,
473 | 'left': '-250px',
474 | 'opacity': 1,
475 | 'transition': 'opacity 250ms linear'
476 | });
477 | });
478 | });
479 |
480 | //TODO write more tests case for carousel
481 | });
482 |
--------------------------------------------------------------------------------
/test/unit/ui-carousel/directives/carousel.directive.js:
--------------------------------------------------------------------------------
1 | describe('ui-carousel', () => {
2 | let $rootScope;
3 | let $compile;
4 | let scope;
5 |
6 | beforeEach(module('ui.carousel.directives'));
7 |
8 | // inject services
9 | beforeEach(inject((_$rootScope_, _$compile_) => {
10 | $rootScope = _$rootScope_;
11 | $compile = _$compile_;
12 |
13 | scope = $rootScope.$new();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/test/unit/ui-carousel/providers/carousel.provider.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('ui.carousel.providers.Carousel', function() {
4 | var Carousel;
5 |
6 | // load the module
7 | beforeEach(angular.mock.module('ui.carousel.providers', function($provide) {
8 | }));
9 |
10 | beforeEach(inject(function(_Carousel_) {
11 | Carousel = _Carousel_;
12 | }));
13 |
14 | it('should be defined', function() {
15 | expect(Carousel).toBeDefined();
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/test/unit/ui-carousel/uiCarouselSpec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('ui.carousel', () => {
4 | var module;
5 | var dependencies = [];
6 |
7 | var hasModule = (module) => {
8 | return dependencies.indexOf(module) >= 0;
9 | };
10 |
11 | beforeEach(() => {
12 | // Get module
13 | module = angular.module('ui.carousel');
14 | dependencies = module.requires;
15 | });
16 |
17 | it('should load config module', () => {
18 | expect(hasModule('ui.carousel.config')).toBeDefined();
19 | });
20 | });
21 |
--------------------------------------------------------------------------------