780 lines
18 KiB
JavaScript
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');
|
|
}
|
|
|
|
}); |