jQuery Touchwipe Plugin с вертикальной прокруткой

Это моя первая запись, связанная непосредственно с работой.

На днях столкнулся с проблемой — нужно было переделать lightbox с горизонтальной каруселью (модифицированный каким-то программистом плагин jQuery Touchwipe Plugin) в вертикальную. Решал эту проблему полтора дня. И как оказалось — все довольно просто. Мой коллега вычленил из огромного кода кусок, отвечающий за прокрутку изображений, а я уже в этом куске нашел 2 строчки, на которые раньше не обратил внимания. Ниже представляю код работающего скрипта, который нужно вставить в файл с расширением .js и подключить к сайту:
[рhp]

(function( window, $, undefined ) {

$.fn.touchwipe = function(settings) {

var config = {

min_move_x: 20,

min_move_y: 20,

wipeLeft: function() { },

wipeRight: function() { },

wipeUp: function() { },

wipeDown: function() { },

preventDefaultEvents: true

};

 

if (settings) $.extend(config, settings);

 

this.each(function() {

var startX;

var startY;

var isMoving = false;

 

function cancelTouch() {

this.removeEventListener(‘touchmove’, onTouchMove);

startX = null;

isMoving = false;

}

 

function onTouchMove(e) {

if(config.preventDefaultEvents) {

e.preventDefault();

}

if(isMoving) {

var x = e.touches[0].pageX;

var y = e.touches[0].pageY;

var dx = startX — x;

var dy = startY — y;

if(Math.abs(dx) >= config.min_move_x) {

cancelTouch();

if(dx > 0) {

config.wipeLeft();

}

else {

config.wipeRight();

}

}

else if(Math.abs(dy) >= config.min_move_y) {

cancelTouch();

if(dy > 0) {

config.wipeDown();

}

else {

config.wipeUp();

}

}

}

}

 

function onTouchStart(e)

{

if (e.touches.length == 1) {

startX = e.touches[0].pageX;

startY = e.touches[0].pageY;

isMoving = true;

this.addEventListener(‘touchmove’, onTouchMove, false);

}

}

if (‘ontouchstart’ in document.documentElement) {

this.addEventListener(‘touchstart’, onTouchStart, false);

}

});

 

return this;

};

 

$.elastislide = function( options, element ) {

this.$el = $( element );

this._init( options );

};

 

$.elastislide.defaults = {

speed : 450, // animation speed

easing : », // animation easing effect

imageW : 190, // the images width

margin : 3, // image margin right

border : 2, // image border

minItems : 1, // the minimum number of items to show.

// when we resize the window, this will make sure minItems are always shown

// (unless of course minItems is higher than the total number of elements)

current : 0, // index of the current item

// when we resize the window, the carousel will make sure this item is visible

onClick : function() { return false; } // click item callback

};

 

$.elastislide.prototype = {

_init : function( options ) {

 

this.options = $.extend( true, {}, $.elastislide.defaults, options );

 

// <ul>

this.$slider = this.$el.find(‘ul’);

 

// <li>

this.$items = this.$slider.children(‘li’);

 

// total number of elements / images

this.itemsCount = this.$items.length;

 

// cache the <ul>’s parent, since we will eventually need to recalculate its width on window resize

this.$esCarousel = this.$slider.parent();

 

// validate options

this._validateOptions();

 

// set sizes and initialize some vars…

this._configure();

 

// add navigation buttons

this._addControls();

 

// initialize the events

this._initEvents();

 

// show the <ul>

this.$slider.show();

 

// slide to current’s position

this._slideToCurrent( false );

 

},

_validateOptions : function() {

 

if( this.options.speed < 0 )

this.options.speed = 450;

if( this.options.margin < 0 )

this.options.margin = 4;

if( this.options.border < 0 )

this.options.border = 1;

if( this.options.minItems < 1 || this.options.minItems > this.itemsCount )

this.options.minItems = 1;

if( this.options.current > this.itemsCount — 1 )

this.options.current = 0;

 

},

_configure : function() {

 

// current item’s index

this.current = this.options.current;

 

// the ul’s parent’s (div.es-carousel) width is the «visible» width

this.visibleWidth = this.$esCarousel.width();

 

// test to see if we need to initially resize the items

if( this.visibleWidth < this.options.minItems * ( this.options.imageW + 2 * this.options.border ) + ( this.options.minItems — 1 ) * this.options.margin ) {

this._setDim( ( this.visibleWidth — ( this.options.minItems — 1 ) * this.options.margin ) / this.options.minItems );

this._setCurrentValues();

// how many items fit with the current width

this.fitCount = this.options.minItems;

}

else {

this._setDim();

this._setCurrentValues();

}

 

// set the <ul> width

this.$slider.css({

width : this.sliderW

});

 

},

_setDim : function( elW ) {

 

// <li> style

this.$items.css({

marginRight : this.options.margin,

width : ( elW ) ? elW : this.options.imageW + 2 * this.options.border

}).children(‘a’).css({ // <a> style

borderWidth : this.options.border

});

 

},

_setCurrentValues : function() {

 

// the total space occupied by one item

this.itemW = this.$items.outerWidth(true);

 

// total width of the slider / <ul>

// this will eventually change on window resize

this.sliderW = this.itemW * this.itemsCount;

 

// the ul parent’s (div.es-carousel) width is the «visible» width

this.visibleWidth = this.$esCarousel.width();

 

// how many items fit with the current width

this.fitCount = Math.floor( this.visibleWidth / this.itemW );

 

},

_addControls : function() {

 

this.$navNext = $(‘<span>Next</span>’);

this.$navPrev = $(‘<span>Previous</span>’);

$(‘<div/>’)

.append( this.$navPrev )

.append( this.$navNext )

.appendTo( this.$el );

 

//this._toggleControls();

 

},

_toggleControls : function( dir, status ) {

 

// show / hide navigation buttons

if( dir && status ) {

if( status === 1 )

( dir === ‘right’ ) ? this.$navNext.show() : this.$navPrev.show();

else

( dir === ‘right’ ) ? this.$navNext.hide() : this.$navPrev.hide();

}

else if( this.current === this.itemsCount — 1 || this.fitCount >= this.itemsCount )

this.$navNext.hide();

 

},

_initEvents : function() {

var instance = this;

 

$(‘.small-picts a img’).click(function(e) {

var code = $(this).parent().parent().data(‘pict’);

$item = $(«ul»).find(«[data-bigpict='» + code +»‘]»);

idx = $item.parent().children().index($item);

if(idx >= 0) {

instance.current = idx;

instance._setCurrentValues();

clearTimeout( instance.resetTimeout );

instance.resetTimeout = setTimeout(function() {

instance._slideToCurrent();

}, 200);

}

return false;

});

// window resize

$(window).bind(‘resize.elastislide’, function( event ) {

 

// set values again

instance._setCurrentValues();

 

// need to resize items

if( instance.visibleWidth < instance.options.minItems * ( instance.options.imageW + 2 * instance.options.border ) + ( instance.options.minItems — 1 ) * instance.options.margin ) {

instance._setDim( ( instance.visibleWidth — ( instance.options.minItems — 1 ) * instance.options.margin ) / instance.options.minItems );

instance._setCurrentValues();

instance.fitCount = instance.options.minItems;

}

else{

instance._setDim();

instance._setCurrentValues();

}

 

instance.$slider.css({

width : instance.sliderW + 10 // TODO: +10px seems to solve a firefox «bug» :S

});

 

// slide to the current element

clearTimeout( instance.resetTimeout );

instance.resetTimeout = setTimeout(function() {

instance._slideToCurrent();

}, 200);

 

});

 

// navigation buttons events

this.$navNext.bind(‘click.elastislide’, function( event ) {

instance._slide(‘right’);

});

 

this.$navPrev.bind(‘click.elastislide’, function( event ) {

instance._slide(‘left’);

});

 

// item click event

this.$items.bind(‘click.elastislide’, function( event ) {

instance.options.onClick( $(this) );

return false;

});

 

// touch events

instance.$slider.touchwipe({

wipeLeft : function() {

instance._slide(‘right’);

},

wipeRight : function() {

instance._slide(‘left’);

}

});

 

},

_slide : function( dir, val, anim, callback ) {

 

// if animating return

if( this.$slider.is(‘:animated’) )

return false;

 

// current margin left

var ml = parseFloat( this.$slider.css(‘margin-top’) );

 

// val is just passed when we want an exact value for the margin left (used in the _slideToCurrent function)

if( val === undefined ) {

 

// how much to slide?

//var amount = this.fitCount * this.itemW, val;

var amount = this.itemW;//FIXME

 

if( amount < 0 ) return false;

 

// make sure not to leave a space between the last item / first item and the end / beggining of the slider available width

if( dir === ‘right’ && this.sliderW — ( Math.abs( ml ) + amount ) < this.visibleWidth ) {

amount = this.sliderW — ( Math.abs( ml ) + this.visibleWidth ) — this.options.margin; // decrease the margin left

// show / hide navigation buttons

this._toggleControls( ‘right’, -1 );

this._toggleControls( ‘left’, 1 );

}

else if( dir === ‘left’ && Math.abs( ml ) — amount < 0 ) {

amount = Math.abs( ml );

// show / hide navigation buttons

this._toggleControls( ‘left’, -1 );

this._toggleControls( ‘right’, 1 );

}

else {

var fml; // future margin left

( dir === ‘right’ )

? fml = Math.abs( ml ) + this.options.margin + Math.abs( amount )

: fml = Math.abs( ml ) — this.options.margin — Math.abs( amount );

 

// show / hide navigation buttons

if( fml > 0 )

this._toggleControls( ‘left’, 1 );

else

this._toggleControls( ‘left’, -1 );

 

if( fml < this.sliderW — this.visibleWidth )

this._toggleControls( ‘right’, 1 );

else

this._toggleControls( ‘right’, -1 );

 

}

 

( dir === ‘right’ ) ? val = ‘-=’ + amount : val = ‘+=’ + amount

 

}

else {

var fml = Math.abs( val ); // future margin left

 

if( Math.max( this.sliderW, this.visibleWidth ) — fml < this.visibleWidth ) {

val = — ( Math.max( this.sliderW, this.visibleWidth ) — this.visibleWidth );

if( val !== 0 )

val += this.options.margin; // decrease the margin left if not on the first position

 

// show / hide navigation buttons

this._toggleControls( ‘right’, -1 );

fml = Math.abs( val );

}

 

// show / hide navigation buttons

if( fml > 0 )

this._toggleControls( ‘left’, 1 );

else

this._toggleControls( ‘left’, -1 );

 

if( Math.max( this.sliderW, this.visibleWidth ) — this.visibleWidth > fml + this.options.margin )

this._toggleControls( ‘right’, 1 );

else

this._toggleControls( ‘right’, -1 );

 

}

 

$.fn.applyStyle = ( anim === undefined ) ? $.fn.animate : $.fn.css;

 

var sliderCSS = { marginTop : val };

 

var instance = this;

 

this.$slider.applyStyle( sliderCSS, $.extend( true, [], { duration : this.options.speed, easing : this.options.easing, complete : function() {

if( callback ) callback.call();

} } ) );

 

},

_slideToCurrent : function( anim ) {

 

// how much to slide?

var amount = this.current * this.itemW;

this._slide(», -amount, anim );

 

},

add : function( $newelems, callback ) {

 

// adds new items to the carousel

this.$items = this.$items.add( $newelems );

this.itemsCount = this.$items.length;

this._setDim();

this._setCurrentValues();

this.$slider.css({

width : this.sliderW

});

this._slideToCurrent();

 

if ( callback ) callback.call( $newelems );

 

},

destroy : function( callback ) {

this._destroy( callback );

},

_destroy : function( callback ) {

this.$el.unbind(‘.elastislide’).removeData(‘elastislide’);

$(window).unbind(‘.elastislide’);

if ( callback ) callback.call();

}

};

 

var logError = function( message ) {

if ( this.console ) {

console.error( message );

}

};

 

$.fn.elastislide = function( options ) {

if ( typeof options === ‘string’ ) {

var args = Array.prototype.slice.call( arguments, 1 );

 

this.each(function() {

var instance = $.data( this, ‘elastislide’ );

if ( !instance ) {

logError( «cannot call methods on elastislide prior to initialization; » +

«attempted to call method ‘» + options + «‘» );

return;

}

if ( !$.isFunction( instance[options] ) || options.charAt(0) === «_» ) {

logError( «no such method ‘» + options + «‘ for elastislide instance» );

return;

}

instance[ options ].apply( instance, args );

});

}

else {

this.each(function() {

var instance = $.data( this, ‘elastislide’ );

if ( !instance ) {

$.data( this, ‘elastislide’, new $.elastislide( options, this ) );

}

});

}

return this;

};

})( window, jQuery );
)( window, jQuery );
[/рhp]

😡
☹️
😐
☺️
😍

Добавить комментарий

Ваш e-mail не будет опубликован.