Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2b66c76ad | ||
|
|
85009c34cd | ||
|
|
7e39eb3d68 | ||
|
|
085cd7abdd | ||
|
|
6edd7a183c | ||
|
|
735c6c0bf3 | ||
|
|
553756b346 | ||
|
|
4707acc287 | ||
|
|
5f0a423128 | ||
|
|
6d2c6ac8ec | ||
|
|
d1340f1b85 | ||
|
|
4a988b5a21 | ||
|
|
1a39d76e48 | ||
|
|
9fc34100df | ||
|
|
d74bdcccec | ||
|
|
5f34edc8c7 | ||
|
|
ce3a199cb3 | ||
|
|
9c485584b9 | ||
|
|
d5db8ca18e | ||
|
|
89174ed99f | ||
|
|
6e7e3f94fa | ||
|
|
7d61475e1d | ||
|
|
2f8daae695 | ||
|
|
5ce0d77f87 | ||
|
|
f811bbcab5 | ||
|
|
4593eb9115 | ||
|
|
b3b1bc2454 | ||
|
|
25e5be13ff | ||
|
|
f683b01959 | ||
|
|
6d2f203441 | ||
|
|
a4808f662e | ||
|
|
98fa15167a | ||
|
|
06929ae685 | ||
|
|
aa63ff0370 | ||
|
|
c7ddde69c2 | ||
|
|
69e3fb2688 | ||
|
|
fad7f8b4a6 | ||
|
|
0deb4c9bc7 | ||
|
|
11fcd09a99 | ||
|
|
0fc5c69b3f | ||
|
|
898928b686 | ||
|
|
ce7146121f | ||
|
|
908cee5490 | ||
|
|
b3880ca638 | ||
|
|
7123891d4d | ||
|
|
4c00a7fdb9 | ||
|
|
3719dd614c | ||
|
|
68dbc427ea | ||
|
|
34135d6ef0 | ||
|
|
0ab95f2d57 | ||
|
|
985980a892 | ||
|
|
fdc8d64fd9 | ||
|
|
26852236cc | ||
|
|
e0510b5fad | ||
|
|
838ccbba77 | ||
|
|
4198b23231 | ||
|
|
3eb2a49109 | ||
|
|
1b2c853972 | ||
|
|
e9d7cc97c8 | ||
|
|
9016f207e9 |
@@ -1,6 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.12
|
||||
- 4
|
||||
deploy:
|
||||
provider: releases
|
||||
|
||||
49
README.md
49
README.md
@@ -106,23 +106,27 @@ You can fork the following JSFiddles for testing and experimenting purposes:
|
||||
* [Perfect Scrollbar](https://jsfiddle.net/DanielApt/xv0rrxv3/)
|
||||
* [Perfect Scrollbar (jQuery)](https://jsfiddle.net/DanielApt/gbfLazpx/)
|
||||
|
||||
## Requirements
|
||||
|
||||
To make this plugin *perfect*, some requirements were unavoidable.
|
||||
But, they're all very trivial and there is nothing to worry about.
|
||||
## Before using perfect-scrollbar
|
||||
|
||||
The following requirements should meet.
|
||||
|
||||
* the container must have a 'position' css style.
|
||||
* the container must be a normal container element.
|
||||
* PS may not work well in `body`, `textarea`, `iframe` or flexbox.
|
||||
|
||||
The following requirements are included in the basic CSS, but please
|
||||
keep in mind when you'd like to change the CSS files.
|
||||
|
||||
* the container must have an 'overflow:hidden' css style.
|
||||
* the container must have an 'overflow: hidden' css style.
|
||||
* the scrollbar's position must be 'absolute'.
|
||||
* the scrollbar-x must have a 'bottom' css style, and the scrollbar-y
|
||||
must have a 'right' css style.
|
||||
|
||||
Please keep in mind that perfect-scrollbar won't completely emulate native
|
||||
scrolls. Scroll hooking is generally considered as bad practice, and
|
||||
perfect-scrollbar should be used with care. Unless custom scroll is really needed,
|
||||
please consider using native scrolls.
|
||||
|
||||
## How to use
|
||||
|
||||
First of all, please check if the container element meets the
|
||||
@@ -284,56 +288,56 @@ imgLoader.perfectScrollbar();
|
||||
perfect-scrollbar supports optional parameters.
|
||||
|
||||
### handlers
|
||||
It is a list of handlers to use to scroll the element.
|
||||
**Default**: `['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch']`
|
||||
It is a list of handlers to use to scroll the element.
|
||||
**Default**: `['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch']`
|
||||
**Disabled by default**: `'selection'`
|
||||
|
||||
### wheelSpeed
|
||||
The scroll speed applied to mousewheel event.
|
||||
The scroll speed applied to mousewheel event.
|
||||
**Default**: `1`
|
||||
|
||||
### wheelPropagation
|
||||
If this option is true, when the scroll reaches the end of the side, mousewheel event will be propagated to parent element.
|
||||
If this option is true, when the scroll reaches the end of the side, mousewheel event will be propagated to parent element.
|
||||
**Default**: `false`
|
||||
|
||||
### swipePropagation
|
||||
If this option is true, when the scroll reaches the end of the side, touch scrolling will be propagated to parent element.
|
||||
If this option is true, when the scroll reaches the end of the side, touch scrolling will be propagated to parent element.
|
||||
**Default**: `true`
|
||||
|
||||
### minScrollbarLength
|
||||
When set to an integer value, the thumb part of the scrollbar will not shrink below that number of pixels.
|
||||
When set to an integer value, the thumb part of the scrollbar will not shrink below that number of pixels.
|
||||
**Default**: `null`
|
||||
|
||||
### maxScrollbarLength
|
||||
When set to an integer value, the thumb part of the scrollbar will not expand over that number of pixels.
|
||||
When set to an integer value, the thumb part of the scrollbar will not expand over that number of pixels.
|
||||
**Default**: `null`
|
||||
|
||||
### useBothWheelAxes
|
||||
When set to true, and only one (vertical or horizontal) scrollbar is visible then both vertical and horizontal scrolling will affect the scrollbar.
|
||||
When set to true, and only one (vertical or horizontal) scrollbar is visible then both vertical and horizontal scrolling will affect the scrollbar.
|
||||
**Default**: `false`
|
||||
|
||||
### suppressScrollX
|
||||
When set to true, the scroll bar in X axis will not be available, regardless of the content width.
|
||||
When set to true, the scroll bar in X axis will not be available, regardless of the content width.
|
||||
**Default**: `false`
|
||||
|
||||
### suppressScrollY
|
||||
When set to true, the scroll bar in Y axis will not be available, regardless of the content height.
|
||||
When set to true, the scroll bar in Y axis will not be available, regardless of the content height.
|
||||
**Default**: `false`
|
||||
|
||||
### scrollXMarginOffset
|
||||
The number of pixels the content width can surpass the container width without enabling the X axis scroll bar. Allows some "wiggle room" or "offset break", so that X axis scroll bar is not enabled just because of a few pixels.
|
||||
The number of pixels the content width can surpass the container width without enabling the X axis scroll bar. Allows some "wiggle room" or "offset break", so that X axis scroll bar is not enabled just because of a few pixels.
|
||||
**Default**: `0`
|
||||
|
||||
### scrollYMarginOffset
|
||||
The number of pixels the content height can surpass the container height without enabling the Y axis scroll bar. Allows some "wiggle room" or "offset break", so that Y axis scroll bar is not enabled just because of a few pixels.
|
||||
The number of pixels the content height can surpass the container height without enabling the Y axis scroll bar. Allows some "wiggle room" or "offset break", so that Y axis scroll bar is not enabled just because of a few pixels.
|
||||
**Default**: `0`
|
||||
|
||||
### stopPropagationOnClick
|
||||
When set to false, when clicking on a rail, the click event will be allowed to propagate.
|
||||
### autoupdate
|
||||
When set to true, the scroll will be updated when an element is added or removed from the content.
|
||||
**Default**: `true`
|
||||
|
||||
### theme
|
||||
A string. It's a class name added to the container element. The class name is prepended with `ps-theme-`. So default theme class name is `ps-theme-default`. In order to create custom themes with scss use `ps-container($theme)` mixin, where `$theme` is a scss map.
|
||||
A string. It's a class name added to the container element. The class name is prepended with `ps-theme-`. So default theme class name is `ps-theme-default`. In order to create custom themes with scss use `ps-container($theme)` mixin, where `$theme` is a scss map.
|
||||
**Default**: `'default'`
|
||||
|
||||
**Example 1:**
|
||||
@@ -396,6 +400,9 @@ This event fires when scrolling reaches the start of the x-axis.
|
||||
### ps-x-reach-end
|
||||
This event fires when scrolling reaches the end of the x-axis.
|
||||
|
||||
### ps-dom-change
|
||||
This event fires when dom elements have been added to or removed from the content.
|
||||
|
||||
You can listen to these events either with vanilla JavaScript
|
||||
```javascript
|
||||
document.addEventListener('ps-scroll-x', function () {
|
||||
@@ -413,7 +420,7 @@ $(document).on('ps-scroll-x', function () {
|
||||
|
||||
### Scrolling children inside perfect-scrollbar
|
||||
|
||||
You can natively scroll children inside `perfect-scrollbar` with the mouse-wheel. Scrolling automatically works if
|
||||
You can natively scroll children inside `perfect-scrollbar` with the mouse-wheel. Scrolling automatically works if
|
||||
the child is a `textarea`. All other elements need to have the `ps-child` class. This is demonstrated in [`/examples/children-native-scroll.html`](examples/children-native-scroll.html)
|
||||
|
||||
## IE Support
|
||||
|
||||
190
examples/custom-theme.css
Normal file
190
examples/custom-theme.css
Normal file
@@ -0,0 +1,190 @@
|
||||
.ps-container {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
overflow: hidden !important;
|
||||
-ms-overflow-style: none; }
|
||||
@supports (-ms-overflow-style: none) {
|
||||
.ps-container {
|
||||
overflow: auto !important; } }
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
.ps-container {
|
||||
overflow: auto !important; } }
|
||||
.ps-container.ps-active-x > .ps-scrollbar-x-rail,
|
||||
.ps-container.ps-active-y > .ps-scrollbar-y-rail {
|
||||
display: block;
|
||||
background-color: transparent; }
|
||||
.ps-container.ps-in-scrolling {
|
||||
pointer-events: none; }
|
||||
.ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||
background-color: #999; }
|
||||
.ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||
background-color: #999; }
|
||||
.ps-container > .ps-scrollbar-x-rail {
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
opacity: 0;
|
||||
transition: background-color .2s linear, opacity .2s linear;
|
||||
bottom: 0px;
|
||||
/* there must be 'bottom' for ps-scrollbar-x-rail */
|
||||
height: 15px; }
|
||||
.ps-container > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
background-color: #aaa;
|
||||
border-radius: 6px;
|
||||
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||
bottom: 2px;
|
||||
/* there must be 'bottom' for ps-scrollbar-x */
|
||||
height: 6px; }
|
||||
.ps-container > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x, .ps-container > .ps-scrollbar-x-rail:active > .ps-scrollbar-x {
|
||||
height: 11px; }
|
||||
.ps-container > .ps-scrollbar-y-rail {
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
opacity: 0;
|
||||
transition: background-color .2s linear, opacity .2s linear;
|
||||
right: 0;
|
||||
/* there must be 'right' for ps-scrollbar-y-rail */
|
||||
width: 15px; }
|
||||
.ps-container > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
background-color: #aaa;
|
||||
border-radius: 6px;
|
||||
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||
right: 2px;
|
||||
/* there must be 'right' for ps-scrollbar-y */
|
||||
width: 6px; }
|
||||
.ps-container > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y, .ps-container > .ps-scrollbar-y-rail:active > .ps-scrollbar-y {
|
||||
width: 11px; }
|
||||
.ps-container:hover.ps-in-scrolling {
|
||||
pointer-events: none; }
|
||||
.ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||
background-color: #999; }
|
||||
.ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||
background-color: #999; }
|
||||
.ps-container:hover > .ps-scrollbar-x-rail,
|
||||
.ps-container:hover > .ps-scrollbar-y-rail {
|
||||
opacity: 0.6; }
|
||||
.ps-container:hover > .ps-scrollbar-x-rail:hover {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-container:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x {
|
||||
background-color: #999; }
|
||||
.ps-container:hover > .ps-scrollbar-y-rail:hover {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-container:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y {
|
||||
background-color: #999; }
|
||||
|
||||
/*
|
||||
this file is built into custom-theme.css
|
||||
|
||||
$ node-sass examples/custom-theme.scss -o examples/
|
||||
*/
|
||||
.ps-theme-square {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
overflow: hidden !important;
|
||||
-ms-overflow-style: none; }
|
||||
@supports (-ms-overflow-style: none) {
|
||||
.ps-theme-square {
|
||||
overflow: auto !important; } }
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
.ps-theme-square {
|
||||
overflow: auto !important; } }
|
||||
.ps-theme-square.ps-active-x > .ps-scrollbar-x-rail,
|
||||
.ps-theme-square.ps-active-y > .ps-scrollbar-y-rail {
|
||||
display: block;
|
||||
background-color: transparent; }
|
||||
.ps-theme-square.ps-in-scrolling {
|
||||
pointer-events: none; }
|
||||
.ps-theme-square.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-theme-square.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||
background-color: #999; }
|
||||
.ps-theme-square.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-theme-square.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||
background-color: #999; }
|
||||
.ps-theme-square > .ps-scrollbar-x-rail {
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
opacity: 0;
|
||||
transition: background-color .2s linear, opacity .2s linear;
|
||||
bottom: 0;
|
||||
/* there must be 'bottom' for ps-scrollbar-x-rail */
|
||||
height: 10px; }
|
||||
.ps-theme-square > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
background-color: #aaa;
|
||||
border-radius: 0;
|
||||
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||
bottom: 0;
|
||||
/* there must be 'bottom' for ps-scrollbar-x */
|
||||
height: 10px; }
|
||||
.ps-theme-square > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x, .ps-theme-square > .ps-scrollbar-x-rail:active > .ps-scrollbar-x {
|
||||
height: 10px; }
|
||||
.ps-theme-square > .ps-scrollbar-y-rail {
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
opacity: 0;
|
||||
transition: background-color .2s linear, opacity .2s linear;
|
||||
right: 0;
|
||||
/* there must be 'right' for ps-scrollbar-y-rail */
|
||||
width: 10px; }
|
||||
.ps-theme-square > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||
position: absolute;
|
||||
/* please don't change 'position' */
|
||||
background-color: #aaa;
|
||||
border-radius: 0;
|
||||
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;
|
||||
right: 0;
|
||||
/* there must be 'right' for ps-scrollbar-y */
|
||||
width: 10px; }
|
||||
.ps-theme-square > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y, .ps-theme-square > .ps-scrollbar-y-rail:active > .ps-scrollbar-y {
|
||||
width: 10px; }
|
||||
.ps-theme-square:hover.ps-in-scrolling {
|
||||
pointer-events: none; }
|
||||
.ps-theme-square:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-theme-square:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x {
|
||||
background-color: #999; }
|
||||
.ps-theme-square:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-theme-square:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y {
|
||||
background-color: #999; }
|
||||
.ps-theme-square:hover > .ps-scrollbar-x-rail,
|
||||
.ps-theme-square:hover > .ps-scrollbar-y-rail {
|
||||
opacity: 0.6; }
|
||||
.ps-theme-square:hover > .ps-scrollbar-x-rail:hover {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-theme-square:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x {
|
||||
background-color: #999; }
|
||||
.ps-theme-square:hover > .ps-scrollbar-y-rail:hover {
|
||||
background-color: #eee;
|
||||
opacity: 0.9; }
|
||||
.ps-theme-square:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y {
|
||||
background-color: #999; }
|
||||
@@ -3,25 +3,36 @@
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>perfect-scrollbar example</title>
|
||||
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
|
||||
<link href="custom-theme.css" rel="stylesheet">
|
||||
<script src="../dist/js/perfect-scrollbar.js"></script>
|
||||
<style>
|
||||
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
|
||||
.contentHolder { position: relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
|
||||
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="Default" class="contentHolder">
|
||||
<div id="container" class="contentHolder">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
<p style='text-align: center'>
|
||||
<button id='default'>default</button>
|
||||
<button id='custom'>custom</button>
|
||||
</p>
|
||||
<script>
|
||||
var $ = document.querySelector.bind(document);
|
||||
var container = $('#container');
|
||||
window.onload = function () {
|
||||
Ps.initialize($('#Default'), {
|
||||
theme: 'big-and-ugly'
|
||||
});
|
||||
Ps.initialize(container, { theme: 'square' });
|
||||
};
|
||||
$('#default').addEventListener('click', function () {
|
||||
Ps.destroy(container);
|
||||
Ps.initialize(container);
|
||||
});
|
||||
$('#custom').addEventListener('click', function () {
|
||||
Ps.destroy(container);
|
||||
Ps.initialize(container, { theme: 'square' });
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
23
examples/custom-theme.scss
Normal file
23
examples/custom-theme.scss
Normal file
@@ -0,0 +1,23 @@
|
||||
@import '../src/css/main';
|
||||
|
||||
/*
|
||||
this file is built into custom-theme.css
|
||||
|
||||
$ node-sass examples/custom-theme.scss -o examples/
|
||||
*/
|
||||
|
||||
.ps-theme-square {
|
||||
@include ps-container(map-merge($ps-theme-default, (
|
||||
border-radius: 0,
|
||||
scrollbar-x-rail-bottom: 0,
|
||||
scrollbar-x-rail-height: 10px,
|
||||
scrollbar-x-bottom: 0,
|
||||
scrollbar-x-height: 10px,
|
||||
scrollbar-x-hover-height: 10px,
|
||||
scrollbar-y-rail-right: 0,
|
||||
scrollbar-y-rail-width: 10px,
|
||||
scrollbar-y-right: 0,
|
||||
scrollbar-y-width: 10px,
|
||||
scrollbar-y-hover-width: 10px,
|
||||
)));
|
||||
}
|
||||
63
examples/infinite-scroll.html
Normal file
63
examples/infinite-scroll.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>perfect-scrollbar example</title>
|
||||
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
|
||||
<script src="../dist/js/perfect-scrollbar.js"></script>
|
||||
<style>
|
||||
#Default {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid blue;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
.entryPlaceholder {
|
||||
height: 48px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="Default">
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var x = 0;
|
||||
var $ = document.querySelector.bind(document);
|
||||
window.onload = function () {
|
||||
// show some initial data
|
||||
for(var i = 0; i < 10; i++) {
|
||||
$('#Default').innerHTML += '<div class="entryPlaceholder">Entry #' + (x++) + '</div>';
|
||||
}
|
||||
Ps.initialize($('#Default'));
|
||||
|
||||
};
|
||||
|
||||
var isProgramaticallyTriggered = false;
|
||||
var addEntries = function(num) {
|
||||
for(var i = 0; i < num; i++) {
|
||||
$('#Default').innerHTML += '<div class="entryPlaceholder">Entry #' + (x++) + '</div>';
|
||||
}
|
||||
|
||||
isProgramaticallyTriggered = true;
|
||||
Ps.update($('#Default'));
|
||||
isProgramaticallyTriggered = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// on scroll, add more entries
|
||||
document.addEventListener('ps-scroll-y', function(e) {
|
||||
if (!isProgramaticallyTriggered) {
|
||||
console.debug("user scrolled to pos: ", $('#Default').scrollTop);
|
||||
addEntries(1);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
55
examples/options-autoupdate.html
Normal file
55
examples/options-autoupdate.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>perfect-scrollbar example</title>
|
||||
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
|
||||
<script src="../dist/js/perfect-scrollbar.js"></script>
|
||||
<style>
|
||||
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 80%; height: 400px; overflow: auto; }
|
||||
.always-visible.contentHolder .content { background-image: url('./azusa.jpg'); width: 680px; height: 320px; }
|
||||
.spacer { text-align:center }
|
||||
|
||||
.always-visible.ps-container > .ps-scrollbar-x-rail,
|
||||
.always-visible.ps-container > .ps-scrollbar-y-rail {
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="Default" class="contentHolder always-visible">
|
||||
<div id="Content" class="content">
|
||||
</div>
|
||||
</div>
|
||||
<p style='text-align: center'>
|
||||
<button onclick='addContent()'>Add new content!</button>
|
||||
<button onclick='removeContent()'>Remove content!</button>
|
||||
</p>
|
||||
<script>
|
||||
var i = 1;
|
||||
var $ = document.querySelector.bind(document);
|
||||
window.onload = function () {
|
||||
Ps.initialize($('#Default'), {
|
||||
autoupdate: true
|
||||
});
|
||||
};
|
||||
|
||||
var addContent = function () {
|
||||
var newDiv = document.createElement('div');
|
||||
newDiv.id = 'node' + i++;
|
||||
var newContent = document.createTextNode('Hi there!');
|
||||
newDiv.appendChild(newContent);
|
||||
|
||||
$('#Default').insertBefore(newDiv, $('#Content'));
|
||||
};
|
||||
|
||||
var removeContent = function () {
|
||||
if (i <= 1) return;
|
||||
|
||||
var node = $('#node' + --i);
|
||||
node.parentNode.removeChild(node);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
20
package.json
20
package.json
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "perfect-scrollbar",
|
||||
"version": "0.6.11",
|
||||
"version": "0.6.17",
|
||||
"description": "Minimalistic but perfect custom scrollbar plugin",
|
||||
"author": "Hyunje Alex Jun <me@noraesae.net>",
|
||||
"author": "Hyunje Jun <me@noraesae.net>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Hyunje Alex Jun",
|
||||
"name": "Hyunje Jun",
|
||||
"email": "me@noraesae.net"
|
||||
}
|
||||
],
|
||||
@@ -30,7 +30,8 @@
|
||||
"dist",
|
||||
"src",
|
||||
"index.js",
|
||||
"jquery.js"
|
||||
"jquery.js",
|
||||
"perfect-scrollbar.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"browserify": "^11.2.0",
|
||||
@@ -48,10 +49,19 @@
|
||||
"vinyl-buffer": "^1.0.0",
|
||||
"vinyl-source-stream": "^1.1.0"
|
||||
},
|
||||
"jspm": {
|
||||
"main": "./index.js",
|
||||
"registry": "jspm"
|
||||
},
|
||||
"typings": "perfect-scrollbar.d.ts",
|
||||
"scripts": {
|
||||
"test": "gulp",
|
||||
"before-deploy": "gulp && gulp compress",
|
||||
"release": "rm -rf dist && gulp && npm publish"
|
||||
"release": "rm -rf dist && gulp && npm publish",
|
||||
"bump": "npm version patch",
|
||||
"bump:major": "npm version major",
|
||||
"bump:minor": "npm version minor",
|
||||
"postversion": "git push origin master --follow-tags"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
29
perfect-scrollbar.d.ts
vendored
Normal file
29
perfect-scrollbar.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
interface PerfectScrollbarOptions {
|
||||
wheelSpeed?: number;
|
||||
wheelPropagation?: boolean;
|
||||
swipePropagation?: boolean;
|
||||
minScrollbarLength?: number;
|
||||
maxScrollbarLength?: number;
|
||||
useBothWheelAxes?: boolean;
|
||||
useKeyboard?: boolean;
|
||||
suppressScrollX?: boolean;
|
||||
suppressScrollY?: boolean;
|
||||
scrollXMarginOffset?: number;
|
||||
scrollYMarginOffset?: number;
|
||||
}
|
||||
|
||||
interface PerfectScrollbar {
|
||||
initialize(container: HTMLElement, options?: PerfectScrollbarOptions): void;
|
||||
update(container: HTMLElement): void;
|
||||
destroy(container: HTMLElement): void;
|
||||
}
|
||||
|
||||
interface JQuery {
|
||||
perfectScrollbar(options?: PerfectScrollbarOptions): JQuery;
|
||||
}
|
||||
|
||||
declare var ps: PerfectScrollbar;
|
||||
|
||||
declare module "perfect-scrollbar" {
|
||||
export = ps;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
@mixin scrollbar-rail-default($theme) {
|
||||
display: none;
|
||||
position: absolute; /* please don't change 'position' */
|
||||
border-radius: map_get($theme, border-radius);
|
||||
opacity: map_get($theme, rail-default-opacity);
|
||||
transition: background-color .2s linear, opacity .2s linear;
|
||||
}
|
||||
@@ -15,7 +14,8 @@
|
||||
position: absolute; /* please don't change 'position' */
|
||||
background-color: map_get($theme, bar-container-hover-bg);
|
||||
border-radius: map_get($theme, border-radius);
|
||||
transition: background-color .2s linear;
|
||||
transition: background-color .2s linear, height .2s linear, width .2s ease-in-out,
|
||||
border-radius .2s ease-in-out;
|
||||
}
|
||||
|
||||
@mixin scrollbar-hover($theme) {
|
||||
@@ -24,17 +24,18 @@
|
||||
|
||||
@mixin in-scrolling($theme) {
|
||||
&.ps-in-scrolling {
|
||||
pointer-events: none;
|
||||
&.ps-x > .ps-scrollbar-x-rail {
|
||||
@include scrollbar-rail-hover($theme);
|
||||
> .ps-scrollbar-x {
|
||||
@include scrollbar-hover($theme);
|
||||
height: map_get($theme, scrollbar-x-hover-height);
|
||||
}
|
||||
}
|
||||
&.ps-y > .ps-scrollbar-y-rail {
|
||||
@include scrollbar-rail-hover($theme);
|
||||
> .ps-scrollbar-y {
|
||||
@include scrollbar-hover($theme);
|
||||
width: map_get($theme, scrollbar-y-hover-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +43,8 @@
|
||||
|
||||
// Layout and theme mixin
|
||||
@mixin ps-container($theme) {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
-ms-touch-action: auto;
|
||||
touch-action: auto;
|
||||
overflow: hidden !important;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
@@ -74,6 +75,12 @@
|
||||
bottom: map_get($theme, scrollbar-x-bottom); /* there must be 'bottom' for ps-scrollbar-x */
|
||||
height: map_get($theme, scrollbar-x-height);
|
||||
}
|
||||
&:hover,
|
||||
&:active {
|
||||
> .ps-scrollbar-x {
|
||||
height: map_get($theme, scrollbar-x-hover-height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .ps-scrollbar-y-rail {
|
||||
@@ -86,6 +93,12 @@
|
||||
right: map_get($theme, scrollbar-y-right); /* there must be 'right' for ps-scrollbar-y */
|
||||
width: map_get($theme, scrollbar-y-width);
|
||||
}
|
||||
&:hover,
|
||||
&:active {
|
||||
> .ps-scrollbar-y {
|
||||
width: map_get($theme, scrollbar-y-hover-width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -11,10 +11,12 @@ $ps-theme-default: (
|
||||
scrollbar-x-rail-height: $ps-scrollbar-x-rail-height,
|
||||
scrollbar-x-bottom: $ps-scrollbar-x-bottom,
|
||||
scrollbar-x-height: $ps-scrollbar-x-height,
|
||||
scrollbar-x-hover-height: $ps-scrollbar-x-hover-height,
|
||||
scrollbar-y-rail-right: $ps-scrollbar-y-rail-right,
|
||||
scrollbar-y-rail-width: $ps-scrollbar-y-rail-width,
|
||||
scrollbar-y-right: $ps-scrollbar-y-right,
|
||||
scrollbar-y-width: $ps-scrollbar-y-width,
|
||||
scrollbar-y-hover-width: $ps-scrollbar-y-hover-width,
|
||||
);
|
||||
|
||||
// Default theme
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Colors
|
||||
$ps-border-radius: 4px !default;
|
||||
$ps-border-radius: 6px !default;
|
||||
|
||||
$ps-rail-default-opacity: 0 !default;
|
||||
$ps-rail-container-hover-opacity: 0.6 !default;
|
||||
@@ -11,12 +11,14 @@ $ps-bar-hover-bg: #999 !default;
|
||||
$ps-rail-hover-bg: #eee !default;
|
||||
|
||||
// Sizes
|
||||
$ps-scrollbar-x-rail-bottom: 3px !default;
|
||||
$ps-scrollbar-x-rail-height: 8px !default;
|
||||
$ps-scrollbar-x-bottom: 0 !default;
|
||||
$ps-scrollbar-x-height: 8px !default;
|
||||
$ps-scrollbar-x-rail-bottom: 0px !default;
|
||||
$ps-scrollbar-x-rail-height: 15px !default;
|
||||
$ps-scrollbar-x-bottom: 2px !default;
|
||||
$ps-scrollbar-x-height: 6px !default;
|
||||
$ps-scrollbar-x-hover-height: 11px !default;
|
||||
|
||||
$ps-scrollbar-y-rail-right: 3px !default;
|
||||
$ps-scrollbar-y-rail-width: 8px !default;
|
||||
$ps-scrollbar-y-right: 0 !default;
|
||||
$ps-scrollbar-y-width: 8px !default;
|
||||
$ps-scrollbar-y-rail-right: 0 !default;
|
||||
$ps-scrollbar-y-rail-width: 15px !default;
|
||||
$ps-scrollbar-y-right: 2px !default;
|
||||
$ps-scrollbar-y-width: 6px !default;
|
||||
$ps-scrollbar-y-hover-width: 11px !default;
|
||||
|
||||
@@ -14,7 +14,10 @@ DOM.appendTo = function (child, parent) {
|
||||
};
|
||||
|
||||
function cssGet(element, styleName) {
|
||||
return window.getComputedStyle(element)[styleName];
|
||||
var style = window.getComputedStyle(element);
|
||||
return style
|
||||
? style[styleName]
|
||||
: null;
|
||||
}
|
||||
|
||||
function cssSet(element, styleName, styleValue) {
|
||||
|
||||
@@ -8,9 +8,9 @@ var toInt = exports.toInt = function (x) {
|
||||
};
|
||||
|
||||
var clone = exports.clone = function (obj) {
|
||||
if (obj === null) {
|
||||
if (!obj) {
|
||||
return null;
|
||||
} else if (obj.constructor === Array) {
|
||||
} else if (Array.isArray(obj)) {
|
||||
return obj.map(clone);
|
||||
} else if (typeof obj === 'object') {
|
||||
var result = {};
|
||||
@@ -23,6 +23,26 @@ var clone = exports.clone = function (obj) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.debounce = function (func, wait, immediate) {
|
||||
var timeout;
|
||||
return function () {
|
||||
var context = this;
|
||||
var args = arguments;
|
||||
var later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) {
|
||||
func.apply(context, args);
|
||||
}
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) {
|
||||
func.apply(context, args);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.extend = function (original, source) {
|
||||
var result = clone(original);
|
||||
for (var key in source) {
|
||||
|
||||
30
src/js/plugin/autoupdate.js
Normal file
30
src/js/plugin/autoupdate.js
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
var update = require('./update');
|
||||
var MutationObserver = window.MutationObserver;
|
||||
var instances = require('./instances');
|
||||
|
||||
var createDOMEvent = function (name) {
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent(name, true, true);
|
||||
return event;
|
||||
};
|
||||
|
||||
module.exports = function (element) {
|
||||
if (MutationObserver === null || MutationObserver === undefined) {
|
||||
// MutationObserver is not supported
|
||||
return;
|
||||
}
|
||||
|
||||
var i = instances.get(element);
|
||||
var onMutationObserver = function () {
|
||||
update(element);
|
||||
element.dispatchEvent(createDOMEvent('ps-dom-change'));
|
||||
};
|
||||
|
||||
i.observer = new MutationObserver(onMutationObserver);
|
||||
onMutationObserver();
|
||||
|
||||
var config = { childList: true, subtree: true };
|
||||
i.observer.observe(element, config);
|
||||
};
|
||||
@@ -6,12 +6,12 @@ module.exports = {
|
||||
minScrollbarLength: null,
|
||||
scrollXMarginOffset: 0,
|
||||
scrollYMarginOffset: 0,
|
||||
stopPropagationOnClick: true,
|
||||
suppressScrollX: false,
|
||||
suppressScrollY: false,
|
||||
swipePropagation: true,
|
||||
useBothWheelAxes: false,
|
||||
wheelPropagation: false,
|
||||
wheelSpeed: 1,
|
||||
theme: 'default'
|
||||
theme: 'default',
|
||||
autoupdate: true
|
||||
};
|
||||
|
||||
@@ -11,6 +11,10 @@ module.exports = function (element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (i.observer) {
|
||||
i.observer.disconnect();
|
||||
}
|
||||
|
||||
i.event.unbindAll();
|
||||
dom.remove(i.scrollbarX);
|
||||
dom.remove(i.scrollbarY);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var _ = require('../../lib/helper');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
@@ -11,43 +10,23 @@ function bindClickRailHandler(element, i) {
|
||||
}
|
||||
var stopPropagation = function (e) { e.stopPropagation(); };
|
||||
|
||||
if (i.settings.stopPropagationOnClick) {
|
||||
i.event.bind(i.scrollbarY, 'click', stopPropagation);
|
||||
}
|
||||
i.event.bind(i.scrollbarY, 'click', stopPropagation);
|
||||
i.event.bind(i.scrollbarYRail, 'click', function (e) {
|
||||
var halfOfScrollbarLength = _.toInt(i.scrollbarYHeight / 2);
|
||||
var positionTop = i.railYRatio * (e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength);
|
||||
var maxPositionTop = i.railYRatio * (i.railYHeight - i.scrollbarYHeight);
|
||||
var positionRatio = positionTop / maxPositionTop;
|
||||
var positionTop = e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top;
|
||||
var direction = positionTop > i.scrollbarYTop ? 1 : -1;
|
||||
|
||||
if (positionRatio < 0) {
|
||||
positionRatio = 0;
|
||||
} else if (positionRatio > 1) {
|
||||
positionRatio = 1;
|
||||
}
|
||||
|
||||
updateScroll(element, 'top', (i.contentHeight - i.containerHeight) * positionRatio);
|
||||
updateScroll(element, 'top', element.scrollTop + direction * i.containerHeight);
|
||||
updateGeometry(element);
|
||||
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
if (i.settings.stopPropagationOnClick) {
|
||||
i.event.bind(i.scrollbarX, 'click', stopPropagation);
|
||||
}
|
||||
i.event.bind(i.scrollbarX, 'click', stopPropagation);
|
||||
i.event.bind(i.scrollbarXRail, 'click', function (e) {
|
||||
var halfOfScrollbarLength = _.toInt(i.scrollbarXWidth / 2);
|
||||
var positionLeft = i.railXRatio * (e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength);
|
||||
var maxPositionLeft = i.railXRatio * (i.railXWidth - i.scrollbarXWidth);
|
||||
var positionRatio = positionLeft / maxPositionLeft;
|
||||
var positionLeft = e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left;
|
||||
var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;
|
||||
|
||||
if (positionRatio < 0) {
|
||||
positionRatio = 0;
|
||||
} else if (positionRatio > 1) {
|
||||
positionRatio = 1;
|
||||
}
|
||||
|
||||
updateScroll(element, 'left', ((i.contentWidth - i.containerWidth) * positionRatio) - i.negativeScrollAdjustment);
|
||||
updateScroll(element, 'left', element.scrollLeft + direction * i.containerWidth);
|
||||
updateGeometry(element);
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -40,7 +40,7 @@ function bindKeyboardHandler(element, i) {
|
||||
}
|
||||
|
||||
i.event.bind(i.ownerDocument, 'keydown', function (e) {
|
||||
if (e.isDefaultPrevented && e.isDefaultPrevented()) {
|
||||
if ((e.isDefaultPrevented && e.isDefaultPrevented()) || e.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,16 +71,40 @@ function bindKeyboardHandler(element, i) {
|
||||
|
||||
switch (e.which) {
|
||||
case 37: // left
|
||||
deltaX = -30;
|
||||
if (e.metaKey) {
|
||||
deltaX = -i.contentWidth;
|
||||
} else if (e.altKey) {
|
||||
deltaX = -i.containerWidth;
|
||||
} else {
|
||||
deltaX = -30;
|
||||
}
|
||||
break;
|
||||
case 38: // up
|
||||
deltaY = 30;
|
||||
if (e.metaKey) {
|
||||
deltaY = i.contentHeight;
|
||||
} else if (e.altKey) {
|
||||
deltaY = i.containerHeight;
|
||||
} else {
|
||||
deltaY = 30;
|
||||
}
|
||||
break;
|
||||
case 39: // right
|
||||
deltaX = 30;
|
||||
if (e.metaKey) {
|
||||
deltaX = i.contentWidth;
|
||||
} else if (e.altKey) {
|
||||
deltaX = i.containerWidth;
|
||||
} else {
|
||||
deltaX = 30;
|
||||
}
|
||||
break;
|
||||
case 40: // down
|
||||
deltaY = -30;
|
||||
if (e.metaKey) {
|
||||
deltaY = -i.contentHeight;
|
||||
} else if (e.altKey) {
|
||||
deltaY = -i.containerHeight;
|
||||
} else {
|
||||
deltaY = -30;
|
||||
}
|
||||
break;
|
||||
case 33: // page up
|
||||
deltaY = 90;
|
||||
|
||||
@@ -52,13 +52,18 @@ function bindMouseWheelHandler(element, i) {
|
||||
deltaY = e.wheelDelta;
|
||||
}
|
||||
|
||||
if (e.shiftKey) {
|
||||
// reverse axis with shift key
|
||||
return [-deltaY, -deltaX];
|
||||
}
|
||||
return [deltaX, deltaY];
|
||||
}
|
||||
|
||||
function shouldBeConsumedByChild(deltaX, deltaY) {
|
||||
var child = element.querySelector('textarea:hover, .ps-child:hover');
|
||||
var child = element.querySelector('textarea:hover, select[multiple]:hover, .ps-child:hover');
|
||||
if (child) {
|
||||
if (child.tagName !== 'TEXTAREA' && !window.getComputedStyle(child).overflow.match(/(scroll|auto)/)) {
|
||||
if (!window.getComputedStyle(child).overflow.match(/(scroll|auto)/)) {
|
||||
// if not scrollable
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,12 @@ function bindSelectionHandler(element, i) {
|
||||
stopScrolling();
|
||||
}
|
||||
});
|
||||
i.event.bind(window, 'keyup', function () {
|
||||
if (isSelected) {
|
||||
isSelected = false;
|
||||
stopScrolling();
|
||||
}
|
||||
});
|
||||
|
||||
i.event.bind(window, 'mousemove', function (e) {
|
||||
if (isSelected) {
|
||||
|
||||
@@ -88,32 +88,37 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
}
|
||||
}
|
||||
function touchMove(e) {
|
||||
if (!inLocalTouch && i.settings.swipePropagation) {
|
||||
touchStart(e);
|
||||
}
|
||||
if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) {
|
||||
var touch = getTouch(e);
|
||||
var target = e.target;
|
||||
var className = target && target.getAttribute && target.getAttribute('class') || '';
|
||||
|
||||
var currentOffset = {pageX: touch.pageX, pageY: touch.pageY};
|
||||
|
||||
var differenceX = currentOffset.pageX - startOffset.pageX;
|
||||
var differenceY = currentOffset.pageY - startOffset.pageY;
|
||||
|
||||
applyTouchMove(differenceX, differenceY);
|
||||
startOffset = currentOffset;
|
||||
|
||||
var currentTime = (new Date()).getTime();
|
||||
|
||||
var timeGap = currentTime - startTime;
|
||||
if (timeGap > 0) {
|
||||
speed.x = differenceX / timeGap;
|
||||
speed.y = differenceY / timeGap;
|
||||
startTime = currentTime;
|
||||
if (!className.match(/ps-prevent-touchmove/)) {
|
||||
if (!inLocalTouch && i.settings.swipePropagation) {
|
||||
touchStart(e);
|
||||
}
|
||||
if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) {
|
||||
var touch = getTouch(e);
|
||||
|
||||
if (shouldPreventDefault(differenceX, differenceY)) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var currentOffset = {pageX: touch.pageX, pageY: touch.pageY};
|
||||
|
||||
var differenceX = currentOffset.pageX - startOffset.pageX;
|
||||
var differenceY = currentOffset.pageY - startOffset.pageY;
|
||||
|
||||
applyTouchMove(differenceX, differenceY);
|
||||
startOffset = currentOffset;
|
||||
|
||||
var currentTime = (new Date()).getTime();
|
||||
|
||||
var timeGap = currentTime - startTime;
|
||||
if (timeGap > 0) {
|
||||
speed.x = differenceX / timeGap;
|
||||
speed.y = differenceY / timeGap;
|
||||
startTime = currentTime;
|
||||
}
|
||||
|
||||
if (shouldPreventDefault(differenceX, differenceY)) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +133,11 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!speed.x && !speed.y) {
|
||||
clearInterval(easingLoop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
|
||||
clearInterval(easingLoop);
|
||||
return;
|
||||
@@ -147,9 +157,7 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
i.event.bind(element, 'touchstart', touchStart);
|
||||
i.event.bind(element, 'touchmove', touchMove);
|
||||
i.event.bind(element, 'touchend', touchEnd);
|
||||
}
|
||||
|
||||
if (supportsIePointer) {
|
||||
} else if (supportsIePointer) {
|
||||
if (window.PointerEvent) {
|
||||
i.event.bind(window, 'pointerdown', globalTouchStart);
|
||||
i.event.bind(window, 'pointerup', globalTouchEnd);
|
||||
|
||||
@@ -4,6 +4,8 @@ var _ = require('../lib/helper');
|
||||
var cls = require('../lib/class');
|
||||
var instances = require('./instances');
|
||||
var updateGeometry = require('./update-geometry');
|
||||
var autoupdate = require('./autoupdate');
|
||||
var resizer = require('./resizer');
|
||||
|
||||
// Handlers
|
||||
var handlers = {
|
||||
@@ -34,4 +36,9 @@ module.exports = function (element, userSettings) {
|
||||
nativeScrollHandler(element);
|
||||
|
||||
updateGeometry(element);
|
||||
|
||||
if (i.settings.autoupdate) {
|
||||
autoupdate(element);
|
||||
resizer(element);
|
||||
}
|
||||
};
|
||||
|
||||
15
src/js/plugin/resizer.js
Normal file
15
src/js/plugin/resizer.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var update = require('./update');
|
||||
var instances = require('./instances');
|
||||
var _ = require('../lib/helper');
|
||||
|
||||
module.exports = function (element) {
|
||||
var i = instances.get(element);
|
||||
|
||||
var onResize = function () {
|
||||
update(element);
|
||||
};
|
||||
|
||||
i.event.bind(window, 'resize', _.debounce(onResize, 60));
|
||||
};
|
||||
@@ -2,29 +2,14 @@
|
||||
|
||||
var instances = require('./instances');
|
||||
|
||||
var upEvent = document.createEvent('Event');
|
||||
var downEvent = document.createEvent('Event');
|
||||
var leftEvent = document.createEvent('Event');
|
||||
var rightEvent = document.createEvent('Event');
|
||||
var yEvent = document.createEvent('Event');
|
||||
var xEvent = document.createEvent('Event');
|
||||
var xStartEvent = document.createEvent('Event');
|
||||
var xEndEvent = document.createEvent('Event');
|
||||
var yStartEvent = document.createEvent('Event');
|
||||
var yEndEvent = document.createEvent('Event');
|
||||
var lastTop;
|
||||
var lastLeft;
|
||||
|
||||
upEvent.initEvent('ps-scroll-up', true, true);
|
||||
downEvent.initEvent('ps-scroll-down', true, true);
|
||||
leftEvent.initEvent('ps-scroll-left', true, true);
|
||||
rightEvent.initEvent('ps-scroll-right', true, true);
|
||||
yEvent.initEvent('ps-scroll-y', true, true);
|
||||
xEvent.initEvent('ps-scroll-x', true, true);
|
||||
xStartEvent.initEvent('ps-x-reach-start', true, true);
|
||||
xEndEvent.initEvent('ps-x-reach-end', true, true);
|
||||
yStartEvent.initEvent('ps-y-reach-start', true, true);
|
||||
yEndEvent.initEvent('ps-y-reach-end', true, true);
|
||||
var createDOMEvent = function (name) {
|
||||
var event = document.createEvent("Event");
|
||||
event.initEvent(name, true, true);
|
||||
return event;
|
||||
};
|
||||
|
||||
module.exports = function (element, axis, value) {
|
||||
if (typeof element === 'undefined') {
|
||||
@@ -41,12 +26,12 @@ module.exports = function (element, axis, value) {
|
||||
|
||||
if (axis === 'top' && value <= 0) {
|
||||
element.scrollTop = value = 0; // don't allow negative scroll
|
||||
element.dispatchEvent(yStartEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-y-reach-start'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value <= 0) {
|
||||
element.scrollLeft = value = 0; // don't allow negative scroll
|
||||
element.dispatchEvent(xStartEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-x-reach-start'));
|
||||
}
|
||||
|
||||
var i = instances.get(element);
|
||||
@@ -60,7 +45,7 @@ module.exports = function (element, axis, value) {
|
||||
} else {
|
||||
element.scrollTop = value;
|
||||
}
|
||||
element.dispatchEvent(yEndEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-y-reach-end'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value >= i.contentWidth - i.containerWidth) {
|
||||
@@ -72,7 +57,7 @@ module.exports = function (element, axis, value) {
|
||||
} else {
|
||||
element.scrollLeft = value;
|
||||
}
|
||||
element.dispatchEvent(xEndEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-x-reach-end'));
|
||||
}
|
||||
|
||||
if (!lastTop) {
|
||||
@@ -84,29 +69,29 @@ module.exports = function (element, axis, value) {
|
||||
}
|
||||
|
||||
if (axis === 'top' && value < lastTop) {
|
||||
element.dispatchEvent(upEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-up'));
|
||||
}
|
||||
|
||||
if (axis === 'top' && value > lastTop) {
|
||||
element.dispatchEvent(downEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-down'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value < lastLeft) {
|
||||
element.dispatchEvent(leftEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-left'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value > lastLeft) {
|
||||
element.dispatchEvent(rightEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-right'));
|
||||
}
|
||||
|
||||
if (axis === 'top') {
|
||||
element.scrollTop = lastTop = value;
|
||||
element.dispatchEvent(yEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-y'));
|
||||
}
|
||||
|
||||
if (axis === 'left') {
|
||||
element.scrollLeft = lastLeft = value;
|
||||
element.dispatchEvent(xEvent);
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-x'));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user