668 lines
20 KiB
JavaScript
668 lines
20 KiB
JavaScript
/*!
|
|
* JavaScript Custom Forms : Scrollbar Module
|
|
*
|
|
* Copyright 2014-2015 PSD2HTML - http://psd2html.com/jcf
|
|
* Released under the MIT license (LICENSE.txt)
|
|
*
|
|
* Version: 1.2.1
|
|
*/
|
|
|
|
(function(jcf) {
|
|
|
|
jcf.addModule(function($, window) {
|
|
'use strict';
|
|
|
|
var module = {
|
|
name: 'Scrollable',
|
|
selector: '.jcf-scrollable',
|
|
plugins: {
|
|
ScrollBar: ScrollBar
|
|
},
|
|
options: {
|
|
mouseWheelStep: 150,
|
|
handleResize: true,
|
|
alwaysShowScrollbars: false,
|
|
alwaysPreventMouseWheel: false,
|
|
scrollAreaStructure: '<div class="jcf-scrollable-wrapper"></div>'
|
|
},
|
|
matchElement: function(element) {
|
|
return element.is('.jcf-scrollable');
|
|
},
|
|
init: function() {
|
|
this.initStructure();
|
|
this.attachEvents();
|
|
this.rebuildScrollbars();
|
|
},
|
|
initStructure: function() {
|
|
// prepare structure
|
|
this.doc = $(document);
|
|
this.win = $(window);
|
|
this.realElement = $(this.options.element);
|
|
this.scrollWrapper = $(this.options.scrollAreaStructure).insertAfter(this.realElement);
|
|
|
|
// set initial styles
|
|
this.scrollWrapper.css('position', 'relative');
|
|
this.realElement.css('overflow', 'hidden');
|
|
this.vBarEdge = 0;
|
|
},
|
|
attachEvents: function() {
|
|
// create scrollbars
|
|
var self = this;
|
|
this.vBar = new ScrollBar({
|
|
holder: this.scrollWrapper,
|
|
vertical: true,
|
|
onScroll: function(scrollTop) {
|
|
self.realElement.scrollTop(scrollTop);
|
|
}
|
|
});
|
|
this.hBar = new ScrollBar({
|
|
holder: this.scrollWrapper,
|
|
vertical: false,
|
|
onScroll: function(scrollLeft) {
|
|
self.realElement.scrollLeft(scrollLeft);
|
|
}
|
|
});
|
|
|
|
// add event handlers
|
|
this.realElement.on('scroll', this.onScroll);
|
|
if (this.options.handleResize) {
|
|
this.win.on('resize orientationchange load', this.onResize);
|
|
}
|
|
|
|
// add pointer/wheel event handlers
|
|
this.realElement.on('jcf-mousewheel', this.onMouseWheel);
|
|
this.realElement.on('jcf-pointerdown', this.onTouchBody);
|
|
},
|
|
onScroll: function() {
|
|
this.redrawScrollbars();
|
|
},
|
|
onResize: function() {
|
|
// do not rebuild scrollbars if form field is in focus
|
|
if (!$(document.activeElement).is(':input')) {
|
|
this.rebuildScrollbars();
|
|
}
|
|
},
|
|
onTouchBody: function(e) {
|
|
if (e.pointerType === 'touch') {
|
|
this.touchData = {
|
|
scrollTop: this.realElement.scrollTop(),
|
|
scrollLeft: this.realElement.scrollLeft(),
|
|
left: e.pageX,
|
|
top: e.pageY
|
|
};
|
|
this.doc.on({
|
|
'jcf-pointermove': this.onMoveBody,
|
|
'jcf-pointerup': this.onReleaseBody
|
|
});
|
|
}
|
|
},
|
|
onMoveBody: function(e) {
|
|
var targetScrollTop,
|
|
targetScrollLeft,
|
|
verticalScrollAllowed = this.verticalScrollActive,
|
|
horizontalScrollAllowed = this.horizontalScrollActive;
|
|
|
|
if (e.pointerType === 'touch') {
|
|
targetScrollTop = this.touchData.scrollTop - e.pageY + this.touchData.top;
|
|
targetScrollLeft = this.touchData.scrollLeft - e.pageX + this.touchData.left;
|
|
|
|
// check that scrolling is ended and release outer scrolling
|
|
if (this.verticalScrollActive && (targetScrollTop < 0 || targetScrollTop > this.vBar.maxValue)) {
|
|
verticalScrollAllowed = false;
|
|
}
|
|
if (this.horizontalScrollActive && (targetScrollLeft < 0 || targetScrollLeft > this.hBar.maxValue)) {
|
|
horizontalScrollAllowed = false;
|
|
}
|
|
|
|
this.realElement.scrollTop(targetScrollTop);
|
|
this.realElement.scrollLeft(targetScrollLeft);
|
|
|
|
if (verticalScrollAllowed || horizontalScrollAllowed) {
|
|
e.preventDefault();
|
|
} else {
|
|
this.onReleaseBody(e);
|
|
}
|
|
}
|
|
},
|
|
onReleaseBody: function(e) {
|
|
if (e.pointerType === 'touch') {
|
|
delete this.touchData;
|
|
this.doc.off({
|
|
'jcf-pointermove': this.onMoveBody,
|
|
'jcf-pointerup': this.onReleaseBody
|
|
});
|
|
}
|
|
},
|
|
onMouseWheel: function(e) {
|
|
var currentScrollTop = this.realElement.scrollTop(),
|
|
currentScrollLeft = this.realElement.scrollLeft(),
|
|
maxScrollTop = this.realElement.prop('scrollHeight') - this.embeddedDimensions.innerHeight,
|
|
maxScrollLeft = this.realElement.prop('scrollWidth') - this.embeddedDimensions.innerWidth,
|
|
extraLeft, extraTop, preventFlag;
|
|
|
|
// check edge cases
|
|
if (!this.options.alwaysPreventMouseWheel) {
|
|
if (this.verticalScrollActive && e.deltaY) {
|
|
if (!(currentScrollTop <= 0 && e.deltaY < 0) && !(currentScrollTop >= maxScrollTop && e.deltaY > 0)) {
|
|
preventFlag = true;
|
|
}
|
|
}
|
|
if (this.horizontalScrollActive && e.deltaX) {
|
|
if (!(currentScrollLeft <= 0 && e.deltaX < 0) && !(currentScrollLeft >= maxScrollLeft && e.deltaX > 0)) {
|
|
preventFlag = true;
|
|
}
|
|
}
|
|
if (!this.verticalScrollActive && !this.horizontalScrollActive) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// prevent default action and scroll item
|
|
if (preventFlag || this.options.alwaysPreventMouseWheel) {
|
|
e.preventDefault();
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
extraLeft = e.deltaX / 100 * this.options.mouseWheelStep;
|
|
extraTop = e.deltaY / 100 * this.options.mouseWheelStep;
|
|
|
|
this.realElement.scrollTop(currentScrollTop + extraTop);
|
|
this.realElement.scrollLeft(currentScrollLeft + extraLeft);
|
|
},
|
|
setScrollBarEdge: function(edgeSize) {
|
|
this.vBarEdge = edgeSize || 0;
|
|
this.redrawScrollbars();
|
|
},
|
|
saveElementDimensions: function() {
|
|
this.savedDimensions = {
|
|
top: this.realElement.width(),
|
|
left: this.realElement.height()
|
|
};
|
|
return this;
|
|
},
|
|
restoreElementDimensions: function() {
|
|
if (this.savedDimensions) {
|
|
this.realElement.css({
|
|
width: this.savedDimensions.width,
|
|
height: this.savedDimensions.height
|
|
});
|
|
}
|
|
return this;
|
|
},
|
|
saveScrollOffsets: function() {
|
|
this.savedOffsets = {
|
|
top: this.realElement.scrollTop(),
|
|
left: this.realElement.scrollLeft()
|
|
};
|
|
return this;
|
|
},
|
|
restoreScrollOffsets: function() {
|
|
if (this.savedOffsets) {
|
|
this.realElement.scrollTop(this.savedOffsets.top);
|
|
this.realElement.scrollLeft(this.savedOffsets.left);
|
|
}
|
|
return this;
|
|
},
|
|
getContainerDimensions: function() {
|
|
// save current styles
|
|
var desiredDimensions,
|
|
currentStyles,
|
|
currentHeight,
|
|
currentWidth;
|
|
|
|
if (this.isModifiedStyles) {
|
|
desiredDimensions = {
|
|
width: this.realElement.innerWidth() + this.vBar.getThickness(),
|
|
height: this.realElement.innerHeight() + this.hBar.getThickness()
|
|
};
|
|
} else {
|
|
// unwrap real element and measure it according to CSS
|
|
this.saveElementDimensions().saveScrollOffsets();
|
|
this.realElement.insertAfter(this.scrollWrapper);
|
|
this.scrollWrapper.detach();
|
|
|
|
// measure element
|
|
currentStyles = this.realElement.prop('style');
|
|
currentWidth = parseFloat(currentStyles.width);
|
|
currentHeight = parseFloat(currentStyles.height);
|
|
|
|
// reset styles if needed
|
|
if (this.embeddedDimensions && currentWidth && currentHeight) {
|
|
this.isModifiedStyles |= (currentWidth !== this.embeddedDimensions.width || currentHeight !== this.embeddedDimensions.height);
|
|
this.realElement.css({
|
|
overflow: '',
|
|
width: '',
|
|
height: ''
|
|
});
|
|
}
|
|
|
|
// calculate desired dimensions for real element
|
|
desiredDimensions = {
|
|
width: this.realElement.outerWidth(),
|
|
height: this.realElement.outerHeight()
|
|
};
|
|
|
|
// restore structure and original scroll offsets
|
|
this.scrollWrapper.insertAfter(this.realElement);
|
|
this.realElement.css('overflow', 'hidden').prependTo(this.scrollWrapper);
|
|
this.restoreElementDimensions().restoreScrollOffsets();
|
|
}
|
|
|
|
return desiredDimensions;
|
|
},
|
|
getEmbeddedDimensions: function(dimensions) {
|
|
// handle scrollbars cropping
|
|
var fakeBarWidth = this.vBar.getThickness(),
|
|
fakeBarHeight = this.hBar.getThickness(),
|
|
paddingWidth = this.realElement.outerWidth() - this.realElement.width(),
|
|
paddingHeight = this.realElement.outerHeight() - this.realElement.height(),
|
|
resultDimensions;
|
|
|
|
if (this.options.alwaysShowScrollbars) {
|
|
// simply return dimensions without custom scrollbars
|
|
this.verticalScrollActive = true;
|
|
this.horizontalScrollActive = true;
|
|
resultDimensions = {
|
|
innerWidth: dimensions.width - fakeBarWidth,
|
|
innerHeight: dimensions.height - fakeBarHeight
|
|
};
|
|
} else {
|
|
// detect when to display each scrollbar
|
|
this.saveElementDimensions();
|
|
this.verticalScrollActive = false;
|
|
this.horizontalScrollActive = false;
|
|
|
|
// fill container with full size
|
|
this.realElement.css({
|
|
width: dimensions.width - paddingWidth,
|
|
height: dimensions.height - paddingHeight
|
|
});
|
|
|
|
this.horizontalScrollActive = this.realElement.prop('scrollWidth') > this.containerDimensions.width;
|
|
this.verticalScrollActive = this.realElement.prop('scrollHeight') > this.containerDimensions.height;
|
|
|
|
this.restoreElementDimensions();
|
|
resultDimensions = {
|
|
innerWidth: dimensions.width - (this.verticalScrollActive ? fakeBarWidth : 0),
|
|
innerHeight: dimensions.height - (this.horizontalScrollActive ? fakeBarHeight : 0)
|
|
};
|
|
}
|
|
$.extend(resultDimensions, {
|
|
width: resultDimensions.innerWidth - paddingWidth,
|
|
height: resultDimensions.innerHeight - paddingHeight
|
|
});
|
|
return resultDimensions;
|
|
},
|
|
rebuildScrollbars: function() {
|
|
// resize wrapper according to real element styles
|
|
this.containerDimensions = this.getContainerDimensions();
|
|
this.embeddedDimensions = this.getEmbeddedDimensions(this.containerDimensions);
|
|
|
|
// resize wrapper to desired dimensions
|
|
this.scrollWrapper.css({
|
|
width: this.containerDimensions.width,
|
|
height: this.containerDimensions.height
|
|
});
|
|
|
|
// resize element inside wrapper excluding scrollbar size
|
|
this.realElement.css({
|
|
overflow: 'hidden',
|
|
width: this.embeddedDimensions.width,
|
|
height: this.embeddedDimensions.height
|
|
});
|
|
|
|
// redraw scrollbar offset
|
|
this.redrawScrollbars();
|
|
},
|
|
redrawScrollbars: function() {
|
|
var viewSize, maxScrollValue;
|
|
|
|
// redraw vertical scrollbar
|
|
if (this.verticalScrollActive) {
|
|
viewSize = this.vBarEdge ? this.containerDimensions.height - this.vBarEdge : this.embeddedDimensions.innerHeight;
|
|
maxScrollValue = Math.max(this.realElement.prop('offsetHeight'), this.realElement.prop('scrollHeight')) - this.vBarEdge;
|
|
|
|
this.vBar.show().setMaxValue(maxScrollValue - viewSize).setRatio(viewSize / maxScrollValue).setSize(viewSize);
|
|
this.vBar.setValue(this.realElement.scrollTop());
|
|
} else {
|
|
this.vBar.hide();
|
|
}
|
|
|
|
// redraw horizontal scrollbar
|
|
if (this.horizontalScrollActive) {
|
|
viewSize = this.embeddedDimensions.innerWidth;
|
|
maxScrollValue = this.realElement.prop('scrollWidth');
|
|
|
|
if (maxScrollValue === viewSize) {
|
|
this.horizontalScrollActive = false;
|
|
}
|
|
this.hBar.show().setMaxValue(maxScrollValue - viewSize).setRatio(viewSize / maxScrollValue).setSize(viewSize);
|
|
this.hBar.setValue(this.realElement.scrollLeft());
|
|
} else {
|
|
this.hBar.hide();
|
|
}
|
|
|
|
// set "touch-action" style rule
|
|
var touchAction = '';
|
|
if (this.verticalScrollActive && this.horizontalScrollActive) {
|
|
touchAction = 'none';
|
|
} else if (this.verticalScrollActive) {
|
|
touchAction = 'pan-x';
|
|
} else if (this.horizontalScrollActive) {
|
|
touchAction = 'pan-y';
|
|
}
|
|
this.realElement.css('touchAction', touchAction);
|
|
},
|
|
refresh: function() {
|
|
this.rebuildScrollbars();
|
|
},
|
|
destroy: function() {
|
|
// remove event listeners
|
|
this.win.off('resize orientationchange load', this.onResize);
|
|
this.realElement.off({
|
|
'jcf-mousewheel': this.onMouseWheel,
|
|
'jcf-pointerdown': this.onTouchBody
|
|
});
|
|
this.doc.off({
|
|
'jcf-pointermove': this.onMoveBody,
|
|
'jcf-pointerup': this.onReleaseBody
|
|
});
|
|
|
|
// restore structure
|
|
this.saveScrollOffsets();
|
|
this.vBar.destroy();
|
|
this.hBar.destroy();
|
|
this.realElement.insertAfter(this.scrollWrapper).css({
|
|
touchAction: '',
|
|
overflow: '',
|
|
width: '',
|
|
height: ''
|
|
});
|
|
this.scrollWrapper.remove();
|
|
this.restoreScrollOffsets();
|
|
}
|
|
};
|
|
|
|
// custom scrollbar
|
|
function ScrollBar(options) {
|
|
this.options = $.extend({
|
|
holder: null,
|
|
vertical: true,
|
|
inactiveClass: 'jcf-inactive',
|
|
verticalClass: 'jcf-scrollbar-vertical',
|
|
horizontalClass: 'jcf-scrollbar-horizontal',
|
|
scrollbarStructure: '<div class="jcf-scrollbar"><div class="jcf-scrollbar-dec"></div><div class="jcf-scrollbar-slider"><div class="jcf-scrollbar-handle"></div></div><div class="jcf-scrollbar-inc"></div></div>',
|
|
btnDecSelector: '.jcf-scrollbar-dec',
|
|
btnIncSelector: '.jcf-scrollbar-inc',
|
|
sliderSelector: '.jcf-scrollbar-slider',
|
|
handleSelector: '.jcf-scrollbar-handle',
|
|
scrollInterval: 300,
|
|
scrollStep: 400 // px/sec
|
|
}, options);
|
|
this.init();
|
|
}
|
|
$.extend(ScrollBar.prototype, {
|
|
init: function() {
|
|
this.initStructure();
|
|
this.attachEvents();
|
|
},
|
|
initStructure: function() {
|
|
// define proporties
|
|
this.doc = $(document);
|
|
this.isVertical = !!this.options.vertical;
|
|
this.sizeProperty = this.isVertical ? 'height' : 'width';
|
|
this.fullSizeProperty = this.isVertical ? 'outerHeight' : 'outerWidth';
|
|
this.invertedSizeProperty = this.isVertical ? 'width' : 'height';
|
|
this.thicknessMeasureMethod = 'outer' + this.invertedSizeProperty.charAt(0).toUpperCase() + this.invertedSizeProperty.substr(1);
|
|
this.offsetProperty = this.isVertical ? 'top' : 'left';
|
|
this.offsetEventProperty = this.isVertical ? 'pageY' : 'pageX';
|
|
|
|
// initialize variables
|
|
this.value = this.options.value || 0;
|
|
this.maxValue = this.options.maxValue || 0;
|
|
this.currentSliderSize = 0;
|
|
this.handleSize = 0;
|
|
|
|
// find elements
|
|
this.holder = $(this.options.holder);
|
|
this.scrollbar = $(this.options.scrollbarStructure).appendTo(this.holder);
|
|
this.btnDec = this.scrollbar.find(this.options.btnDecSelector);
|
|
this.btnInc = this.scrollbar.find(this.options.btnIncSelector);
|
|
this.slider = this.scrollbar.find(this.options.sliderSelector);
|
|
this.handle = this.slider.find(this.options.handleSelector);
|
|
|
|
// set initial styles
|
|
this.scrollbar.addClass(this.isVertical ? this.options.verticalClass : this.options.horizontalClass).css({
|
|
touchAction: this.isVertical ? 'pan-x' : 'pan-y',
|
|
position: 'absolute'
|
|
});
|
|
this.slider.css({
|
|
position: 'relative'
|
|
});
|
|
this.handle.css({
|
|
touchAction: 'none',
|
|
position: 'absolute'
|
|
});
|
|
},
|
|
attachEvents: function() {
|
|
this.bindHandlers();
|
|
this.handle.on('jcf-pointerdown', this.onHandlePress);
|
|
this.slider.add(this.btnDec).add(this.btnInc).on('jcf-pointerdown', this.onButtonPress);
|
|
},
|
|
onHandlePress: function(e) {
|
|
if (e.pointerType === 'mouse' && e.button > 1) {
|
|
return;
|
|
} else {
|
|
e.preventDefault();
|
|
this.handleDragActive = true;
|
|
this.sliderOffset = this.slider.offset()[this.offsetProperty];
|
|
this.innerHandleOffset = e[this.offsetEventProperty] - this.handle.offset()[this.offsetProperty];
|
|
|
|
this.doc.on('jcf-pointermove', this.onHandleDrag);
|
|
this.doc.on('jcf-pointerup', this.onHandleRelease);
|
|
}
|
|
},
|
|
onHandleDrag: function(e) {
|
|
e.preventDefault();
|
|
this.calcOffset = e[this.offsetEventProperty] - this.sliderOffset - this.innerHandleOffset;
|
|
this.setValue(this.calcOffset / (this.currentSliderSize - this.handleSize) * this.maxValue);
|
|
this.triggerScrollEvent(this.value);
|
|
},
|
|
onHandleRelease: function() {
|
|
this.handleDragActive = false;
|
|
this.doc.off('jcf-pointermove', this.onHandleDrag);
|
|
this.doc.off('jcf-pointerup', this.onHandleRelease);
|
|
},
|
|
onButtonPress: function(e) {
|
|
var direction, clickOffset;
|
|
if (e.pointerType === 'mouse' && e.button > 1) {
|
|
return;
|
|
} else {
|
|
e.preventDefault();
|
|
if (!this.handleDragActive) {
|
|
if (this.slider.is(e.currentTarget)) {
|
|
// slider pressed
|
|
direction = this.handle.offset()[this.offsetProperty] > e[this.offsetEventProperty] ? -1 : 1;
|
|
clickOffset = e[this.offsetEventProperty] - this.slider.offset()[this.offsetProperty];
|
|
this.startPageScrolling(direction, clickOffset);
|
|
} else {
|
|
// scrollbar buttons pressed
|
|
direction = this.btnDec.is(e.currentTarget) ? -1 : 1;
|
|
this.startSmoothScrolling(direction);
|
|
}
|
|
this.doc.on('jcf-pointerup', this.onButtonRelease);
|
|
}
|
|
}
|
|
},
|
|
onButtonRelease: function() {
|
|
this.stopPageScrolling();
|
|
this.stopSmoothScrolling();
|
|
this.doc.off('jcf-pointerup', this.onButtonRelease);
|
|
},
|
|
startPageScrolling: function(direction, clickOffset) {
|
|
var self = this,
|
|
stepValue = direction * self.currentSize;
|
|
|
|
// limit checker
|
|
var isFinishedScrolling = function() {
|
|
var handleTop = (self.value / self.maxValue) * (self.currentSliderSize - self.handleSize);
|
|
|
|
if (direction > 0) {
|
|
return handleTop + self.handleSize >= clickOffset;
|
|
} else {
|
|
return handleTop <= clickOffset;
|
|
}
|
|
};
|
|
|
|
// scroll by page when track is pressed
|
|
var doPageScroll = function() {
|
|
self.value += stepValue;
|
|
self.setValue(self.value);
|
|
self.triggerScrollEvent(self.value);
|
|
|
|
if (isFinishedScrolling()) {
|
|
clearInterval(self.pageScrollTimer);
|
|
}
|
|
};
|
|
|
|
// start scrolling
|
|
this.pageScrollTimer = setInterval(doPageScroll, this.options.scrollInterval);
|
|
doPageScroll();
|
|
},
|
|
stopPageScrolling: function() {
|
|
clearInterval(this.pageScrollTimer);
|
|
},
|
|
startSmoothScrolling: function(direction) {
|
|
var self = this, dt;
|
|
this.stopSmoothScrolling();
|
|
|
|
// simple animation functions
|
|
var raf = window.requestAnimationFrame || function(func) {
|
|
setTimeout(func, 16);
|
|
};
|
|
var getTimestamp = function() {
|
|
return Date.now ? Date.now() : new Date().getTime();
|
|
};
|
|
|
|
// set animation limit
|
|
var isFinishedScrolling = function() {
|
|
if (direction > 0) {
|
|
return self.value >= self.maxValue;
|
|
} else {
|
|
return self.value <= 0;
|
|
}
|
|
};
|
|
|
|
// animation step
|
|
var doScrollAnimation = function() {
|
|
var stepValue = (getTimestamp() - dt) / 1000 * self.options.scrollStep;
|
|
|
|
if (self.smoothScrollActive) {
|
|
self.value += stepValue * direction;
|
|
self.setValue(self.value);
|
|
self.triggerScrollEvent(self.value);
|
|
|
|
if (!isFinishedScrolling()) {
|
|
dt = getTimestamp();
|
|
raf(doScrollAnimation);
|
|
}
|
|
}
|
|
};
|
|
|
|
// start animation
|
|
self.smoothScrollActive = true;
|
|
dt = getTimestamp();
|
|
raf(doScrollAnimation);
|
|
},
|
|
stopSmoothScrolling: function() {
|
|
this.smoothScrollActive = false;
|
|
},
|
|
triggerScrollEvent: function(scrollValue) {
|
|
if (this.options.onScroll) {
|
|
this.options.onScroll(scrollValue);
|
|
}
|
|
},
|
|
getThickness: function() {
|
|
return this.scrollbar[this.thicknessMeasureMethod]();
|
|
},
|
|
setSize: function(size) {
|
|
// resize scrollbar
|
|
var btnDecSize = this.btnDec[this.fullSizeProperty](),
|
|
btnIncSize = this.btnInc[this.fullSizeProperty]();
|
|
|
|
// resize slider
|
|
this.currentSize = size;
|
|
this.currentSliderSize = size - btnDecSize - btnIncSize;
|
|
this.scrollbar.css(this.sizeProperty, size);
|
|
this.slider.css(this.sizeProperty, this.currentSliderSize);
|
|
this.currentSliderSize = this.slider[this.sizeProperty]();
|
|
|
|
// resize handle
|
|
this.handleSize = Math.round(this.currentSliderSize * this.ratio);
|
|
this.handle.css(this.sizeProperty, this.handleSize);
|
|
this.handleSize = this.handle[this.fullSizeProperty]();
|
|
|
|
return this;
|
|
},
|
|
setRatio: function(ratio) {
|
|
this.ratio = ratio;
|
|
return this;
|
|
},
|
|
setMaxValue: function(maxValue) {
|
|
this.maxValue = maxValue;
|
|
this.setValue(Math.min(this.value, this.maxValue));
|
|
return this;
|
|
},
|
|
setValue: function(value) {
|
|
this.value = value;
|
|
if (this.value < 0) {
|
|
this.value = 0;
|
|
} else if (this.value > this.maxValue) {
|
|
this.value = this.maxValue;
|
|
}
|
|
this.refresh();
|
|
},
|
|
setPosition: function(styles) {
|
|
this.scrollbar.css(styles);
|
|
return this;
|
|
},
|
|
hide: function() {
|
|
this.scrollbar.detach();
|
|
return this;
|
|
},
|
|
show: function() {
|
|
this.scrollbar.appendTo(this.holder);
|
|
return this;
|
|
},
|
|
refresh: function() {
|
|
// recalculate handle position
|
|
if (this.value === 0 || this.maxValue === 0) {
|
|
this.calcOffset = 0;
|
|
} else {
|
|
this.calcOffset = (this.value / this.maxValue) * (this.currentSliderSize - this.handleSize);
|
|
}
|
|
this.handle.css(this.offsetProperty, this.calcOffset);
|
|
|
|
// toggle inactive classes
|
|
this.btnDec.toggleClass(this.options.inactiveClass, this.value === 0);
|
|
this.btnInc.toggleClass(this.options.inactiveClass, this.value === this.maxValue);
|
|
this.scrollbar.toggleClass(this.options.inactiveClass, this.maxValue === 0);
|
|
},
|
|
destroy: function() {
|
|
// remove event handlers and scrollbar block itself
|
|
this.btnDec.add(this.btnInc).off('jcf-pointerdown', this.onButtonPress);
|
|
this.handle.off('jcf-pointerdown', this.onHandlePress);
|
|
this.doc.off('jcf-pointermove', this.onHandleDrag);
|
|
this.doc.off('jcf-pointerup', this.onHandleRelease);
|
|
this.doc.off('jcf-pointerup', this.onButtonRelease);
|
|
this.stopSmoothScrolling();
|
|
this.stopPageScrolling();
|
|
this.scrollbar.remove();
|
|
}
|
|
});
|
|
|
|
return module;
|
|
});
|
|
|
|
}(jcf));
|