flickity
Version:
Touch, responsive, flickable carousels
183 lines (161 loc) • 4.91 kB
JavaScript
// add, remove cell
( function( window, factory ) {
// universal module definition
/* jshint strict: false */
if ( typeof define == 'function' && define.amd ) {
// AMD
define( [
'./flickity',
'fizzy-ui-utils/utils'
], function( Flickity, utils ) {
return factory( window, Flickity, utils );
});
} else if ( typeof module == 'object' && module.exports ) {
// CommonJS
module.exports = factory(
window,
require('./flickity'),
require('fizzy-ui-utils')
);
} else {
// browser global
factory(
window,
window.Flickity,
window.fizzyUIUtils
);
}
}( window, function factory( window, Flickity, utils ) {
'use strict';
// append cells to a document fragment
function getCellsFragment( cells ) {
var fragment = document.createDocumentFragment();
cells.forEach( function( cell ) {
fragment.appendChild( cell.element );
});
return fragment;
}
// -------------------------- add/remove cell prototype -------------------------- //
var proto = Flickity.prototype;
/**
* Insert, prepend, or append cells
* @param {Element, Array, NodeList} elems
* @param {Integer} index
*/
proto.insert = function( elems, index ) {
var cells = this._makeCells( elems );
if ( !cells || !cells.length ) {
return;
}
var len = this.cells.length;
// default to append
index = index === undefined ? len : index;
// add cells with document fragment
var fragment = getCellsFragment( cells );
// append to slider
var isAppend = index == len;
if ( isAppend ) {
this.slider.appendChild( fragment );
} else {
var insertCellElement = this.cells[ index ].element;
this.slider.insertBefore( fragment, insertCellElement );
}
// add to this.cells
if ( index === 0 ) {
// prepend, add to start
this.cells = cells.concat( this.cells );
} else if ( isAppend ) {
// append, add to end
this.cells = this.cells.concat( cells );
} else {
// insert in this.cells
var endCells = this.cells.splice( index, len - index );
this.cells = this.cells.concat( cells ).concat( endCells );
}
this._sizeCells( cells );
var selectedIndexDelta = index > this.selectedIndex ? 0 : cells.length;
this._cellAddedRemoved( index, selectedIndexDelta );
};
proto.append = function( elems ) {
this.insert( elems, this.cells.length );
};
proto.prepend = function( elems ) {
this.insert( elems, 0 );
};
/**
* Remove cells
* @param {Element, Array, NodeList} elems
*/
proto.remove = function( elems ) {
var cells = this.getCells( elems );
var selectedIndexDelta = 0;
var len = cells.length;
var i, cell;
// calculate selectedIndexDelta, easier if done in seperate loop
for ( i=0; i < len; i++ ) {
cell = cells[i];
var wasBefore = this.cells.indexOf( cell ) < this.selectedIndex;
selectedIndexDelta -= wasBefore ? 1 : 0;
}
for ( i=0; i < len; i++ ) {
cell = cells[i];
cell.remove();
// remove item from collection
utils.removeFrom( this.cells, cell );
}
if ( cells.length ) {
// update stuff
this._cellAddedRemoved( 0, selectedIndexDelta );
}
};
// updates when cells are added or removed
proto._cellAddedRemoved = function( changedCellIndex, selectedIndexDelta ) {
// TODO this math isn't perfect with grouped slides
selectedIndexDelta = selectedIndexDelta || 0;
this.selectedIndex += selectedIndexDelta;
this.selectedIndex = Math.max( 0, Math.min( this.slides.length - 1, this.selectedIndex ) );
this.cellChange( changedCellIndex, true );
// backwards compatibility
this.emitEvent( 'cellAddedRemoved', [ changedCellIndex, selectedIndexDelta ] );
};
/**
* logic to be run after a cell's size changes
* @param {Element} elem - cell's element
*/
proto.cellSizeChange = function( elem ) {
var cell = this.getCell( elem );
if ( !cell ) {
return;
}
cell.getSize();
var index = this.cells.indexOf( cell );
this.cellChange( index );
};
/**
* logic any time a cell is changed: added, removed, or size changed
* @param {Integer} changedCellIndex - index of the changed cell, optional
*/
proto.cellChange = function( changedCellIndex, isPositioningSlider ) {
var prevSlideableWidth = this.slideableWidth;
this._positionCells( changedCellIndex );
this._getWrapShiftCells();
this.setGallerySize();
this.emitEvent( 'cellChange', [ changedCellIndex ] );
// position slider
if ( this.options.freeScroll ) {
// shift x by change in slideableWidth
// TODO fix position shifts when prepending w/ freeScroll
var deltaX = prevSlideableWidth - this.slideableWidth;
this.x += deltaX * this.cellAlign;
this.positionSlider();
} else {
// do not position slider after lazy load
if ( isPositioningSlider ) {
this.positionSliderAtSelected();
}
this.select( this.selectedIndex );
}
};
// ----- ----- //
return Flickity;
}));