(function ($, undefined) {
var $window = $(window);
var defaults = {
btnPrev: null,
btnNext: null,
btnGo: null,
auto: null,
speed: 'fast',
easing: null,
editMode: false,
vertical: false,
circular: true,
visible: 3,
start: 0,
scroll: 1,
hideScrollButtons: false,
resizeListItems: false,
beforeStart: null,
afterEnd: null,
afterScroll: null
};
function Layout(dimension, position, float) {
this.d = dimension;
this.p = position;
this.itemFloat = float;
}
Layout.prototype = {
dimension: function (element, value) {
return element[this.d](value);
},
positionCss: function (value) {
var result = {};
result[this.p] = value;
return result;
},
setPosition: function (element, value) {
element.css(this.p, value);
}
};
var VerticalLayout = new Layout('height', 'top', 'none');
var HorizontalLayout = new Layout('width', 'left', 'left');
var HorizontalRtlLayout = new Layout('width', 'right', 'right');
function Filmstrip(e, options) {
var self = this;
var rtl = false;
var autoEnabled, autoTimer;
var first, last, layout, animating;
var $container, $list, $items;
var $btnNext, $btnPrev;
$container = $(e);
$list = $container.find('ul, ol').first();
$items = listItems();
options = $.extend({}, defaults, options);
rtl = ($container.css('direction') == 'rtl')
first = options.start;
last = first + options.visible;
layout = options.vertical ? VerticalLayout : rtl ? HorizontalRtlLayout : HorizontalLayout;
animating = false;
autoTimer = null;
autoEnabled = false;
self.$container = $container;
self.$list = $list;
if (options.btnNext) {
$btnNext = $(options.btnNext);
$btnNext.click(function (e) {
self.next();
e.preventDefault();
});
self.$btnNext = $btnNext;
}
if (options.btnPrev) {
$btnPrev = $(options.btnPrev);
$btnPrev.click(function (e) {
self.prev();
e.preventDefault();
});
self.$btnPrev = $btnPrev;
}
function listItems() {
return $list.children('li');
}
function updateItems() {
$items = listItems();
if (options.resizeListItems) {
var itemDimension = Math.floor(layout.dimension($container) / options.visible);
layout.dimension($items, itemDimension);
}
$items.css({
height: '100%',
display: 'block',
float: layout.itemFloat
});
}
function updateList() {
updateItems();
var width = 0;
$items.each(function () { width += $(this).outerWidth(true); });
layout.dimension($list, width);
$list.css('height', '100%');
}
function pos(delta, animate, userCallback) {
if (animating) {
return;
}
var newFirst = first + (delta || 0);
var newLast = newFirst + options.visible;
var $itemsToClone, $clonedItems;
updateList();
pauseAutoScroll();
if (options.visible >= $items.length) {
newFirst = 0;
}
else if (newFirst < 0) {
$itemsToClone = $items.slice(newFirst);
$clonedItems =
$itemsToClone
.clone()
.prependTo($list);
updateList();
newFirst += $itemsToClone.length;
if ($clonedItems) {
var pos = 0;
$clonedItems.each(function () { pos -= $(this).outerWidth(true); });
layout.setPosition($list, pos);
}
}
else if (newLast > $items.length) {
$itemsToClone = $items.slice(0, newLast - $items.length);
$clonedItems =
$itemsToClone
.clone()
.appendTo($list);
updateList();
}
var destPos = 0;
$items.slice(0, newFirst).each(function () { destPos -= $(this).outerWidth(true); });
var properties = layout.positionCss(destPos);
if (animate) {
animating = true;
$list.animate(properties, options.speed, function () {
animating = false;
callback();
});
}
else {
$list.css(properties);
callback();
}
function callback() {
if ($itemsToClone) {
$itemsToClone.remove();
updateList();
if (newLast > $items.length) {
newFirst -= $itemsToClone.length;
var destPos = 0;
var includeMargin = true;
$items.slice(0, newFirst).each(function () { destPos -= $(this).outerWidth(includeMargin); });
layout.setPosition($list, destPos);
}
}
first = newFirst;
last = newLast;
self.first = newFirst;
if (options.afterScroll) {
options.afterScroll(self);
}
if (userCallback) {
userCallback(self);
}
if (autoEnabled) {
autoScroll();
}
}
}
function pauseAutoScroll() {
if (autoTimer !== null) {
window.clearTimeout(autoTimer);
autoTimer = null;
}
}
function autoScroll(timeout) {
if (timeout !== undefined) {
options.auto = timeout;
}
pauseAutoScroll();
autoEnabled = (0 < options.auto);
if (autoEnabled) {
autoTimer = window.setTimeout(function () {
self.next();
}, options.auto);
}
}
function ensureVisible(index, callback) {
if (index < first) {
pos(index - first, true, callback);
}
else if (index >= first + options.visible) {
pos(index - (first + options.visible) + 1, true, callback);
}
else {
callback(self);
}
}
function update() {
delete self.next;
delete self.prev;
pos(0);
if ((options.visible < $items.length) && (options.scroll < $items.length)) {
$btnNext.show();
$btnPrev.show();
var scroll = options.scroll;
if (rtl) {
scroll = -scroll;
}
self.next = function () {
pos(+scroll, true);
};
self.prev = function () {
pos(-scroll, true);
};
}
else if (options.hideScrollButtons) {
$btnNext.css('visibility', 'hidden');
$btnPrev.css('visibility', 'hidden');
}
}
$container.css({
overflow: 'hidden',
position: 'relative'
});
$window.bind('resize.filmstrip', function () {
pos(0);
});
$list.css({
margin: 0,
padding: 0,
border: 'none',
display: 'block',
position: 'absolute',
listStyleType: 'none'
});
self.update = update;
self.autoScroll = autoScroll;
self.pauseAutoScroll = pauseAutoScroll;
self.resumeAutoScroll = function () { autoScroll(); }
self.ensureVisible = ensureVisible;
self.options = options;
setTimeout(function () {
self.update();
autoScroll();
}, 0);
}
Filmstrip.fn = Filmstrip.prototype = {
filmstrip: '1.0.0',
next: $.noop,
prev: $.noop
};
$.fn.filmstrip = function () {
var fs;
var slice = Array.prototype.slice;
if (typeof arguments[0] === 'string') {
fs = this.data('filmstrip');
fs[arguments[0]].apply(fs, slice.call(arguments, 1));
}
else {
fs = new Filmstrip(this, arguments[0]);
this.data('filmstrip', fs);
}
return this;
}
})(jQuery);
