Files
HotLunches/include/NivooSlider.js
T
2026-10-19 15:22:52 -07:00

780 lines
18 KiB
JavaScript

/*
---
script: NivooSlider.js
description: A nice image slider for MooTools.
license: MIT-style license
authors:
- Johannes Fischer
requires:
- core/1.4: '*'
provides:
- NivooSlider
...
*/
var NivooSlider = new Class({
Implements: [Events, Options],
caption: null,
children: null,
containerSize: 0,
count: 0,
currentSlide: 0,
currentImage: '',
effects: {
// used for random effects
common: ['fade'],
horizontal: ['foldDown', 'foldUp', 'sliceLeftUp', 'sliceLeftDown', 'sliceLeftRightDown', 'sliceLeftRightUp', 'sliceRightDown', 'sliceRightUp', 'wipeDown', 'wipeUp'],
vertical: ['foldLeft', 'foldRight', 'sliceDownLeft', 'sliceDownRight', 'sliceUpDownLeft', 'sliceUpDownRight', 'sliceUpLeft', 'sliceUpRight', 'wipeLeft', 'wipeRight']
},
holder: null,
hover: false,
interval: null,
isActive: true,
orientation: '',
paused: false,
running: false,
slices: null,
sliceSize: null,
totalSlides: 0,
options: {
animSpeed: 500,
autoPlay: true,
controlNav: true,
controlNavItem: 'disc',
directionNav: true,
directionNavHide: false,
directionNavPosition: 'inside',
directionNavWidth: '20%',
effect: 'sliceDown', // TODO allow to pass an array with multiple effects
interval: 3000,
orientation: 'vertical',
pauseOnBlur: false,
pauseOnHover: true,
slices: 15,
// not implemented yet
preLoadImages: false
//onFinish: function () {}
//onLastSlide: function () {}
//onStart: function () {}
},
initialize: function (container, options) {
this.container = $(container);
this.setOptions(options);
this.orientation = this.getOrientation();
this.effects.horizontal.combine(this.effects.common);
this.effects.vertical.combine(this.effects.common);
this.initSlider();
this.createSlices();
if (this.options.autoPlay) {
this.play();
if (this.options.pauseOnBlur) {
window.addEvents({
blur: function () {
this.isActive = false;
this.pause();
}.bind(this),
focus: function () {
this.isActive = true;
this.play();
}.bind(this)
});
}
}
},
animate: function (slice, fxStyles, last)
{
var fx = slice.retrieve('fxInstance'),
isLast = last !== undefined && last === true;
fx.start(fxStyles).chain(function () {
this.count += 1;
if (this.count === this.options.slices || isLast) {
this.running = false;
// fire onFinish function
this.finish();
this.setBackgroundImage();
this.count = 0;
if (this.currentSlide === (this.totalSlides - 1)) {
this.lastSlide();
}
}
}.bind(this));
},
arrangeSlices: function () {
var height,
position,
sliceSize,
width;
this.slices.each(function (el, i) {
position = {
left: this.orientation === 'vertical' ? this.sliceSize.x * i : 0,
top: this.orientation === 'horizontal' ? this.sliceSize.y * i : 0
};
// set size & position
if (this.orientation === 'horizontal') {
height = i === this.options.slices - 1 ? this.containerSize.y - (this.sliceSize.y * i) : this.sliceSize.y;
width = '100%';
el.setStyles({
height: height,
top: position.top,
width: width
});
} else { // if vertical
height = 0;
width = i === this.options.slices - 1 ? this.containerSize.x - (this.sliceSize.x * i) : this.sliceSize.x;
el.setStyles({
height: height,
left: position.left,
top: '',
width: width
});
}
el.store('fxInstance', new Fx.Morph(el, {
duration: this.options.animSpeed
})).store('coordinates', Object.merge(position, {height: height, width: width}));
}, this);
},
createCaption: function () {
this.caption = new Element('p', {
styles: {
opacity: 0
}
}).inject(this.holder);
this.caption.store('fxInstance', new Fx.Morph(this.caption, {
duration: 200,
wait: false
}));
},
createControlNav: function () {
var cssClass = '',
html,
i = 1;
this.container.addClass('got-control-nav');
new Element('div.control-nav').inject(this.container);
this.totalSlides.each(function (el) {
if (this.options.controlNavItem === 'decimal') {
html = i;
i++;
} else if (this.options.controlNavItem === 'disc') {
cssClass = 'decimal';
html = '•';
} else {
html = this.options.controlNavItem;
}
new Element('a', {
'class': cssClass,
events: {
'click': function (e) {
e.stop();
this.slide(el);
}.bind(this)
},
href: '#',
html: html
}).inject(this.container.getElement('div.control-nav'));
}, this);
this.setCurrentControlItem();
},
createDirectionNav: function () {
var directionNavStyles,
leftContainer,
rightContainer,
target,
width;
target = this.options.directionNavPosition === 'inside' ? this.holder : this.container;
width = this.options.directionNavWidth;
directionNavStyles = {
height: this.containerSize.y
};
if (this.options.directionNavPosition === 'inside' && this.options.directionNavWidth.toInt() !== 0) {
directionNavStyles.width = width;
}
// create container
leftContainer = new Element('div.direction-nav-left', {
styles: directionNavStyles
}).inject(target);
rightContainer = new Element('div.direction-nav-right', {
styles: directionNavStyles
}).inject(target);
// create controls
this.leftNav = new Element('a', {
events: {
'click': function (e) {
e.stop();
if (this.options.autoPlay)
{
this.pause();
if (!this.options.pauseOnHover)
{
this.play();
}
}
this.previous();
}.bind(this)
},
href: '#',
styles: {
height: directionNavStyles.height
}
}).inject(leftContainer);
this.rightNav = new Element('a', {
events: {
'click': function (e) {
e.stop();
if (this.options.autoPlay) {
this.pause();
if (!this.options.pauseOnHover)
{
this.play();
}
}
this.next();
}.bind(this)
},
href: '#',
styles: {
height: directionNavStyles.height
}
}).inject(rightContainer);
if (this.options.directionNavHide && this.options.directionNav)
{
$$(this.leftNav, this.rightNav).setStyle('opacity', 0);
this.holder.addEvents({
'mouseout': function () {
$$(this.leftNav, this.rightNav).fade(0);
}.bind(this),
'mouseover': function () {
$$(this.leftNav, this.rightNav).fade(1);
}.bind(this)
});
}
},
createLinkHolder: function ()
{
this.linkHolder = new Element('a.nivoo-link', {
href: '#'
}).inject(this.holder);
},
createSlices: function ()
{
this.sliceSize = {
x: (this.containerSize.x / this.options.slices).round(),
y: (this.containerSize.y / this.options.slices).round()
};
// effects that need one slice only
if (['fade', 'wipeLeft', 'wipeRight'].contains(this.options.effect)) {
this.options.slices = 1;
}
this.options.slices.each(function (i) {
new Element('div.nivoo-slice').inject(this.holder);
}, this);
this.slices = this.getSlices();
this.arrangeSlices();
},
getImages: function () {
return this.holder.getElements('img');
},
getOrientation: function () {
if (this.effects.horizontal.indexOf(this.options.effect) > -1) {
return 'horizontal';
} else if (this.effects.vertical.indexOf(this.options.effect) > -1) {
return 'vertical';
} else {
return this.options.orientation;
}
},
getSlices: function () {
return this.holder.getElements('.nivoo-slice');
},
initSlider: function () {
if (this.options.directionNavPosition === 'outside') {
this.container.addClass('direction-nav-outside');
}
// wrap child elements
this.holder = new Element('div.nivoo-slider-holder').adopt(this.container.getChildren()).inject(this.container);
this.containerSize = this.holder.getSize();
// Find our slider children
this.children = this.getImages();
this.totalSlides = this.children.length;
this.children.setStyle('display', 'none');
this.currentImage = this.children[0];
// init LinkHolderand set link
this.createLinkHolder();
this.setLink();
// Set first background
this.setBackgroundImage();
this.createCaption();
this.showCaption();
// attach pauseOnHover
if (this.options.pauseOnHover && this.options.autoPlay) {
this.holder.addEvents({
'mouseenter': function () {
this.pause();
}.bind(this),
'mouseleave': function () {
this.play();
}.bind(this)
});
}
// create directional navigation
if (this.options.directionNav)
{
this.createDirectionNav();
}
// create control navigation
if (this.options.controlNav)
{
this.createControlNav();
}
},
hideCaption: function ()
{
this.caption.retrieve('fxInstance').start({
bottom: this.caption.getHeight() * -1,
opacity: 0.5
});
},
next: function ()
{
this.currentSlide += 1;
if (this.currentSlide === this.totalSlides) {
this.currentSlide = 0;
}
this.slide();
},
pause: function ()
{
window.clearInterval(this.interval);
this.interval = null;
},
play: function ()
{
if (this.interval === null && this.isActive === true) {
this.interval = this.next.periodical(this.options.interval, this);
}
},
previous: function ()
{
if (this.options.autoPlay) {
this.pause();
if (!this.options.pauseOnHover) {
this.play();
}
}
this.currentSlide -= 1;
if (this.currentSlide < 0) {
this.currentSlide = (this.totalSlides - 1);
}
this.slide();
},
setCurrentControlItem: function ()
{
var active = this.container.getElement('div.control-nav a.current');
if (active) {
active.removeClass('current');
}
this.container.getElements('div.control-nav a')[this.currentSlide].addClass('current');
},
showCaption: function ()
{
var title = this.currentImage.get('title');
if (!title) {
this.hideCaption();
return;
}
this.setCaptionText(title);
this.caption.retrieve('fxInstance').start({
bottom: 0,
opacity: 1
});
},
slide: function (slideNo) {
var coordinates,
effect,
slice,
slices,
styles,
timeBuff;
if (this.running) {
return;
}
if (this.orientation === 'random') {
this.orientation = ['horizontal', 'vertical'].getRandom();
}
this.arrangeSlices();
if (slideNo !== undefined) {
this.currentSlide = slideNo;
}
// set currentImage
this.currentImage = this.children[this.currentSlide];
// set current control nav item
if (this.options.controlNav) {
this.setCurrentControlItem();
}
this.setLink();
// Process caption
this.showCaption();
// TODO use this.slices within each loop instead
slices = this.slices;
timeBuff = 0;
// reset slices
this.slices.each(function (slice) {
coordinates = slice.retrieve('coordinates');
slice.setStyles({
background: 'url("' + this.currentImage.get('src') + '") no-repeat -' + coordinates.left + 'px ' + coordinates.top * -1 + 'px',
bottom: '',
height: coordinates.height,
left: coordinates.left,
opacity: 0,
right: '',
top: coordinates.top,
width: coordinates.width
});
var property = this.orientation === 'horizontal' ? 'width' : 'height';
slice.setStyle(property, 0);
}, this);
// fire onStart function
this.start();
// Run effects
this.running = true;
effect = this.options.effect;
if (effect === 'random') {
effect = this.effects[this.orientation].getRandom();
}
// vertical effects
if (['sliceDownRight', 'sliceDownLeft'].contains(effect)) {
if (effect === 'sliceDownLeft')
{
slices = slices.reverse();
}
slices.each(function (slice) {
slice.setStyle('top', 0);
this.animate.delay(100 + timeBuff, this, [slice, {height: this.containerSize.y, opacity: 1}]);
timeBuff += 50;
}, this);
} else if (['sliceUpRight', 'sliceUpLeft'].contains(effect)) {
if (effect === 'sliceUpLeft')
{
slices = slices.reverse();
}
slices.each(function (slice) {
var fx = slice.retrieve('fxInstance');
slice.setStyle('bottom', 0);
this.animate.delay(100 + timeBuff, this, [slice, {height: this.containerSize.y, opacity: 1}]);
timeBuff += 50;
}, this);
}
else if (['sliceUpDownRight', 'sliceUpDownLeft'].contains(effect))
{
if (effect === 'sliceUpDownLeft')
{
slices = slices.reverse();
}
slices.each(function (slice, i) {
if (i % 2 === 0)
{
slice.setStyle('top', 0);
}
else
{
slice.setStyles({
bottom: 0,
top: ''
});
}
this.animate.delay(100 + timeBuff, this, [slice, {height: this.containerSize.y, opacity: 1}]);
timeBuff += 50;
}, this);
}
else if (['wipeLeft', 'wipeRight'].contains(effect))
{
styles = {
height: this.containerSize.y,
opacity: 1,
width: 0
};
if (effect === 'wipeRight')
{
Object.append(styles, {
backgroundPosition: 'top right',
left: '',
right: 0
});
}
slice = slices[0];
slice.setStyles(styles);
this.animate(slice, {width: this.containerSize.x}, true);
}
// horizontal effects
else if (['sliceLeftUp', 'sliceLeftDown', 'sliceRightDown', 'sliceRightUp'].contains(effect))
{
if (effect === 'sliceLeftUp' || effect === 'sliceRightUp') {
slices = slices.reverse();
}
if (effect === 'sliceRightDown' || effect === 'sliceRightUp') {
slices.setStyles({
left: '',
right: 0
});
} else {
slices.setStyles({
left: 0,
right: ''
});
}
slices.each(function (slice) {
this.animate.delay(100 + timeBuff, this, [slice, {opacity: 1, width: this.containerSize.x}]);
timeBuff += 50;
}, this);
} else if (['sliceLeftRightDown', 'sliceLeftRightUp'].contains(effect)) {
if (effect === 'sliceLeftRightUp') {
slices = slices.reverse();
}
slices.each(function (slice, i) {
if (i % 2 === 0) {
slice.setStyles({
left: 0,
right: ''
});
} else {
slice.setStyles({
left: '',
right: 0
});
}
this.animate.delay(100 + timeBuff, this, [slice, {opacity: 1, width: this.containerSize.x}]);
timeBuff += 50;
}, this);
} else if (['wipeDown', 'wipeUp'].contains(effect)) {
styles = {
height: 0,
opacity: 1,
width: this.containerSize.x
};
if (effect === 'wipeUp')
{
Object.append(styles, {
backgroundPosition: 'bottom left',
bottom: 0,
top: ''
});
}
slice = slices[0];
slice.setStyles(styles);
this.animate(slice, {height: this.containerSize.y}, true);
} else if (['foldDown', 'foldLeft', 'foldRight', 'foldUp'].contains(effect)) {
if (effect === 'foldUp' || effect === 'foldLeft') {
slices.reverse();
}
slices.each(function (slice) {
var fxStyles = {
opacity: 1
};
if (this.orientation === 'horizontal') {
fxStyles.height = slice.getHeight();
slice.setStyles({
height: 0,
width: this.containerSize.x
});
} else {
fxStyles.width= slice.getWidth();
slice.setStyles({
height: this.containerSize.y,
width: 0
});
}
this.animate.delay(100 + timeBuff, this, [slice, fxStyles]);
timeBuff += 50;
}, this);
}
else // if (effect == 'fade')
{
slice = slices[0];
slice.setStyles({
height: this.containerSize.y,
width: this.containerSize.x
});
this.animate(slice, {opacity: 1}, true);
}
},
setBackgroundImage: function () {
this.holder.setStyle('background-image', 'url("' + this.currentImage.get('src') + '")');
},
setCaptionText: function (text)
{
this.caption.set('text', text);
},
setLink: function ()
{
//Set active link
var clone,
imageParent = this.currentImage.getParent();
if (imageParent.get('tag') === 'a') {
clone = imageParent.clone(false).cloneEvents(imageParent);
clone.replaces(this.linkHolder);
this.linkHolder = clone;
this.linkHolder.addClass('nivoo-link').setStyle('display', 'block');
} else {
this.linkHolder.setStyle('display', 'none');
}
},
/**
* Events
*/
finish: function () {
this.fireEvent('finish');
},
lastSlide: function () {
this.fireEvent('lastSlide');
},
start: function () {
this.fireEvent('start');
}
});