Wrap core functionality in an each function

If we have many DOM elements that match the PerfectScrollbar selector,
then all elemets get scrolled if one of them is scrolled.
This commit is contained in:
Ahmad Sherif 2013-05-22 11:48:51 +02:00
parent c6c087275c
commit d5dd3422cf
3 changed files with 288 additions and 286 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,314 +11,316 @@
$.fn.perfectScrollbar = function (suppliedSettings, option) { $.fn.perfectScrollbar = function (suppliedSettings, option) {
// Use the default settings return this.each(function() {
var settings = $.extend(true, {}, defaultSettings); // Use the default settings
if (typeof suppliedSettings === "object") { var settings = $.extend(true, {}, defaultSettings);
// But over-ride any supplied if (typeof suppliedSettings === "object") {
$.extend(true, settings, suppliedSettings); // But over-ride any supplied
} else { $.extend(true, settings, suppliedSettings);
// If no settings were supplied, then the first param must be the option } else {
option = suppliedSettings; // If no settings were supplied, then the first param must be the option
} option = suppliedSettings;
if (option === 'update') {
if ($(this).data('perfect-scrollbar-update')) {
$(this).data('perfect-scrollbar-update')();
}
return $(this);
}
else if (option === 'destroy') {
if ($(this).data('perfect-scrollbar-destroy')) {
$(this).data('perfect-scrollbar-destroy')();
}
return $(this);
}
if ($(this).data('perfect-scrollbar')) {
// if there's already perfect-scrollbar
return $(this).data('perfect-scrollbar');
}
var $this = $(this).addClass('ps-container'),
$content = $(this).children(),
$scrollbarX = $("<div class='ps-scrollbar-x'></div>").appendTo($this),
$scrollbarY = $("<div class='ps-scrollbar-y'></div>").appendTo($this),
containerWidth,
containerHeight,
contentWidth,
contentHeight,
scrollbarXWidth,
scrollbarXLeft,
scrollbarXBottom = parseInt($scrollbarX.css('bottom'), 10),
scrollbarYHeight,
scrollbarYTop,
scrollbarYRight = parseInt($scrollbarY.css('right'), 10);
var updateContentScrollTop = function () {
var scrollTop = parseInt(scrollbarYTop * contentHeight / containerHeight, 10);
$this.scrollTop(scrollTop);
$scrollbarX.css({bottom: scrollbarXBottom - scrollTop});
};
var updateContentScrollLeft = function () {
var scrollLeft = parseInt(scrollbarXLeft * contentWidth / containerWidth, 10);
$this.scrollLeft(scrollLeft);
$scrollbarY.css({right: scrollbarYRight - scrollLeft});
};
var updateBarSizeAndPosition = function () {
containerWidth = $this.width();
containerHeight = $this.height();
contentWidth = $content.outerWidth(false);
contentHeight = $content.outerHeight(false);
if (containerWidth < contentWidth) {
scrollbarXWidth = parseInt(containerWidth * containerWidth / contentWidth, 10);
scrollbarXLeft = parseInt($this.scrollLeft() * containerWidth / contentWidth, 10);
}
else {
scrollbarXWidth = 0;
scrollbarXLeft = 0;
$this.scrollLeft(0);
}
if (containerHeight < contentHeight) {
scrollbarYHeight = parseInt(containerHeight * containerHeight / contentHeight, 10);
scrollbarYTop = parseInt($this.scrollTop() * containerHeight / contentHeight, 10);
}
else {
scrollbarYHeight = 0;
scrollbarYTop = 0;
$this.scrollTop(0);
} }
if (scrollbarYTop >= containerHeight - scrollbarYHeight) { if (option === 'update') {
scrollbarYTop = containerHeight - scrollbarYHeight; if ($(this).data('perfect-scrollbar-update')) {
} $(this).data('perfect-scrollbar-update')();
if (scrollbarXLeft >= containerWidth - scrollbarXWidth) {
scrollbarXLeft = containerWidth - scrollbarXWidth;
}
$scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft(), bottom: scrollbarXBottom - $this.scrollTop(), width: scrollbarXWidth});
$scrollbarY.css({top: scrollbarYTop + $this.scrollTop(), right: scrollbarYRight - $this.scrollLeft(), height: scrollbarYHeight});
};
var moveBarX = function (currentLeft, deltaX) {
var newLeft = currentLeft + deltaX,
maxLeft = containerWidth - scrollbarXWidth;
if (newLeft < 0) {
scrollbarXLeft = 0;
}
else if (newLeft > maxLeft) {
scrollbarXLeft = maxLeft;
}
else {
scrollbarXLeft = newLeft;
}
$scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft()});
};
var moveBarY = function (currentTop, deltaY) {
var newTop = currentTop + deltaY,
maxTop = containerHeight - scrollbarYHeight;
if (newTop < 0) {
scrollbarYTop = 0;
}
else if (newTop > maxTop) {
scrollbarYTop = maxTop;
}
else {
scrollbarYTop = newTop;
}
$scrollbarY.css({top: scrollbarYTop + $this.scrollTop()});
};
var bindMouseScrollXHandler = function () {
var currentLeft,
currentPageX;
$scrollbarX.bind('mousedown.perfect-scroll', function (e) {
currentPageX = e.pageX;
currentLeft = $scrollbarX.position().left;
$scrollbarX.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove.perfect-scroll', function (e) {
if ($scrollbarX.hasClass('in-scrolling')) {
moveBarX(currentLeft, e.pageX - currentPageX);
updateContentScrollLeft();
e.stopPropagation();
e.preventDefault();
} }
}); return $(this);
}
$(document).bind('mouseup.perfect-scroll', function (e) { else if (option === 'destroy') {
if ($scrollbarX.hasClass('in-scrolling')) { if ($(this).data('perfect-scrollbar-destroy')) {
$scrollbarX.removeClass('in-scrolling'); $(this).data('perfect-scrollbar-destroy')();
} }
}); return $(this);
}; }
var bindMouseScrollYHandler = function () { if ($(this).data('perfect-scrollbar')) {
var currentTop, // if there's already perfect-scrollbar
currentPageY; return $(this).data('perfect-scrollbar');
}
$scrollbarY.bind('mousedown.perfect-scroll', function (e) { var $this = $(this).addClass('ps-container'),
currentPageY = e.pageY; $content = $(this).children(),
currentTop = $scrollbarY.position().top; $scrollbarX = $("<div class='ps-scrollbar-x'></div>").appendTo($this),
$scrollbarY.addClass('in-scrolling'); $scrollbarY = $("<div class='ps-scrollbar-y'></div>").appendTo($this),
e.stopPropagation(); containerWidth,
e.preventDefault(); containerHeight,
}); contentWidth,
contentHeight,
scrollbarXWidth,
scrollbarXLeft,
scrollbarXBottom = parseInt($scrollbarX.css('bottom'), 10),
scrollbarYHeight,
scrollbarYTop,
scrollbarYRight = parseInt($scrollbarY.css('right'), 10);
$(document).bind('mousemove.perfect-scroll', function (e) { var updateContentScrollTop = function () {
if ($scrollbarY.hasClass('in-scrolling')) { var scrollTop = parseInt(scrollbarYTop * contentHeight / containerHeight, 10);
moveBarY(currentTop, e.pageY - currentPageY); $this.scrollTop(scrollTop);
updateContentScrollTop(); $scrollbarX.css({bottom: scrollbarXBottom - scrollTop});
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup.perfect-scroll', function (e) {
if ($scrollbarY.hasClass('in-scrolling')) {
$scrollbarY.removeClass('in-scrolling');
}
});
};
// bind handlers
var bindMouseWheelHandler = function () {
var shouldPreventDefault = function (deltaX, deltaY) {
var scrollTop = $this.scrollTop();
if (scrollTop === 0 && deltaY > 0 && deltaX === 0) {
return !settings.wheelPropagation;
}
else if (scrollTop >= contentHeight - containerHeight && deltaY < 0 && deltaX === 0) {
return !settings.wheelPropagation;
}
var scrollLeft = $this.scrollLeft();
if (scrollLeft === 0 && deltaX < 0 && deltaY === 0) {
return !settings.wheelPropagation;
}
else if (scrollLeft >= contentWidth - containerWidth && deltaX > 0 && deltaY === 0) {
return !settings.wheelPropagation;
}
return true;
}; };
$this.mousewheel(function (e, delta, deltaX, deltaY) { var updateContentScrollLeft = function () {
$this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed)); var scrollLeft = parseInt(scrollbarXLeft * contentWidth / containerWidth, 10);
$this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed)); $this.scrollLeft(scrollLeft);
$scrollbarY.css({right: scrollbarYRight - scrollLeft});
// update bar position
updateBarSizeAndPosition();
if (shouldPreventDefault(deltaX, deltaY)) {
e.preventDefault();
}
});
};
// bind mobile touch handler
var bindMobileTouchHandler = function () {
var applyTouchMove = function (differenceX, differenceY) {
$this.scrollTop($this.scrollTop() - differenceY);
$this.scrollLeft($this.scrollLeft() - differenceX);
// update bar position
updateBarSizeAndPosition();
}; };
var startCoords = {}, var updateBarSizeAndPosition = function () {
startTime = 0, containerWidth = $this.width();
speed = {}, containerHeight = $this.height();
breakingProcess = null; contentWidth = $content.outerWidth(false);
contentHeight = $content.outerHeight(false);
$this.bind("touchstart.perfect-scroll", function (e) { if (containerWidth < contentWidth) {
var touch = e.originalEvent.targetTouches[0]; scrollbarXWidth = parseInt(containerWidth * containerWidth / contentWidth, 10);
scrollbarXLeft = parseInt($this.scrollLeft() * containerWidth / contentWidth, 10);
startCoords.pageX = touch.pageX; }
startCoords.pageY = touch.pageY; else {
scrollbarXWidth = 0;
startTime = (new Date()).getTime(); scrollbarXLeft = 0;
$this.scrollLeft(0);
if (breakingProcess !== null) { }
clearInterval(breakingProcess); if (containerHeight < contentHeight) {
scrollbarYHeight = parseInt(containerHeight * containerHeight / contentHeight, 10);
scrollbarYTop = parseInt($this.scrollTop() * containerHeight / contentHeight, 10);
}
else {
scrollbarYHeight = 0;
scrollbarYTop = 0;
$this.scrollTop(0);
} }
});
$this.bind("touchmove.perfect-scroll", function (e) {
var touch = e.originalEvent.targetTouches[0];
var currentCoords = {}; if (scrollbarYTop >= containerHeight - scrollbarYHeight) {
currentCoords.pageX = touch.pageX; scrollbarYTop = containerHeight - scrollbarYHeight;
currentCoords.pageY = touch.pageY; }
if (scrollbarXLeft >= containerWidth - scrollbarXWidth) {
scrollbarXLeft = containerWidth - scrollbarXWidth;
}
var differenceX = currentCoords.pageX - startCoords.pageX, $scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft(), bottom: scrollbarXBottom - $this.scrollTop(), width: scrollbarXWidth});
differenceY = currentCoords.pageY - startCoords.pageY; $scrollbarY.css({top: scrollbarYTop + $this.scrollTop(), right: scrollbarYRight - $this.scrollLeft(), height: scrollbarYHeight});
};
applyTouchMove(differenceX, differenceY); var moveBarX = function (currentLeft, deltaX) {
startCoords = currentCoords; var newLeft = currentLeft + deltaX,
maxLeft = containerWidth - scrollbarXWidth;
var currentTime = (new Date()).getTime(); if (newLeft < 0) {
speed.x = differenceX / (currentTime - startTime); scrollbarXLeft = 0;
speed.y = differenceY / (currentTime - startTime); }
startTime = currentTime; else if (newLeft > maxLeft) {
scrollbarXLeft = maxLeft;
}
else {
scrollbarXLeft = newLeft;
}
$scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft()});
};
e.preventDefault(); var moveBarY = function (currentTop, deltaY) {
}); var newTop = currentTop + deltaY,
$this.bind("touchend.perfect-scroll", function (e) { maxTop = containerHeight - scrollbarYHeight;
breakingProcess = setInterval(function () {
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) { if (newTop < 0) {
clearInterval(breakingProcess); scrollbarYTop = 0;
return; }
else if (newTop > maxTop) {
scrollbarYTop = maxTop;
}
else {
scrollbarYTop = newTop;
}
$scrollbarY.css({top: scrollbarYTop + $this.scrollTop()});
};
var bindMouseScrollXHandler = function () {
var currentLeft,
currentPageX;
$scrollbarX.bind('mousedown.perfect-scroll', function (e) {
currentPageX = e.pageX;
currentLeft = $scrollbarX.position().left;
$scrollbarX.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove.perfect-scroll', function (e) {
if ($scrollbarX.hasClass('in-scrolling')) {
moveBarX(currentLeft, e.pageX - currentPageX);
updateContentScrollLeft();
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup.perfect-scroll', function (e) {
if ($scrollbarX.hasClass('in-scrolling')) {
$scrollbarX.removeClass('in-scrolling');
}
});
};
var bindMouseScrollYHandler = function () {
var currentTop,
currentPageY;
$scrollbarY.bind('mousedown.perfect-scroll', function (e) {
currentPageY = e.pageY;
currentTop = $scrollbarY.position().top;
$scrollbarY.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove.perfect-scroll', function (e) {
if ($scrollbarY.hasClass('in-scrolling')) {
moveBarY(currentTop, e.pageY - currentPageY);
updateContentScrollTop();
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup.perfect-scroll', function (e) {
if ($scrollbarY.hasClass('in-scrolling')) {
$scrollbarY.removeClass('in-scrolling');
}
});
};
// bind handlers
var bindMouseWheelHandler = function () {
var shouldPreventDefault = function (deltaX, deltaY) {
var scrollTop = $this.scrollTop();
if (scrollTop === 0 && deltaY > 0 && deltaX === 0) {
return !settings.wheelPropagation;
}
else if (scrollTop >= contentHeight - containerHeight && deltaY < 0 && deltaX === 0) {
return !settings.wheelPropagation;
} }
applyTouchMove(speed.x * 30, speed.y * 30); var scrollLeft = $this.scrollLeft();
if (scrollLeft === 0 && deltaX < 0 && deltaY === 0) {
return !settings.wheelPropagation;
}
else if (scrollLeft >= contentWidth - containerWidth && deltaX > 0 && deltaY === 0) {
return !settings.wheelPropagation;
}
return true;
};
speed.x *= 0.8; $this.mousewheel(function (e, delta, deltaX, deltaY) {
speed.y *= 0.8; $this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed));
}, 10); $this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed));
});
};
var destroy = function () { // update bar position
$scrollbarX.remove(); updateBarSizeAndPosition();
$scrollbarY.remove();
$this.unbind('mousewheel');
$this.unbind('touchstart.perfect-scroll');
$this.unbind('touchmove.perfect-scroll');
$this.unbind('touchend.perfect-scroll');
$(window).unbind('mousemove.perfect-scroll');
$(window).unbind('mouseup.perfect-scroll');
$this.data('perfect-scrollbar', null);
$this.data('perfect-scrollbar-update', null);
$this.data('perfect-scrollbar-destroy', null);
};
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); if (shouldPreventDefault(deltaX, deltaY)) {
e.preventDefault();
}
});
};
var initialize = function () { // bind mobile touch handler
updateBarSizeAndPosition(); var bindMobileTouchHandler = function () {
bindMouseScrollXHandler(); var applyTouchMove = function (differenceX, differenceY) {
bindMouseScrollYHandler(); $this.scrollTop($this.scrollTop() - differenceY);
if (isMobile) { $this.scrollLeft($this.scrollLeft() - differenceX);
bindMobileTouchHandler();
}
if ($this.mousewheel) {
bindMouseWheelHandler();
}
$this.data('perfect-scrollbar', $this);
$this.data('perfect-scrollbar-update', updateBarSizeAndPosition);
$this.data('perfect-scrollbar-destroy', destroy);
};
// initialize // update bar position
initialize(); updateBarSizeAndPosition();
};
return $this; var startCoords = {},
startTime = 0,
speed = {},
breakingProcess = null;
$this.bind("touchstart.perfect-scroll", function (e) {
var touch = e.originalEvent.targetTouches[0];
startCoords.pageX = touch.pageX;
startCoords.pageY = touch.pageY;
startTime = (new Date()).getTime();
if (breakingProcess !== null) {
clearInterval(breakingProcess);
}
});
$this.bind("touchmove.perfect-scroll", function (e) {
var touch = e.originalEvent.targetTouches[0];
var currentCoords = {};
currentCoords.pageX = touch.pageX;
currentCoords.pageY = touch.pageY;
var differenceX = currentCoords.pageX - startCoords.pageX,
differenceY = currentCoords.pageY - startCoords.pageY;
applyTouchMove(differenceX, differenceY);
startCoords = currentCoords;
var currentTime = (new Date()).getTime();
speed.x = differenceX / (currentTime - startTime);
speed.y = differenceY / (currentTime - startTime);
startTime = currentTime;
e.preventDefault();
});
$this.bind("touchend.perfect-scroll", function (e) {
breakingProcess = setInterval(function () {
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
clearInterval(breakingProcess);
return;
}
applyTouchMove(speed.x * 30, speed.y * 30);
speed.x *= 0.8;
speed.y *= 0.8;
}, 10);
});
};
var destroy = function () {
$scrollbarX.remove();
$scrollbarY.remove();
$this.unbind('mousewheel');
$this.unbind('touchstart.perfect-scroll');
$this.unbind('touchmove.perfect-scroll');
$this.unbind('touchend.perfect-scroll');
$(window).unbind('mousemove.perfect-scroll');
$(window).unbind('mouseup.perfect-scroll');
$this.data('perfect-scrollbar', null);
$this.data('perfect-scrollbar-update', null);
$this.data('perfect-scrollbar-destroy', null);
};
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var initialize = function () {
updateBarSizeAndPosition();
bindMouseScrollXHandler();
bindMouseScrollYHandler();
if (isMobile) {
bindMobileTouchHandler();
}
if ($this.mousewheel) {
bindMouseWheelHandler();
}
$this.data('perfect-scrollbar', $this);
$this.data('perfect-scrollbar-update', updateBarSizeAndPosition);
$this.data('perfect-scrollbar-destroy', destroy);
};
// initialize
initialize();
return $this;
});
}; };
})(jQuery)); })(jQuery));