├── .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 | 11 | 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 | 74 | 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 | 47 | 48 | 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 | 71 | 72 | 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 | --------------------------------------------------------------------------------