├── .nvmrc
├── .gitignore
├── .eslintrc.js
├── bower.json
├── package.json
├── test
├── test-sync.js
└── index.html
├── README.md
├── sandbox
└── sync.html
└── flickity-sync.js
/.nvmrc:
--------------------------------------------------------------------------------
1 | 16
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components/
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [ 'metafizzy' ],
3 | extends: 'plugin:metafizzy/browser',
4 | env: {
5 | browser: true,
6 | commonjs: true,
7 | },
8 | parserOptions: {
9 | ecmaVersion: 2018,
10 | },
11 | globals: {
12 | Flickity: 'readonly',
13 | QUnit: 'readonly',
14 | },
15 | rules: {
16 | 'prefer-object-spread': 'error',
17 | },
18 | ignorePatterns: [ 'bower_components' ],
19 | };
20 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flickity-sync",
3 | "description": "Enable sync for Flickity",
4 | "main": "flickity-sync.js",
5 | "dependencies": {
6 | "flickity": "^2.0.0",
7 | "fizzy-ui-utils": "^2.0.0"
8 | },
9 | "devDependencies": {
10 | "qunit": "~1.17.1"
11 | },
12 | "authors": [
13 | "David DeSandro"
14 | ],
15 | "moduleType": [
16 | "amd",
17 | "globals",
18 | "node"
19 | ],
20 | "keywords": [
21 | "flickity"
22 | ],
23 | "license": "MIT",
24 | "ignore": [
25 | "**/.*",
26 | "node_modules",
27 | "bower_components",
28 | "test",
29 | "tests",
30 | "package.json"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flickity-sync",
3 | "version": "3.0.0",
4 | "description": "Enable sync for Flickity",
5 | "main": "flickity-sync.js",
6 | "dependencies": {
7 | "fizzy-ui-utils": "^3.0.0"
8 | },
9 | "peerDependencies": {
10 | "flickity": "^3.0.0"
11 | },
12 | "devDependencies": {
13 | "eslint": "^8.10.0",
14 | "eslint-plugin-metafizzy": "^2.0.1",
15 | "qunit": "^2.18.0"
16 | },
17 | "scripts": {
18 | "test": "npm run lint",
19 | "lint": "npx eslint ."
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "git://github.com/metafizzy/flickity-sync.git"
24 | },
25 | "keywords": [
26 | "flickity",
27 | "browser",
28 | "DOM"
29 | ],
30 | "author": "David DeSandro",
31 | "license": "GPL",
32 | "bugs": {
33 | "url": "https://github.com/metafizzy/flickity-sync/issues"
34 | },
35 | "homepage": "https://github.com/metafizzy/flickity-sync"
36 | }
37 |
--------------------------------------------------------------------------------
/test/test-sync.js:
--------------------------------------------------------------------------------
1 | QUnit.test( 'sync', function( assert ) {
2 |
3 | let flktyA = new Flickity( '#sync-a', {
4 | sync: '#sync-b',
5 | } );
6 |
7 | let elemB = document.querySelector('#sync-b');
8 | let flktyB = new Flickity( elemB );
9 |
10 | // HACK do async because syncing is async
11 | let done = assert.async();
12 |
13 | setTimeout( function() {
14 | flktyA.next();
15 | assert.equal( flktyB.selectedIndex, 1, 'A.next() syncs to B' );
16 | flktyB.previous();
17 | assert.equal( flktyA.selectedIndex, 0, 'B.previous() syncs to A' );
18 | flktyA.select( 3 );
19 | assert.equal( flktyB.selectedIndex, 3, 'A.select() syncs to B' );
20 | // usync()
21 | flktyA.unsync('#sync-b');
22 | flktyA.select( 1 );
23 | assert.equal( flktyB.selectedIndex, 3, 'A.unsync() unsyncs A from B' );
24 | flktyB.select( 4 );
25 | assert.equal( flktyA.selectedIndex, 1, 'A.unsync() unsyncs B from A' );
26 | // sync()
27 | flktyB.sync('#sync-a');
28 | flktyB.select( 0 );
29 | assert.equal( flktyA.selectedIndex, 0, 'B.sync() syncs B to A' );
30 | flktyA.select( 2 );
31 | assert.equal( flktyB.selectedIndex, 2, 'B.sync() syncs A to B' );
32 | // unsyncAll()
33 | flktyA.unsyncAll();
34 | flktyA.select( 1 );
35 | assert.equal( flktyB.selectedIndex, 2, 'A.unsyncAll() unsyncs A from B' );
36 | flktyB.select( 4 );
37 | assert.equal( flktyA.selectedIndex, 1, 'A.unsyncAll() unsyncs B from A' );
38 |
39 | done();
40 | }, 100 );
41 |
42 | } );
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flickity sync
2 |
3 | Enables `sync` option for [Flickity](https://flickity.metafizzy.co/)
4 |
5 | You can sync two Flickity carousels. Whenever one selects a cell, its companion will select its matching cell of the same index.
6 |
7 | ``` html
8 |
9 | ...
10 |
11 |
12 | ...
13 |
14 | ```
15 |
16 | ``` js
17 | // options
18 | sync: '.carousel-b'
19 | // set as a selector string
20 |
21 | sync: document.querySelector('.carousel-b')
22 | // set as an element
23 | ```
24 |
25 | [See demo on CodePen](https://codepen.io/desandro/pen/gOXEKPK).
26 |
27 | ## Install
28 |
29 | Add `flickity-sync.js` to your scripts.
30 |
31 | ### Download
32 |
33 | + [flickity-sync.js](https://unpkg.com/flickity-sync@3/flickity-sync.js)
34 |
35 | ### CDN
36 |
37 | ``` html
38 |
39 | ```
40 |
41 | ### Package managers
42 |
43 | npm: `npm install flickity-sync`
44 |
45 | Yarn: `yarn add flickity-sync`
46 |
47 | ## Usage
48 |
49 | ### jQuery
50 |
51 | ``` js
52 | $('.carousel-a').flickity({
53 | sync: '.carousel-b'
54 | });
55 | // only need to set sync on one of the Flickity galleries
56 | $('.carousel-b').flickity();
57 | ```
58 |
59 | ### Vanilla JS
60 |
61 | ``` js
62 | var flktyA = new Flickity( '.carousel-a', {
63 | sync: '.carousel-b'
64 | });
65 | var flktyB = new Flickity('.carousel-b');
66 | ```
67 |
68 | ### HTML
69 |
70 | ``` html
71 |
72 | ...
73 |
74 |
75 | ...
76 |
77 | ```
78 |
79 | ### Webpack
80 |
81 | ``` js
82 | const Flickity = require('flickity');
83 | require('flickity-sync');
84 |
85 | var flktyA = new Flickity( '.carousel-a', {
86 | sync: '.carousel-b'
87 | });
88 | var flktyB = new Flickity('.carousel-b');
89 | ```
90 |
91 | ---
92 |
93 | By [Metafizzy 🌈🐻](https://metafizzy.co)
94 |
--------------------------------------------------------------------------------
/sandbox/sync.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | sync
8 |
9 |
10 |
31 |
32 |
33 |
34 |
35 | sync
36 |
37 |
39 |
1
40 |
2
41 |
3
42 |
4
43 |
5
44 |
6
45 |
7
46 |
47 |
48 |
49 |
1
50 |
2
51 |
3
52 |
4
53 |
5
54 |
6
55 |
7
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Flickity tests
8 |
9 |
10 |
11 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | sync
63 |
64 |
1
65 |
2
66 |
3
67 |
4
68 |
5
69 |
6
70 |
71 |
72 |
73 |
1
74 |
2
75 |
3
76 |
4
77 |
5
78 |
6
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/flickity-sync.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Flickity sync v2.0.0
3 | * enable sync for Flickity
4 | */
5 |
6 | ( function( window, factory ) {
7 | // universal module definition
8 | if ( typeof module == 'object' && module.exports ) {
9 | // CommonJS
10 | module.exports = factory(
11 | require('flickity'),
12 | require('fizzy-ui-utils'),
13 | );
14 | } else {
15 | // browser global
16 | factory(
17 | window.Flickity,
18 | window.fizzyUIUtils,
19 | );
20 | }
21 |
22 | }( typeof window != 'undefined' ? window : this, function factory( Flickity, utils ) {
23 |
24 | // -------------------------- sync prototype -------------------------- //
25 |
26 | // Flickity.defaults.sync = false;
27 |
28 | Flickity.create.sync = function() {
29 | this.syncers = {};
30 | let syncOption = this.options.sync;
31 |
32 | this.on( 'destroy', this.unsyncAll );
33 |
34 | if ( !syncOption ) return;
35 | // HACK do async, give time for other flickity to be initalized
36 | setTimeout( () => {
37 | this.sync( syncOption );
38 | } );
39 | };
40 |
41 | let proto = Flickity.prototype;
42 |
43 | /**
44 | * sync
45 | * @param {[Element, String]} elem
46 | */
47 | proto.sync = function( elem ) {
48 | elem = utils.getQueryElement( elem );
49 | let companion = Flickity.data( elem );
50 | if ( !companion ) return;
51 | // two hearts, that beat as one
52 | this._syncCompanion( companion );
53 | companion._syncCompanion( this );
54 | };
55 |
56 | /**
57 | * @param {Flickity} companion
58 | */
59 | proto._syncCompanion = function( companion ) {
60 | let _this = this;
61 | function syncListener() {
62 | let index = _this.selectedIndex;
63 | // do not select if already selected, prevent infinite loop
64 | if ( companion.selectedIndex !== index ) {
65 | companion.select( index );
66 | }
67 | }
68 | this.on( 'select', syncListener );
69 | // keep track of all synced flickities
70 | // hold on to listener to unsync
71 | this.syncers[ companion.guid ] = {
72 | flickity: companion,
73 | listener: syncListener,
74 | };
75 | };
76 |
77 | /**
78 | * unsync
79 | * @param {[Element, String]} elem
80 | */
81 | proto.unsync = function( elem ) {
82 | elem = utils.getQueryElement( elem );
83 | let companion = Flickity.data( elem );
84 | this._unsync( companion );
85 | };
86 |
87 | /**
88 | * @param {Flickity} companion
89 | */
90 | proto._unsync = function( companion ) {
91 | if ( !companion ) return;
92 | // I love you but I've chosen darkness
93 | this._unsyncCompanion( companion );
94 | companion._unsyncCompanion( this );
95 | };
96 |
97 | /**
98 | * @param {Flickity} companion
99 | */
100 | proto._unsyncCompanion = function( companion ) {
101 | let id = companion.guid;
102 | let syncer = this.syncers[ id ];
103 | this.off( 'select', syncer.listener );
104 | delete this.syncers[ id ];
105 | };
106 |
107 | proto.unsyncAll = function() {
108 | for ( let id in this.syncers ) {
109 | let syncer = this.syncers[ id ];
110 | this._unsync( syncer.flickity );
111 | }
112 | };
113 |
114 | // ----- ----- //
115 |
116 | return Flickity;
117 |
118 | } ) );
119 |
--------------------------------------------------------------------------------