├── demo
├── favicon.ico
├── images
│ ├── cow1.jpg
│ ├── cow2.jpg
│ ├── cow3.jpg
│ ├── face1.jpg
│ ├── face2.jpg
│ ├── face3.jpg
│ └── face4.jpg
├── styles.css
├── prism.js
└── index.html
├── .gitignore
├── .travis.yml
├── .eslintrc
├── src
├── transform.js
├── carousel.css
└── carousel.js
├── LICENSE
├── rollup.config.js
├── package.json
├── README.md
├── dist
├── carousel.min.js
├── carousel.es6.js
├── carousel.cjs.js
└── carousel.js
└── test
└── carousel.spec.js
/demo/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/favicon.ico
--------------------------------------------------------------------------------
/demo/images/cow1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/cow1.jpg
--------------------------------------------------------------------------------
/demo/images/cow2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/cow2.jpg
--------------------------------------------------------------------------------
/demo/images/cow3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/cow3.jpg
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | .DS_Store
3 | /node_modules
4 | npm-debug.log
5 | .idea/
6 | *sublime*
7 |
8 |
--------------------------------------------------------------------------------
/demo/images/face1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/face1.jpg
--------------------------------------------------------------------------------
/demo/images/face2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/face2.jpg
--------------------------------------------------------------------------------
/demo/images/face3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/face3.jpg
--------------------------------------------------------------------------------
/demo/images/face4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hugeinc/component-carousel/HEAD/demo/images/face4.jpg
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "6.0"
5 | cache:
6 | directories:
7 | - node_modules
8 | script:
9 | - npm run travis
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 6,
4 | "sourceType": "module"
5 | },
6 | "root": true,
7 | "globals": {
8 | "window": true,
9 | "document": true,
10 | "module": true
11 | },
12 | "rules": {
13 | "semi": ["error", "always"],
14 | "space-before-function-paren": ["error", "never"],
15 | "no-multiple-empty-lines": ["error", {"max": 3}],
16 | "arrow-parens": 0
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/transform.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Feature detection: CSS transforms
3 | * @type {Boolean}
4 | */
5 |
6 | const dummy = document.createElement('div');
7 | const transform = ['transform', 'webkitTransform', 'MozTransform', 'OTransform', 'msTransform'].find((t) => {
8 | // return (document.body.style[t] !== undefined); // if DOM is not yet ready, let's do:
9 | return (dummy.style[t] !== undefined);
10 | });
11 |
12 | export default transform;
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2013, 2017 wes hatch
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/carousel.css:
--------------------------------------------------------------------------------
1 | /*
2 | * flexicarousel
3 | * https://github.com/apathetic/flexicarousel-2
4 | *
5 | * Copyright (c) 2014, 2017 Wes Hatch
6 | * Licensed under the MIT license.
7 | */
8 |
9 |
10 | /* -------------------------------------
11 | CAROUSEL STYLES
12 | ------------------------------------- */
13 |
14 | .carousel .animate {
15 | -webkit-transition: all 0.4s ease;
16 | -moz-transition: all 0.4s ease;
17 | -o-transition: all 0.4s ease;
18 | transition: all 0.4s ease !important;
19 | }
20 |
21 | .carousel .wrap {
22 | white-space: nowrap; /* fallback */
23 | width: 100%;
24 | display: -webkit-box;
25 | display: -webkit-flex;
26 | display: -moz-box;
27 | display: -ms-flexbox;
28 | display: flex;
29 | -webkit-box-wrap: nowrap;
30 | -ms-flexbox-wrap: nowrap;
31 | -moz-box-wrap: nowrap;
32 | flex-wrap: nowrap;
33 | -webkit-user-select: none;
34 | -moz-user-select: none;
35 | -ms-user-select: none;
36 | user-select: none;
37 | padding: 0;
38 | }
39 |
40 | .carousel .wrap > li {
41 | display: inline-block; /* fallback */
42 | vertical-align: top; /* fallback */
43 | position: relative; /* fallback */
44 | width: 100%; /* fallback */
45 | cursor: move;
46 | -webkit-box-flex: 1 0 100%;
47 | -webkit-flex: 1 0 100%;
48 | -ms-flex: 1 0 100%;
49 | flex: 1 0 100%;
50 | padding: 0;
51 | }
52 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import buble from 'rollup-plugin-buble';
2 | import uglify from 'rollup-plugin-uglify';
3 | import { minify } from 'uglify-es';
4 | import * as fs from 'fs';
5 |
6 | const license = fs.readFileSync('LICENSE', 'utf8');
7 |
8 |
9 | export default [{
10 | input: 'src/carousel.js',
11 | output: [
12 | {
13 | file: 'dist/carousel.cjs.js',
14 | format: 'cjs',
15 | banner: '/*!\n' + license + '*/'
16 | }, {
17 | file: 'dist/carousel.es6.js',
18 | format: 'es',
19 | banner: '/*!\n' + license + '*/'
20 | }, {
21 | file: 'dist/carousel.js',
22 | format: 'iife',
23 | name: 'Carousel',
24 | banner: '/*!\n' + license + '*/'
25 | },
26 | ],
27 | plugins: [
28 | buble()
29 | ]
30 | }, {
31 | input: 'src/carousel.js',
32 | output: [
33 | {
34 | file: 'dist/carousel.min.js',
35 | format: 'iife',
36 | name: 'Carousel',
37 | banner: '/*!\n' + license + '*/'
38 | }
39 | ],
40 | plugins: [
41 | buble(),
42 | uglify({
43 | output: {
44 | comments: function(node, comment) {
45 | var text = comment.value;
46 | var type = comment.type;
47 | if (type == "comment2") {
48 | return /^!/i.test(text);
49 | }
50 | }
51 | }
52 | }, minify)
53 | ]
54 | }];
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@apatheticwes/flexicarousel",
3 | "author": "wes hatch",
4 | "license": "MIT",
5 | "version": "0.8.7",
6 | "description": "A micro, responsive, touch-enabled carousel.",
7 | "main": "./dist/carousel.cjs.js",
8 | "browser": "./dist/carousel.js",
9 | "jsnext:main": "./dist/carousel.es6.js",
10 | "module": "./dist/carousel.es6.js",
11 | "repository": {
12 | "type": "git",
13 | "url": "git@github.com:hugeinc/component-carousel.git"
14 | },
15 | "keywords": [
16 | "carousel"
17 | ],
18 | "babel": {
19 | "presets": [
20 | "env"
21 | ]
22 | },
23 | "scripts": {
24 | "start": "http-server ./ -p 8080 -d",
25 | "clean": "rm -f dist/*.js*",
26 | "build": "npm run clean && npm run lint && rollup -c",
27 | "lint": "eslint source/js/*.js",
28 | "test": "tape -r babel-register test/*.js",
29 | "prepublish": "npm run build && npm test",
30 | "preversion": "npm run build && npm test",
31 | "travis": "npm run lint && npm test"
32 | },
33 | "devDependencies": {
34 | "babel-cli": "^6.26.0",
35 | "babel-preset-env": "^1.6.1",
36 | "eslint": "^3.1.1",
37 | "http-server": "^0.9.0",
38 | "jsdom": "^11.5.1",
39 | "rollup": "^0.50.0",
40 | "rollup-plugin-buble": "^0.16.0",
41 | "rollup-plugin-uglify": "^2.0.1",
42 | "spy": "^1.0.0",
43 | "tape": "^4.6.0",
44 | "uglify-es": "^3.1.3"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/demo/styles.css:
--------------------------------------------------------------------------------
1 | /* -------------------------------------
2 | SAMPLE CAROUSEL STYLES
3 | ------------------------------------- */
4 |
5 | /*
6 | SEE: https://apathetic.github.io/showcase/assets/css/main.min.css
7 | for other demo styles
8 | */
9 |
10 | .carousel nav .next.disabled,
11 | .carousel nav .prev.disabled {
12 | opacity: 0.2;
13 | }
14 |
15 | .carousel img {
16 | pointer-events: none;
17 | width: 100%;
18 | height: auto;
19 | border: 2px solid #fff;
20 | display: block;
21 | }
22 |
23 | .carousel h3 {
24 | position: absolute;
25 | z-index: 10;
26 | color: #fff;
27 | padding: 1em;
28 | }
29 |
30 |
31 | /* TEN */
32 | #ten .wrap {
33 | width: calc(100% + 20px);
34 | margin: -10px;
35 | }
36 | #ten .wrap li {
37 | padding: 10px;
38 | }
39 |
40 | @media(min-width:480px) {
41 | #ten .wrap > li {
42 | -webkit-flex-basis: 100%;
43 | -moz-flex-basis: 100%;
44 | -ms-flex: 1 0 100%;
45 | flex-basis: 100%;
46 | }
47 | }
48 | @media(min-width:800px) {
49 | #ten .wrap > li {
50 | flex-basis: 50%;
51 | }
52 | }
53 | @media(min-width:1120px) {
54 | #ten .wrap li {
55 | flex-basis: 33.3333%;
56 | }
57 | }
58 |
59 | /* BILLION */
60 | #billion {
61 | max-width: 540px;
62 | overflow: hidden;
63 | }
64 | #billion .wrap {
65 | width: 66.666%;
66 | margin: 0px auto;
67 | }
68 |
69 | /* SEVEN */
70 | @media screen and (min-width:480px) {
71 | #seven .wrap > li {
72 | flex-basis: calc(1/3 * 100%); /* 33.3333%; */
73 | }
74 | }
75 | @media screen and (min-width:800px) {
76 | #seven .wrap > li {
77 | flex-basis: 25%;
78 | }
79 | }
80 | @media screen and (min-width:1120px) {
81 | #seven .wrap > li {
82 | flex-basis: 20%;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Carousel
2 | [](https://www.npmjs.com/package/@apatheticwes/flexicarousel)
3 | [](https://raw.githubusercontent.com/apathetic/flexicarousel/master/LICENSE)
4 |
5 | > A carousel that'll use CSS to dynamically adapt its width. Uses transforms for its transitions and is also touch-enabled.
6 |
7 | ## Introduction
8 |
9 | The general idea is that this component should maintain a separation of state and style. That is to say, the Javascript maintains the state of the carousel (which slide, etc), while the CSS should take care of the presentation of this state (ie. transitions between slides, responsive, etc).
10 |
11 | ## Overview
12 |
13 | Features a touch-based interface, simple API, and a very-lightweight footprint. It does the basics well, but that's it. No bloat.
14 | You can swipe to drag a slide yet still use CSS to control how the slide transitions will behave. You can also choose to change slides by
15 | using the exposed API. The carousel works on both desktop and mobile, while only weighing in at 2.5 KB!
16 |
17 | ## Getting Started
18 | There is an ES6 module you may consume however you wish. Alternatively, you can also include the relevant scripts in your web page, and then:
19 |
20 | ```html
21 |
22 |
23 |
24 | - slide 1
25 | - slide 2
26 | - slide 3
27 |
28 |
29 | ```
30 |
31 | ```javascript
32 | // available options
33 | var options = {
34 | onSlide: someFunction,
35 | activeClass: 'active',
36 | slideWrap: 'ul',
37 | slides: 'li',
38 | infinite: true,
39 | display: 1,
40 | disableDragging: false,
41 | initialIndex: 0
42 | };
43 |
44 | var container = document.querySelector('.carousel');
45 | var carousel = new Carousel(container, options);
46 |
47 | ```
48 |
49 | ## Options
50 |
51 | | name | type | default | description |
52 | | --------------- | -------- | --------- | ----------- |
53 | | onSlide | function | undefined | A function to execute on slide. It is passed _to_ and _from_ indices. |
54 | | slideWrap | string | ul | The selector to use when searching for the slides' container. This is used only to bind touch events to, on mobile. |
55 | | slides | string | li | The selector to use when searching for slides within the slideWrap container. |
56 | | activeClass | string | active | Class to use on the active slide. |
57 | | animateClass | string | animate | Class to use on the wrapper when animating. |
58 | | infinite | boolean | true | Enable an infinitely scrolling carousel or not |
59 | | display | integer | 1 | the maximum # of slides to display at a time. If you want to have prev/next slides visible outside those currently displayed, they'd be included here. |
60 | | disableDragging | boolean | false | if you'd like to disable the touch UI for whatever reason |
61 | | initialIndex | integer | 0 | which slide it's going to start on |
62 |
63 | ## Methods
64 |
65 | | method | description |
66 | | --------- | ----------- |
67 | | next() | Advances carousel to the next slide |
68 | | prev() | Move carousel to the previous slide |
69 | | to(i) | Advance carousel to the ith slide |
70 | | destroy() | Destroy carousel and remove all EventListeners |
71 |
72 | ## Demo
73 |
74 | [Hugeinc Carousel](http://hugeinc.github.io/showcase/components/carousel)
75 |
76 | ## Develop
77 |
78 | After cloning the repo:
79 | ```
80 | npm i
81 | npm start
82 | ```
83 |
84 | A server will spin up at ```http://localhost:8080```, where you may play with the various examples. See the "demo" directory.
85 |
86 | ## Support
87 | * IE8+
88 | * Safari / Chrome
89 | * Firefox
90 | * iOS
91 | * Android 4.0+
92 |
93 | ## Release History
94 |
95 | ### 0.6
96 | * updated some css
97 |
98 | ### 0.5
99 | * added destroy()
100 | * added some tests
101 |
102 | ### 0.4
103 | * better dragging response
104 | * fixed click bug when dragging
105 |
106 | ### 0.3
107 | * cleaning up cloning logic
108 | * further optimizations
109 |
110 | ### 0.2
111 | * bug fixes, mostly
112 | * updated slide engine
113 | * more robust dragging on mobile
114 |
115 | ### 0.1
116 | * first release
117 |
--------------------------------------------------------------------------------
/dist/carousel.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | MIT License
3 |
4 | Copyright (c) 2013, 2017 wes hatch
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | var Carousel=function(){"use strict";var t=function(t,i){var s=this;void 0===i&&(i={}),this.handle=t,this.options={animateClass:"animate",activeClass:"active",slideWrap:"ul",slides:"li",infinite:!0,display:1,disableDragging:!1,initialIndex:0},this.current=0,this.slides=[],this.sliding=!1,this.cloned=0,this.active=!0,this.dragging=!1,this.dragThreshold=50,this.deltaX=0,this.isTouch="ontouchend"in document,["transform","webkitTransform","MozTransform","OTransform","msTransform"].forEach(function(t){void 0!==document.body.style[t]&&(s.transform=t)}),this.options=this._assign(this.options,i),this.init()};return t.prototype.init=function(){var t=this;return this.slideWrap=this.handle.querySelector(this.options.slideWrap),this.slides=this.slideWrap.querySelectorAll(this.options.slides),this.numSlides=this.slides.length,this.current=this.options.initialIndex,!this.slideWrap||!this.slides||this.numSlides=this.numSlides){var e=t<0?this.current+this.numSlides:this.current-this.numSlides;this._slide(-(e*this.width-this.deltaX)),this.slideWrap.offsetHeight}t=this._loop(t),this._slide(-t*this.width,i),s.onSlide&&t!==this.current&&s.onSlide.call(this,t,this.current),this._removeClass(this.slides[this.current],s.activeClass),this._addClass(this.slides[t],s.activeClass),this.current=t}},t.prototype._createBindings=function(){var t=this;this._bindings={touchstart:function(i){t._dragStart(i)},touchmove:function(i){t._drag(i)},touchend:function(i){t._dragEnd(i)},touchcancel:function(i){t._dragEnd(i)},mousedown:function(i){t._dragStart(i)},mousemove:function(i){t._drag(i)},mouseup:function(i){t._dragEnd(i)},mouseleave:function(i){t._dragEnd(i)},click:function(i){t._checkDragThreshold(i)},resize:function(i){t._updateView(i)},orientationchange:function(i){t._updateView(i)}}},t.prototype._checkDragThreshold=function(t){this.dragThresholdMet&&t.preventDefault()},t.prototype._dragStart=function(t){var i;if(this.sliding)return!1;i=void 0!==(t=t.originalEvent||t).touches&&t.touches,this.dragThresholdMet=!1,this.dragging=!0,this.startClientX=i?i[0].pageX:t.clientX,this.startClientY=i?i[0].pageY:t.clientY,this.deltaX=0,this.deltaY=0,"IMG"!==t.target.tagName&&"A"!==t.target.tagName||(t.target.draggable=!1)},t.prototype._drag=function(t){var i;this.dragging&&(i=void 0!==(t=t.originalEvent||t).touches&&t.touches,this.deltaX=(i?i[0].pageX:t.clientX)-this.startClientX,this.deltaY=(i?i[0].pageY:t.clientY)-this.startClientY,this._slide(-(this.current*this.width-this.deltaX)),this.dragThresholdMet=Math.abs(this.deltaX)>this.dragThreshold)},t.prototype._dragEnd=function(t){this.dragging&&(this.dragThresholdMet&&(t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()),this.dragging=!1,0!==this.deltaX&&Math.abs(this.deltaX)0?this.prev():this.deltaX<0&&this.next(),this.deltaX=0)},t.prototype._slide=function(t,i){var s=this;t-=this.offset,i&&(this.sliding=!0,this._addClass(this.slideWrap,this.options.animateClass),setTimeout(function(){s.sliding=!1,s.active&&s._removeClass(s.slideWrap,s.options.animateClass)},400)),this.transform?this.slideWrap.style[this.transform]="translate3d("+t+"px, 0, 0)":this.slideWrap.style.left=t+"px"},t.prototype._loop=function(t){return(this.numSlides+t%this.numSlides)%this.numSlides},t.prototype._getDimensions=function(){this.width=this.slides[0].getBoundingClientRect().width,this.offset=this.cloned*this.width},t.prototype._updateView=function(){var t=this;window.innerWidth!==this._viewport&&(this._viewport=window.innerWidth,clearTimeout(this.timer),this.timer=setTimeout(function(){t._getDimensions(),t.go(t.current)},300))},t.prototype._cloneSlides=function(){for(var t,i=this,s=this.options.display,e=Math.max(this.numSlides-s,0),n=Math.min(s,this.numSlides),o=this.numSlides;o>e;o--)(t=i.slides[o-1].cloneNode(!0)).removeAttribute("id"),t.setAttribute("aria-hidden","true"),i._addClass(t,"clone"),i.slideWrap.insertBefore(t,i.slideWrap.firstChild),i.cloned++;for(var r=0;r
10 |
11 |
12 |
19 |
20 | `;
21 | const badTemplate = `
22 |
23 |
24 |
25 |
28 |
29 | `;
30 |
31 | const setup = (opts={}, template = goodTemplate) => {
32 | const dom = new JSDOM(template);
33 | const { window } = dom;
34 | const container = window.document.querySelector('div');
35 |
36 | global.window = window;
37 | global.document = window.document;
38 | carousel = new Carousel(container, opts);
39 | };
40 | const teardown = () => {
41 | carousel.destroy();
42 | // createBindings.reset();
43 | };
44 | // const createBindings = spy(Carousel.prototype._createBindings);
45 |
46 |
47 | /////////////////////////////////////////////////////////////////////////////////////
48 |
49 |
50 | test('Setup and teardown:', function(t) {
51 |
52 | t.test('initializes correctly', function(assert) {
53 | // const createBindings = spy(Carousel.prototype._createBindings); // wrap in spy function
54 | setup();
55 |
56 | assert.equal(typeof carousel, 'object');
57 | assert.equal(carousel.handle.nodeName, 'DIV');
58 | assert.equal(carousel.slideWrap.nodeName, 'UL');
59 | assert.equal(carousel.slides[0].nodeName, 'LI');
60 | assert.equal(carousel.numSlides, 3);
61 | // assert.equal(createBindings.called, true);
62 |
63 | teardown();
64 | assert.end();
65 | });
66 |
67 | t.test('requires at least 2 slides (with default display value)', function(assert) {
68 | setup({}, badTemplate);
69 |
70 | // assert.equal(createBindings.called, false);
71 | assert.equal(carousel.active, false);
72 |
73 | teardown();
74 | assert.end();
75 | });
76 |
77 | t.skip('cannot call destroy (or other methods) on carousel which did not init', function(assert) {
78 | setup({}, badTemplate);
79 | // assert: carousel did not init
80 | teardown();
81 | assert.end();
82 |
83 | });
84 |
85 | t.skip('destroys cleanly, removing all references and events', function(assert) {
86 | setup();
87 |
88 | const destroy = spy(carousel.destroy);
89 |
90 | carousel.destroy();
91 |
92 | assert.equal(destroy.called, true);
93 | // assert.equal(Object.keys(getEventListeners(carousel.handle)).length, 0); // *sigh* JSDOM cannot do this
94 | // assert.equal(Object.keys(getEventListeners(global.window)).length, 0); // :(
95 |
96 | teardown();
97 | assert.end();
98 | });
99 |
100 | t.test('accepts and applies options correctly', function(assert) {
101 | setup({
102 | animateClass: 'sample',
103 | activeClass: 'sample',
104 | infinite: false,
105 | display: 2,
106 | disableDragging: true,
107 | initialIndex: 2
108 | });
109 |
110 | assert.equal(carousel.options.animateClass, 'sample');
111 | assert.equal(carousel.options.activeClass, 'sample');
112 | assert.equal(carousel.options.infinite, false);
113 | assert.equal(carousel.options.display, 2);
114 | assert.equal(carousel.options.disableDragging, true);
115 | assert.equal(carousel.options.initialIndex, 2);
116 | assert.equal(carousel.current, 2);
117 |
118 | teardown();
119 | assert.end();
120 | });
121 |
122 | t.test('clones slides if infinite', function(assert) {
123 | setup({
124 | infinite: true,
125 | });
126 |
127 | // spyOn(Carousel._cloneSlides).and.callThrough();
128 |
129 | // assert(carousel._cloneSlides).toHaveBeenCalled();
130 |
131 | teardown();
132 | assert.end();
133 | });
134 |
135 | t.test('clones slides correctly', function(assert) {
136 | setup({
137 | infinite: true,
138 | display: 1
139 | });
140 |
141 | const slides = carousel.slideWrap.children; // this includes cloned nodes, while carousel.slides does not
142 | const begClone = slides[0];
143 | const endClone = slides[4];
144 |
145 | assert.equal(slides.length, 5); // 3 slides + 1 begClone + 1 endClone
146 | assert.deepEqual(begClone, slides[3]); // begClone was taken from the end
147 | assert.deepEqual(endClone, slides[1]); // endClone was taken from the beg
148 | // assert: begClone has aria-hidden attr, "clone" class, no id
149 |
150 | teardown();
151 | assert.end();
152 | });
153 | });
154 |
155 |
156 | test('Navigation:', function(t) {
157 |
158 | t.test('jumps to slide 2 when go(2) is called', function(assert) {
159 | setup();
160 |
161 | carousel.go(2);
162 | assert.equal(carousel.current, 2);
163 |
164 | teardown();
165 | assert.end();
166 | });
167 |
168 | t.test('goes to the next slide when next() is called', function(assert) {
169 | setup();
170 |
171 | carousel.next();
172 | assert.equal(carousel.current, 1); // because 0 is first
173 |
174 | teardown();
175 | assert.end();
176 | });
177 |
178 | t.test('goes to the previous slide when prev() is called', function(assert) {
179 | setup({ initialIndex: 2 });
180 |
181 | carousel.prev();
182 |
183 | assert.equal(carousel.current, 1);
184 |
185 | teardown();
186 | assert.end();
187 | });
188 |
189 | t.test('when we are at the last slide in an infinite carousel, goes to the first slide when next() is called', function(assert) {
190 | setup({ initialIndex: 2 });
191 |
192 | carousel.next();
193 |
194 | assert.equal(carousel.current, 0);
195 |
196 | teardown();
197 | assert.end();
198 | });
199 |
200 | t.test('when we are at the first slide in an infinite carousel, goes to the last slide when prev() is called', function(assert) {
201 | setup();
202 |
203 | carousel.prev();
204 |
205 | assert.equal(carousel.current, 2);
206 |
207 | teardown();
208 | assert.end();
209 | });
210 | });
211 |
212 |
213 | test('General:', function(t) {
214 | t.skip('will not error out if destroy() called during slide transition', function(assert) {
215 | setup();
216 |
217 | carousel.next();
218 | assert.doesNotThrow(carousel.destroy, 'TypeError');
219 |
220 | teardown();
221 | assert.end();
222 | });
223 |
224 | t.test('updates class on active element', function(assert) {
225 | setup({
226 | activeClass: 'test',
227 | initialIndex: 1
228 | });
229 |
230 | const slideClass = carousel.slides[carousel.current].classList[0];
231 |
232 | assert.equal(slideClass, 'test');
233 |
234 | teardown();
235 | assert.end();
236 | });
237 | });
--------------------------------------------------------------------------------
/demo/prism.js:
--------------------------------------------------------------------------------
1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript */
2 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=_self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),P=[p,1];b&&P.push(b);var A=new a(i,g?t.tokenize(m,g):m,h);P.push(A),w&&P.push(w),Array.prototype.splice.apply(r,P)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,l=0;r=a[l++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var l={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==l.type&&(l.attributes.spellcheck="true"),e.alias){var i="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}t.hooks.run("wrap",l);var o="";for(var s in l.attributes)o+=(o?" ":"")+s+'="'+(l.attributes[s]||"")+'"';return"<"+l.tag+' class="'+l.classes.join(" ")+'" '+o+">"+l.content+""+l.tag+">"},!_self.document)return _self.addEventListener?(_self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code,l=n.immediateClose;_self.postMessage(t.highlight(r,t.languages[a],a)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
3 | Prism.languages.markup={comment://,prolog:/<\?[\w\W]+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=.$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/[=>"']/}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup;
4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*?(?=\s*\{)/,string:/("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.util.clone(Prism.languages.css),Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/(