Compare commits
185 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 | ||
|
|
aec4e37f61 | ||
|
|
269a1dc402 | ||
|
|
2cac43ef39 | ||
|
|
b0a38741df | ||
|
|
edaeccebf2 | ||
|
|
42364c4d43 | ||
|
|
f20a8532ff | ||
|
|
7621a2488c | ||
|
|
205c6d0223 | ||
|
|
ad5cd4fe53 | ||
|
|
dc951a3804 | ||
|
|
9996b1c8e3 | ||
|
|
f14b6a0d47 | ||
|
|
9580e08886 | ||
|
|
a2b2a77de1 | ||
|
|
e63d4c03cb | ||
|
|
d277a363b0 | ||
|
|
4a661f181f | ||
|
|
bd7134f33d | ||
|
|
6f63623b93 | ||
|
|
cfc658d648 | ||
|
|
181265261b | ||
|
|
db65fe0f6a | ||
|
|
7e0d5f5dc5 | ||
|
|
e0d6243f24 | ||
|
|
3d91c6f098 | ||
|
|
636eaffd41 | ||
|
|
3ba211133d | ||
|
|
40b1510d49 | ||
|
|
b959edbf78 | ||
|
|
c49cf7905e | ||
|
|
f4cb31f8d8 | ||
|
|
965e315b30 | ||
|
|
3e76ce9d3e | ||
|
|
2413028ad4 | ||
|
|
cc0fded8cb | ||
|
|
fbfe505408 | ||
|
|
c76aa08113 | ||
|
|
4d7f441d1f | ||
|
|
4f6ed64b17 | ||
|
|
2fe45b3a97 | ||
|
|
57b1404e29 | ||
|
|
bcfe954803 | ||
|
|
31434f81d4 | ||
|
|
8a3ed6d0b7 | ||
|
|
1dfbbe9e56 | ||
|
|
eb02d5ae65 | ||
|
|
6fbaa00403 | ||
|
|
c14feba0bf | ||
|
|
6fbfd5c90d | ||
|
|
eddd2c2731 | ||
|
|
4c08b0e089 | ||
|
|
c04b662a1b | ||
|
|
5ba86c2217 | ||
|
|
6e32d3ddce | ||
|
|
9f9f15f83c | ||
|
|
7e04a2e72b | ||
|
|
24b34d3dea | ||
|
|
e1910cde3e | ||
|
|
bbf3d4db9f | ||
|
|
3b134d6193 | ||
|
|
e9024292cd | ||
|
|
e4dda6f408 | ||
|
|
fd53ae0b48 | ||
|
|
66fd8bfd6a | ||
|
|
4aa28add99 | ||
|
|
d6ede33202 | ||
|
|
1c3b409d12 | ||
|
|
17e5f67519 | ||
|
|
002034fd54 | ||
|
|
8761735a54 | ||
|
|
c285521caa | ||
|
|
3d2d50c308 | ||
|
|
a0d39e1b49 | ||
|
|
e288476ba0 | ||
|
|
e9bc40bd37 | ||
|
|
0b8fe0ac0b | ||
|
|
a3676556b2 | ||
|
|
39893fc6f2 | ||
|
|
6c5b9d249e | ||
|
|
2ef7e81ce9 | ||
|
|
3b90c734e4 | ||
|
|
afebe908b1 | ||
|
|
6cbb4a9b9d | ||
|
|
51f33a44b5 | ||
|
|
8eac54d49f | ||
|
|
ed4e335978 | ||
|
|
272bb4983a | ||
|
|
f200bea4cc | ||
|
|
b1d7aa0e64 | ||
|
|
49e39f513d | ||
|
|
89f4226778 | ||
|
|
79f4cfcf5f | ||
|
|
158b113d18 | ||
|
|
6c642d8a47 | ||
|
|
f9f20eeb6f | ||
|
|
1f082a2e04 | ||
|
|
b19c5e0765 | ||
|
|
3dbf20a5d0 | ||
|
|
db855ceca1 | ||
|
|
84b74926e3 | ||
|
|
d6bd30f2da | ||
|
|
fc28ceb4ea | ||
|
|
ca4d835129 | ||
|
|
88b4e2fc19 | ||
|
|
de32082a62 | ||
|
|
7ba25d020c | ||
|
|
08d559561e | ||
|
|
046ce954fd | ||
|
|
a40ab40695 | ||
|
|
2cd65684e2 | ||
|
|
a0b3754a0d | ||
|
|
dc7b14d0e1 | ||
|
|
a5aab04264 | ||
|
|
aca7683de1 | ||
|
|
c21cfb6ed0 | ||
|
|
e4b21c7069 | ||
|
|
bb58ab98e3 | ||
|
|
633f1f53d3 | ||
|
|
4a7f27356a | ||
|
|
2e071274db | ||
|
|
b23ad2834e | ||
|
|
cbdf812de8 | ||
|
|
5e363b876f | ||
|
|
cbf96b3302 |
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# EditorConfig: http://editorconfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# Indentation for JS & SCSS
|
||||
[*.{js, scss}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
38
.eslintrc
38
.eslintrc
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"env" : {
|
||||
"env": {
|
||||
"node": true,
|
||||
"browser": true
|
||||
},
|
||||
@@ -7,14 +7,34 @@
|
||||
"$": true,
|
||||
"define": true
|
||||
},
|
||||
"rules" : {
|
||||
"quotes": false,
|
||||
"space-after-keywords": [2, "always", {"checkFunctionKeyword": true}],
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"eqeqeq": 2,
|
||||
"no-multi-spaces": 2,
|
||||
"curly": 2,
|
||||
"semi": 2,
|
||||
"no-with": 2,
|
||||
"strict": [2, "global"],
|
||||
"radix": 2,
|
||||
"no-use-before-define": 2,
|
||||
"block-spacing": 2,
|
||||
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
|
||||
"camelcase": 2,
|
||||
"comma-spacing": [2, {"before": false, "after": true}],
|
||||
"eol-last": 2,
|
||||
"no-multiple-empty-lines": 2,
|
||||
"indent": [2, 2],
|
||||
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
|
||||
"linebreak-style": [2, "unix"],
|
||||
"new-parens": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"semi-spacing": 2,
|
||||
"space-before-blocks": [2, "always"],
|
||||
"brace-style": [2, "1tbs", { "allowSingleLine": false}],
|
||||
"spaced-line-comment": [2, "always"],
|
||||
"radix": [2, "always"],
|
||||
"key-spacing": [2, "always", {"beforeColon": false, "afterColon": true}],
|
||||
"no-multiple-empty-lines": [2, {max: 1}],
|
||||
"space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
|
||||
"space-in-parens": 2,
|
||||
"space-infix-ops": 2,
|
||||
"space-return-throw-case": 2,
|
||||
"space-unary-ops": 2,
|
||||
"spaced-comment": 2
|
||||
}
|
||||
}
|
||||
|
||||
8
.github/ISSUE_TEMPLATE.md
vendored
Normal file
8
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
Make sure these boxes are checked before submitting your issue -- thank you!
|
||||
|
||||
- [ ] Check [FAQ](https://github.com/noraesae/perfect-scrollbar/wiki/FAQ)
|
||||
- [ ] Search if there's already one reported in Issues
|
||||
- [ ] Prepare a JSFiddle reproducing the issue
|
||||
- Perfect Scrollbar JSFiddle: https://jsfiddle.net/DanielApt/xv0rrxv3/
|
||||
- With jQuery: https://jsfiddle.net/DanielApt/gbfLazpx/
|
||||
- [ ] Provide a page or source code where the issue can be checked
|
||||
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
Thank you very much for your contribution! Please make sure the followings
|
||||
are checked.
|
||||
|
||||
- [ ] Read [CONTRIBUTING.md](../CONTRIBUTING.md)
|
||||
- [ ] Run `gulp` to make sure it builds and lints successfully
|
||||
- [ ] Provide the scenario this PR will address(some JSFiddles will be perfect)
|
||||
- Perfect Scrollbar JSFiddle: https://jsfiddle.net/DanielApt/xv0rrxv3/
|
||||
- With jQuery: https://jsfiddle.net/DanielApt/gbfLazpx/
|
||||
- [ ] Refer to concerning issues if exist
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
.idea
|
||||
.idea
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
.DS_Store
|
||||
|
||||
/.eslintrc
|
||||
/.gitignore
|
||||
/.travis.yml
|
||||
/gulpfile.js
|
||||
/examples
|
||||
|
||||
node_modules
|
||||
@@ -1,8 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
before_script:
|
||||
- npm install -g gulp
|
||||
- 4
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
@@ -13,5 +11,4 @@ deploy:
|
||||
branch: master
|
||||
tags: true
|
||||
before_deploy:
|
||||
- gulp
|
||||
- gulp compress
|
||||
- npm run before-deploy
|
||||
|
||||
74
CONTRIBUTING.md
Normal file
74
CONTRIBUTING.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Contributing
|
||||
|
||||
I *really* welcome contributions! Please feel free to fork and issue pull requests when...
|
||||
|
||||
* You have a very nice idea to improve this plugin!
|
||||
* You found a bug!
|
||||
* You're good at English and can help my bad English!
|
||||
|
||||
For IE problems, please refer to [IE Support](https://github.com/noraesae/perfect-scrollbar#ie-support).
|
||||
|
||||
## Introduction
|
||||
First of all, thank you in advance for your contribution!
|
||||
|
||||
This document will introduce something you should know before making some contributions to **perfect-scrollbar**. I'll try to explain as easy as possible. If there are something missed or not well-documented, please let me know.
|
||||
|
||||
Email: me@noraesae.net
|
||||
|
||||
## Directory Structure
|
||||
Please don't edit files in the `out` subdirectory as they are generated via Gulp. You'll find source code in the `src` subdirectory!
|
||||
|
||||
`examples` directory is for the example sources. If you have any example you want to add with a new feature, please add it in the directory.
|
||||
|
||||
## Code Conventions
|
||||
Regarding code style like indentation and whitespace, **follow the conventions you see used in the source already.**
|
||||
|
||||
Basically, I try to follow [Douglas Crockford's JavaScript Code Conventions](http://javascript.crockford.com/code.html).
|
||||
|
||||
You can check if your code fits in the convention with `gulp lint`.
|
||||
|
||||
## Getting Started
|
||||
First, ensure that you have stable [Node.js](https://nodejs.org/) and [npm](https://npmjs.com) installed.
|
||||
|
||||
Test if Gulp CLI is installed by running `gulp --version`. If the command isn't found, run `npm install -g gulp`. For more information about installing Gulp, see the Gulp's [Getting Started](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md).
|
||||
|
||||
If `gulp` is installed, follow the steps below.
|
||||
|
||||
1. Fork and clone the repo.
|
||||
1. Run `npm install` to install all dev dependencies.
|
||||
1. Run `gulp` to check if Gulp works well.
|
||||
|
||||
Assuming that you don't see any error, you're ready to go.
|
||||
|
||||
## Linting Sources
|
||||
|
||||
You can use `gulp lint` command to lint the source files. If there're warnings with the command, it means that there are something that don't fit into the convention. Please modify the source to fit.
|
||||
|
||||
## Building Sources
|
||||
|
||||
You can use the `gulp build` command to build source files into output files.
|
||||
|
||||
If you want to watch the modification and build automatically during development, use the `gulp serve` command. It'll automatically rebuild the code when there's any change in it. It will also reload example pages, which is quite helpful.
|
||||
|
||||
## Submitting pull requests
|
||||
|
||||
1. Create a new branch. Working in your `master` branch is okay, but not recommended.
|
||||
1. Modify the sources.
|
||||
1. Run `gulp` to see if the code fit into the code convention and build without an error. Repeat steps 2-3 until done.
|
||||
1. Update the documentation to reflect any changes.
|
||||
1. Create examples if needed.
|
||||
1. Push to your fork and submit a pull request.
|
||||
|
||||
For further information about pull requests, please refer to GitHub's [Using Pull Requests](https://help.github.com/articles/using-pull-requests).
|
||||
|
||||
## Code Review
|
||||
|
||||
When the pull request is created, anyone can review the source code. After the review is finished and the patch doesn't have any problem, it'll be merged.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The process looks somewhat difficult, but it's necessary to avoid maintanance issues and make the code easy to read and use.
|
||||
|
||||
If there is any opinion or question, please feel free to contact me.
|
||||
|
||||
Email: me@noraesae.net
|
||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
The MIT License (MIT) Copyright (c) 2016 Hyunje Alex Jun and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
252
README.md
252
README.md
@@ -4,9 +4,6 @@ Minimalistic but perfect custom scrollbar plugin
|
||||
|
||||
[](https://travis-ci.org/noraesae/perfect-scrollbar)
|
||||
|
||||
**The plugin is currently changing quickly in the master branch.
|
||||
Please refer to the related issue [#227](https://github.com/noraesae/perfect-scrollbar/issues/277).**
|
||||
|
||||
If you want information of old versions<0.6.0, please refer to
|
||||
[an old documentation](https://github.com/noraesae/perfect-scrollbar/tree/0.5.9).
|
||||
|
||||
@@ -49,21 +46,32 @@ I hope you love it!
|
||||
to update the size or position of the scrollbar, just update.
|
||||
* Additionally, perfect-scrollbar uses 'scrollTop' and 'scrollLeft',
|
||||
not absolute positioning or something messy.
|
||||
* perfect-scrollbar supports RTL perfectly on both WebKit and Gecko based browsers.
|
||||
|
||||
It's cool, isn't it?
|
||||
|
||||
## Install
|
||||
|
||||
#### NPM
|
||||
|
||||
The best way to install and use perfect-scrollbar is with NPM.
|
||||
It's registered on [npm](https://www.npmjs.org/package/perfect-scrollbar) as `perfect-scrollbar`.
|
||||
It's registered on [npm](https://www.npmjs.com/package/perfect-scrollbar) as `perfect-scrollbar`.
|
||||
|
||||
```
|
||||
$ npm install perfect-scrollbar
|
||||
```
|
||||
|
||||
#### Rails
|
||||
|
||||
In the case you would like to have perfect-scrollbar in your Rails application, there is the [perfect-scrollbar-rails gem](https://github.com/YourCursus/perfect-scrollbar-rails).
|
||||
|
||||
#### Manually
|
||||
|
||||
You can download the latest stable version with download links [here](http://noraesae.github.io/perfect-scrollbar/).
|
||||
You also can find all releases on [Releases](https://github.com/noraesae/perfect-scrollbar/releases).
|
||||
|
||||
#### From sources
|
||||
|
||||
If you want to use the development version of the plugin, use the
|
||||
source files which are not minified. They're in the `src` directory.
|
||||
The development version may be unstable, but some known bugs may
|
||||
@@ -76,6 +84,7 @@ $ npm install
|
||||
$ gulp # will lint and build the source code.
|
||||
```
|
||||
|
||||
#### Bower
|
||||
|
||||
There is a Bower package for perfect-scrollbar as well. It is managed
|
||||
under the [perfect-scrollbar-bower](https://github.com/noraesae/perfect-scrollbar-bower)
|
||||
@@ -85,27 +94,39 @@ repository. The plugin is registered as `perfect-scrollbar`.
|
||||
$ bower install perfect-scrollbar
|
||||
```
|
||||
|
||||
#### CDNs
|
||||
|
||||
You can also load it from [cdnjs](http://cdnjs.com/).
|
||||
It is registered as [`jquery.perfect-scrollbar`](http://www.cdnjs.com/libraries/jquery.perfect-scrollbar).
|
||||
* [cdnjs](http://www.cdnjs.com/libraries/jquery.perfect-scrollbar)
|
||||
* [JSDelivr](https://www.jsdelivr.com/projects/perfect-scrollbar)
|
||||
|
||||
## Requirements
|
||||
#### JSFiddle
|
||||
|
||||
To make this plugin *perfect*, some requirements were unavoidable.
|
||||
But, they're all very trivial and there is nothing to worry about.
|
||||
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/)
|
||||
|
||||
## 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
|
||||
@@ -157,7 +178,7 @@ If the size of your container or content changes, call `update`.
|
||||
Ps.update(container);
|
||||
```
|
||||
|
||||
If you want to destory the scrollbar, use `destroy`.
|
||||
If you want to destroy the scrollbar, use `destroy`.
|
||||
|
||||
```javascript
|
||||
Ps.destroy(container);
|
||||
@@ -202,72 +223,213 @@ $('#container').perfectScrollbar('update'); // Update
|
||||
$('#container').perfectScrollbar('destroy'); // Destroy
|
||||
```
|
||||
|
||||
## RequireJS usage
|
||||
|
||||
For RequireJS loader, no need to write shim, simply import two libs:
|
||||
|
||||
```javascript
|
||||
require.config({
|
||||
paths: {
|
||||
perfectScrollbarJQuery: '.../perfect-scrollbar.jquery',
|
||||
perfectScrollbar: '.../perfect-scrollbar',
|
||||
}
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
and load `perfectScrollbar` in the initialiser of your app:
|
||||
|
||||
```javascript
|
||||
// for vanilla JS:
|
||||
window.Ps = require('perfectScrollbar');
|
||||
|
||||
// for jQuery:
|
||||
require('perfectScrollbarJQuery');
|
||||
```
|
||||
|
||||
|
||||
## AngularJS + RequireJS usage
|
||||
|
||||
With the require.config settings above, at the beginning of your app module
|
||||
definition, you can have following code:
|
||||
|
||||
```javascript
|
||||
define([
|
||||
'angular',
|
||||
'perfectScrollbar',
|
||||
'perfectScrollbarJquery'
|
||||
],
|
||||
function (angular) {
|
||||
var app = angular.module('myApp', []);
|
||||
app.run(function () {
|
||||
window.Ps = require('perfectScrollbar');
|
||||
require('perfectScrollbarJQuery');
|
||||
});
|
||||
return app;
|
||||
});
|
||||
```
|
||||
|
||||
And initialise perfectScrollbar in a controller:
|
||||
|
||||
```javascript
|
||||
// by vanilla JS:
|
||||
var container = document.getElementById('imgLoader');
|
||||
Ps.initialize(container);
|
||||
Ps.update(container);
|
||||
|
||||
// or by jQuery:
|
||||
var imgLoader = $('#imgLoader')
|
||||
imgLoader.perfectScrollbar();
|
||||
```
|
||||
|
||||
## Optional parameters
|
||||
|
||||
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']`
|
||||
**Disabled by default**: `'selection'`
|
||||
|
||||
### wheelSpeed
|
||||
The scroll speed applied to mousewheel event.
|
||||
**Default: 1**
|
||||
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.
|
||||
**Default: false**
|
||||
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.
|
||||
**Default: true**
|
||||
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.
|
||||
**Default: null**
|
||||
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.
|
||||
**Default: null**
|
||||
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.
|
||||
**Default: false**
|
||||
|
||||
### useKeyboard
|
||||
When set to true, the scroll works with arrow keys on the keyboard. The element is scrolled only when the mouse cursor hovers the element.
|
||||
**Default: true**
|
||||
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.
|
||||
**Default: false**
|
||||
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.
|
||||
**Default: false**
|
||||
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.
|
||||
**Default: 0**
|
||||
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.
|
||||
**Default: 0**
|
||||
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`
|
||||
|
||||
## Contribution
|
||||
### autoupdate
|
||||
When set to true, the scroll will be updated when an element is added or removed from the content.
|
||||
**Default**: `true`
|
||||
|
||||
#### Please read [Contributing](https://github.com/noraesae/perfect-scrollbar/wiki/Contributing) in the wiki before making any contribution.
|
||||
### 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.
|
||||
**Default**: `'default'`
|
||||
|
||||
**Example 1:**
|
||||
|
||||
Add `theme` parameter:
|
||||
```javascript
|
||||
Ps.initialize(container, {
|
||||
theme: 'my-theme-name'
|
||||
});
|
||||
```
|
||||
Create a class name prefixed with `.ps-theme-`. Include `ps-container()` mixin. It's recommended to use `map-merge()` to extend `$ps-theme-default` map with your custom styles.
|
||||
```scss
|
||||
.ps-theme-my-theme-name {
|
||||
@include ps-container(map-merge($ps-theme-default, (
|
||||
border-radius: 0,
|
||||
scrollbar-x-rail-height: 20px,
|
||||
scrollbar-x-height: 20px,
|
||||
scrollbar-y-rail-width: 20px,
|
||||
scrollbar-y-width: 20px
|
||||
)));
|
||||
}
|
||||
```
|
||||
|
||||
**Example 2:**
|
||||
|
||||
Alternatively, if you don't want to create your own themes, but only modify the default one, you could simply overwrite `$ps-*` variables with your own values. In this case `theme` parameter is not required when calling `.initialize()` method. Remember do define your own variables before the `theme.scss` file is imported.
|
||||
|
||||
|
||||
I *really* welcome contributions! Please feel free to fork and issue pull requests when...
|
||||
## Events
|
||||
|
||||
* You have a very nice idea to improve this plugin!
|
||||
* You found a bug!
|
||||
* You're good at English and can help my bad English!
|
||||
perfect-scrollbar dispatches custom events.
|
||||
|
||||
For IE problems, please refer to [IE Support](https://github.com/noraesae/perfect-scrollbar#ie-support).
|
||||
### ps-scroll-y
|
||||
This event fires when the y-axis is scrolled in either direction.
|
||||
|
||||
### ps-scroll-x
|
||||
This event fires when the x-axis is scrolled in either direction.
|
||||
|
||||
### ps-scroll-up
|
||||
This event fires when scrolling upwards.
|
||||
|
||||
### ps-scroll-down
|
||||
This event fires when scrolling downwards.
|
||||
|
||||
### ps-scroll-left
|
||||
This event fires when scrolling to the left.
|
||||
|
||||
### ps-scroll-right
|
||||
This event fires when scrolling to the right.
|
||||
|
||||
### ps-y-reach-start
|
||||
This event fires when scrolling reaches the start of the y-axis.
|
||||
|
||||
### ps-y-reach-end
|
||||
This event fires when scrolling reaches the end of the y-axis (useful for infinite scroll).
|
||||
|
||||
### ps-x-reach-start
|
||||
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 () {
|
||||
// ...
|
||||
})
|
||||
```
|
||||
or with jQuery
|
||||
```javascript
|
||||
$(document).on('ps-scroll-x', function () {
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
### Scrolling children inside perfect-scrollbar
|
||||
|
||||
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
|
||||
|
||||
The plugin would work in IEs >= IE9 (not well, though).
|
||||
The plugin is designed to work in modern browsers, including the very latest
|
||||
version of IE and Edge. Specifically, it should work in IEs >= IE10. If there
|
||||
is any issue in the browsers, please [file it](https://github.com/noraesae/perfect-scrollbar/issues).
|
||||
|
||||
**The patches to fix problems in IE<=8 won't be accepted.**
|
||||
**The patches to fix problems in IE<=9 won't be accepted.**
|
||||
|
||||
When old IEs should be supported, please fork the project and
|
||||
make patches personally.
|
||||
@@ -283,7 +445,7 @@ For common problems there is a
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT) Copyright (c) 2015 Hyunje Alex Jun and other contributors.
|
||||
The MIT License (MIT) Copyright (c) 2016 Hyunje Alex Jun and other contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
73
examples/children-native-scroll.html
Normal file
73
examples/children-native-scroll.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!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: 600px; height: 400px; overflow: auto; }
|
||||
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
|
||||
.my-list, textarea {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 130px;
|
||||
height: 200px;
|
||||
overflow: scroll;
|
||||
background-color: rgba(255,255,255,0.6);
|
||||
}
|
||||
|
||||
.my-list {
|
||||
left: 140px;
|
||||
}
|
||||
|
||||
.my-list-two {
|
||||
left: 280px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
box-sizing: border-box;
|
||||
padding: 10px 5px;
|
||||
border-width: 0 0 1px 0;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li:nth-child(even) {
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-size: 120%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<div id="Default" class="contentHolder">
|
||||
<div class="content">
|
||||
<textarea cols="20" rows="50">
|
||||
Children inside perfect scrollbar can be natively scrolled by the mousewheel. It automatically works for textarea elements, other elements need the .ps-child class.
|
||||
</textarea>
|
||||
<div class="ps-child my-list">
|
||||
<code>overflow: scroll</code>
|
||||
<ul><li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li><li>Six</li><li>Seven</li><li>Eight</li></ul>
|
||||
</div>
|
||||
<div class="ps-child my-list my-list-two">
|
||||
<code>overflow: auto</code>
|
||||
<ul><li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li><li>Six</li><li>Seven</li><li>Eight</li></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
window.onload = function () {
|
||||
Ps.initialize(document.querySelector('#Default'));
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
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; }
|
||||
38
examples/custom-theme.html
Normal file
38
examples/custom-theme.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>perfect-scrollbar example</title>
|
||||
<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: hidden; }
|
||||
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<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(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,
|
||||
)));
|
||||
}
|
||||
89
examples/events.html
Normal file
89
examples/events.html
Normal file
@@ -0,0 +1,89 @@
|
||||
<!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>
|
||||
p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
margin: 0px auto;
|
||||
padding: 0px;
|
||||
width: 600px;
|
||||
height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.container .content {
|
||||
background-image: url('./azusa.jpg');
|
||||
width: 1280px;
|
||||
height: 720px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p><strong>Axis</strong> <span id="axis">…</span></p>
|
||||
|
||||
<p><strong>Direction</strong> <span id="direction">…</span></p>
|
||||
|
||||
<p><strong>Start / End</strong> <span id="start-end">(scroll to the start or end of an axis)</span></p>
|
||||
<script>
|
||||
var container = document.querySelector('.container');
|
||||
var axis = document.getElementById('axis');
|
||||
var direction = document.getElementById('direction');
|
||||
var startEnd = document.getElementById('start-end');
|
||||
|
||||
Ps.initialize(container);
|
||||
|
||||
document.addEventListener('ps-scroll-y', function () {
|
||||
axis.innerHTML = 'Y Axis';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-scroll-x', function () {
|
||||
axis.innerHTML = 'X Axis';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-scroll-up', function () {
|
||||
direction.innerHTML = 'up';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-scroll-down', function () {
|
||||
direction.innerHTML = 'down';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-scroll-left', function () {
|
||||
direction.innerHTML = 'left';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-scroll-right', function () {
|
||||
direction.innerHTML = 'right';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-y-reach-start', function () {
|
||||
startEnd.innerHTML = 'Reached start of <em>Y-Axis</em>';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-y-reach-end', function () {
|
||||
startEnd.innerHTML = 'Reached end of <em>Y-Axis</em>';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-x-reach-start', function () {
|
||||
startEnd.innerHTML = 'Reached start of <em>X-Axis</em>';
|
||||
});
|
||||
|
||||
document.addEventListener('ps-x-reach-end', function () {
|
||||
startEnd.innerHTML = 'Reached end of <em>X-Axis</em>'
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
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>
|
||||
|
||||
49
examples/options-handlers.html
Normal file
49
examples/options-handlers.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!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; padding:0px; width: 600px; height: 400px; overflow: auto; }
|
||||
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
|
||||
.spacer { text-align:center }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Default</h1>
|
||||
<pre><code>handlers: ['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch']</code></pre>
|
||||
<div id="default" class="contentHolder">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>No keyboard</h1>
|
||||
<pre><code>handlers: ['click-rail', 'drag-scrollbar', 'wheel', 'touch']</code></pre>
|
||||
<div id="no-keyboard" class="contentHolder">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Click and Drag</h1>
|
||||
<pre><code>handlers: ['click-rail', 'drag-scrollbar']</code></pre>
|
||||
<div id="click-and-drag" class="contentHolder">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var $ = document.querySelector.bind(document);
|
||||
window.onload = function () {
|
||||
Ps.initialize($('#default'));
|
||||
Ps.initialize($('#no-keyboard'), {
|
||||
handlers: ['click-rail', 'drag-scrollbar', 'wheel', 'touch']
|
||||
});
|
||||
Ps.initialize($('#click-and-drag'), {
|
||||
handlers: ['click-rail', 'drag-scrollbar']
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<!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>
|
||||
#description {
|
||||
border: 1px solid gray;
|
||||
height:150px;
|
||||
width: 400px;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
#status { color: red; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description" class="wrapper">
|
||||
<p>Hello, world! 0</p>
|
||||
<p>Hello, world! 1</p>
|
||||
<p>Hello, world! 2</p>
|
||||
<p>Hello, world! 3</p>
|
||||
<p>Hello, world! 4</p>
|
||||
<p>Hello, world! 5</p>
|
||||
<p>Hello, world! 6</p>
|
||||
<p>Hello, world! 7</p>
|
||||
<p>Hello, world! 8</p>
|
||||
<p>Hello, world! 9</p>
|
||||
</div>
|
||||
<div id="status">
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var $ = document.querySelector.bind(document);
|
||||
window.onload = function () {
|
||||
var container = $('#description');
|
||||
var stat = $('#status');
|
||||
Ps.initialize(container);
|
||||
container.addEventListener('scroll', function (e) {
|
||||
if(container.scrollTop === 0) {
|
||||
stat.innerHTML = 'it reaches the top!';
|
||||
}
|
||||
else if (container.scrollTop === container.scrollHeight - container.clientHeight) {
|
||||
stat.innerHTML = 'it reaches the end!';
|
||||
} else {
|
||||
stat.innerHTML = '';
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -6,27 +6,39 @@
|
||||
<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: 600px; height: 400px; overflow: auto; }
|
||||
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
|
||||
.spacer { text-align:center }
|
||||
h1 { text-align: center; }
|
||||
.container { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
|
||||
.container .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
|
||||
|
||||
.ps-scrollbar-x-rail {
|
||||
margin: 0 3px;
|
||||
.large-margin .ps-scrollbar-x-rail {
|
||||
margin: 0 25%;
|
||||
opacity: 0.5;
|
||||
background-color: #eee;
|
||||
}
|
||||
.ps-scrollbar-y-rail {
|
||||
margin: 3px 0;
|
||||
.large-margin .ps-scrollbar-y-rail {
|
||||
margin: 100px 0;
|
||||
opacity: 0.5;
|
||||
background-color: #eee;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="Default" class="contentHolder">
|
||||
<h1>Default</h1>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Margins</h1>
|
||||
<div class="container large-margin">
|
||||
<div class="content">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var $ = document.querySelector.bind(document);
|
||||
window.onload = function () {
|
||||
Ps.initialize($('#Default'));
|
||||
[].forEach.call(document.querySelectorAll('.container'), function (el) {
|
||||
Ps.initialize(el);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
<script>
|
||||
var $ = document.querySelector.bind(document);
|
||||
window.onload = function () {
|
||||
Ps.initialize($('#description'));
|
||||
Ps.initialize($('#description'), {
|
||||
useSelectionScroll: true
|
||||
});
|
||||
};
|
||||
$('#redraw').addEventListener('click', function () {
|
||||
var oldHtml = $('#description').innerHTML;
|
||||
|
||||
138
gulpfile.js
138
gulpfile.js
@@ -1,16 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp')
|
||||
, browserify = require('browserify')
|
||||
, bump = require('gulp-bump')
|
||||
, connect = require('gulp-connect')
|
||||
, eslint = require('gulp-eslint')
|
||||
, rename = require('gulp-rename')
|
||||
, rimraf = require('gulp-rimraf')
|
||||
, sass = require('gulp-sass')
|
||||
, transform = require('vinyl-transform')
|
||||
, uglify = require('gulp-uglify')
|
||||
, zip = require('gulp-zip');
|
||||
var autoprefixer = require('gulp-autoprefixer');
|
||||
var browserify = require('browserify');
|
||||
var buffer = require('vinyl-buffer');
|
||||
var connect = require('gulp-connect');
|
||||
var del = require('del');
|
||||
var eslint = require('gulp-eslint');
|
||||
var gulp = require('gulp');
|
||||
var insert = require('gulp-insert');
|
||||
var path = require('path');
|
||||
var rename = require('gulp-rename');
|
||||
var sass = require('gulp-sass');
|
||||
var source = require('vinyl-source-stream');
|
||||
var stream = require('event-stream');
|
||||
var uglify = require('gulp-uglify');
|
||||
var zip = require('gulp-zip');
|
||||
|
||||
var version = '/* perfect-scrollbar v' + require('./package').version + ' */\n';
|
||||
|
||||
gulp.task('lint', function () {
|
||||
return gulp.src(['./src/**/*.js', './gulpfile.js'])
|
||||
@@ -20,94 +26,90 @@ gulp.task('lint', function () {
|
||||
});
|
||||
|
||||
gulp.task('clean:js', function () {
|
||||
return gulp.src('./dist/js/*.js', {read: false})
|
||||
.pipe(rimraf());
|
||||
return del(['./dist/js/*.js']);
|
||||
});
|
||||
|
||||
gulp.task('clean:js:min', function () {
|
||||
return gulp.src('./dist/js/min/*.js', {read: false})
|
||||
.pipe(rimraf());
|
||||
return del(['./dist/js/*.min.js']);
|
||||
});
|
||||
|
||||
function browserified() {
|
||||
return transform(function (filename) {
|
||||
var b = browserify(filename);
|
||||
return b.bundle();
|
||||
});
|
||||
}
|
||||
var jsEntries = [
|
||||
'./src/js/adaptor/global.js',
|
||||
'./src/js/adaptor/jquery.js'
|
||||
];
|
||||
|
||||
var autoPrefixerConfig = {
|
||||
browsers: ['> 0%'], // '> 0%' forces autoprefixer to use all the possible prefixes. See https://github.com/ai/browserslist#queries for more details. IMO 'last 3 versions' would be good enough.
|
||||
cascade: false
|
||||
};
|
||||
|
||||
gulp.task('js', ['clean:js'], function () {
|
||||
return gulp.src('./src/js/adaptor/*.js')
|
||||
.pipe(browserified())
|
||||
.pipe(rename(function (path) {
|
||||
if (path.basename === 'global') {
|
||||
path.basename = 'perfect-scrollbar';
|
||||
} else {
|
||||
path.basename = 'perfect-scrollbar.' + path.basename;
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('./dist/js'))
|
||||
.pipe(connect.reload());
|
||||
var tasks = jsEntries.map(function (src) {
|
||||
return browserify([src]).bundle()
|
||||
.pipe(source(path.basename(src)))
|
||||
.pipe(buffer())
|
||||
.pipe(insert.prepend(version))
|
||||
.pipe(rename(function (path) {
|
||||
if (path.basename === 'global') {
|
||||
path.basename = 'perfect-scrollbar';
|
||||
} else {
|
||||
path.basename = 'perfect-scrollbar.' + path.basename;
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('./dist/js'))
|
||||
.pipe(connect.reload());
|
||||
});
|
||||
return stream.merge.apply(null, tasks);
|
||||
});
|
||||
|
||||
gulp.task('js:min', ['clean:js:min'], function () {
|
||||
return gulp.src('./src/js/adaptor/*.js')
|
||||
.pipe(browserified())
|
||||
.pipe(uglify())
|
||||
.pipe(rename(function (path) {
|
||||
if (path.basename === 'global') {
|
||||
path.basename = 'perfect-scrollbar.min';
|
||||
} else {
|
||||
path.basename = 'perfect-scrollbar.' + path.basename + '.min';
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('./dist/js/min'));
|
||||
var tasks = jsEntries.map(function (src) {
|
||||
return browserify([src]).bundle()
|
||||
.pipe(source(path.basename(src)))
|
||||
.pipe(buffer())
|
||||
.pipe(uglify())
|
||||
.pipe(insert.prepend(version))
|
||||
.pipe(rename(function (path) {
|
||||
if (path.basename === 'global') {
|
||||
path.basename = 'perfect-scrollbar.min';
|
||||
} else {
|
||||
path.basename = 'perfect-scrollbar.' + path.basename + '.min';
|
||||
}
|
||||
}))
|
||||
.pipe(gulp.dest('./dist/js'))
|
||||
.pipe(connect.reload());
|
||||
});
|
||||
return stream.merge.apply(null, tasks);
|
||||
});
|
||||
|
||||
gulp.task('clean:css', function () {
|
||||
return gulp.src('./dist/css/perfect-scrollbar.css', {read: false})
|
||||
.pipe(rimraf());
|
||||
return del(['./dist/css/perfect-scrollbar.css']);
|
||||
});
|
||||
|
||||
gulp.task('clean:css:min', function () {
|
||||
return gulp.src('./dist/css/perfect-scrollbar.min.css', {read: false})
|
||||
.pipe(rimraf());
|
||||
return del(['./dist/css/perfect-scrollbar.min.css']);
|
||||
});
|
||||
|
||||
gulp.task('sass', ['clean:css'], function () {
|
||||
gulp.task('css', ['clean:css'], function () {
|
||||
return gulp.src('./src/css/main.scss')
|
||||
.pipe(sass())
|
||||
.pipe(autoprefixer(autoPrefixerConfig))
|
||||
.pipe(insert.prepend(version))
|
||||
.pipe(rename('perfect-scrollbar.css'))
|
||||
.pipe(gulp.dest('./dist/css'))
|
||||
.pipe(connect.reload());
|
||||
});
|
||||
|
||||
gulp.task('sass:min', ['clean:css:min'], function () {
|
||||
gulp.task('css:min', ['clean:css:min'], function () {
|
||||
return gulp.src('./src/css/main.scss')
|
||||
.pipe(sass({outputStyle: 'compressed'}))
|
||||
.pipe(autoprefixer(autoPrefixerConfig))
|
||||
.pipe(insert.prepend(version))
|
||||
.pipe(rename('perfect-scrollbar.min.css'))
|
||||
.pipe(gulp.dest('./dist/css'));
|
||||
});
|
||||
|
||||
function bumpType() {
|
||||
if (gulp.env.major) {
|
||||
return 'major';
|
||||
} else if (gulp.env.minor) {
|
||||
return 'minor';
|
||||
} else {
|
||||
return 'patch';
|
||||
}
|
||||
}
|
||||
|
||||
gulp.task('bump', function () {
|
||||
gulp.src('./*.json')
|
||||
.pipe(bump({type: bumpType()}))
|
||||
.pipe(gulp.dest('./'));
|
||||
});
|
||||
|
||||
gulp.task('release', ['bump', 'build']);
|
||||
|
||||
gulp.task('build', ['js', 'js:min', 'sass', 'sass:min']);
|
||||
gulp.task('build', ['js', 'js:min', 'css', 'css:min']);
|
||||
|
||||
gulp.task('connect', ['build'], function () {
|
||||
connect.server({
|
||||
|
||||
3
index.js
3
index.js
@@ -1,6 +1,3 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./src/js/main');
|
||||
|
||||
3
jquery.js
vendored
3
jquery.js
vendored
@@ -1,6 +1,3 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./src/js/adaptor/jquery');
|
||||
|
||||
51
package.json
51
package.json
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "perfect-scrollbar",
|
||||
"version": "0.6.0",
|
||||
"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"
|
||||
}
|
||||
],
|
||||
@@ -24,23 +24,44 @@
|
||||
"scrollbar"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
"node": ">= 0.12.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"index.js",
|
||||
"jquery.js",
|
||||
"perfect-scrollbar.d.ts"
|
||||
],
|
||||
"devDependencies": {
|
||||
"browserify": "^8.1.1",
|
||||
"gulp": "^3.8.10",
|
||||
"gulp-bump": "^0.1.11",
|
||||
"browserify": "^11.2.0",
|
||||
"del": "^2.0.2",
|
||||
"event-stream": "^3.3.1",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-autoprefixer": "^3.1.0",
|
||||
"gulp-connect": "^2.2.0",
|
||||
"gulp-eslint": "^0.2.0",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-rimraf": "^0.1.1",
|
||||
"gulp-sass": "^1.3.1",
|
||||
"gulp-uglify": "^1.0.2",
|
||||
"gulp-zip": "^2.0.2",
|
||||
"vinyl-transform": "^1.0.0"
|
||||
"gulp-eslint": "^1.0.0",
|
||||
"gulp-insert": "^0.5.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-sass": "^2.0.4",
|
||||
"gulp-uglify": "^1.4.1",
|
||||
"gulp-zip": "^3.0.2",
|
||||
"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"
|
||||
"test": "gulp",
|
||||
"before-deploy": "gulp && gulp compress",
|
||||
"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,129 +1,3 @@
|
||||
// Colors
|
||||
$ps-rail-hover: #eee;
|
||||
$ps-bar-default: #aaa;
|
||||
$ps-bar-hover: #999;
|
||||
|
||||
// Helper mixins
|
||||
@mixin opacity($o) {
|
||||
$IEValue: $o * 100;
|
||||
opacity: $o;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity="+$IEValue+")";
|
||||
filter: alpha(opacity=$IEValue);
|
||||
}
|
||||
|
||||
@mixin border-radius($r) {
|
||||
-webkit-border-radius: $r;
|
||||
-moz-border-radius: $r;
|
||||
-ms-border-radius: $r;
|
||||
border-radius: $r;
|
||||
}
|
||||
|
||||
@mixin transition($t...) {
|
||||
-webkit-transition: $t;
|
||||
-moz-transition: $t;
|
||||
-o-transition: $t;
|
||||
transition: $t;
|
||||
}
|
||||
|
||||
// Scrollbar mixins
|
||||
@mixin scrollbar-rail-default {
|
||||
display: none;
|
||||
position: absolute; /* please don't change 'position' */
|
||||
@include border-radius(4px);
|
||||
@include opacity(0);
|
||||
@include transition(background-color .2s linear, opacity .2s linear);
|
||||
}
|
||||
|
||||
@mixin scrollbar-rail-hover {
|
||||
background-color: $ps-rail-hover;
|
||||
@include opacity(0.9);
|
||||
}
|
||||
|
||||
@mixin scrollbar-default {
|
||||
position: absolute; /* please don't change 'position' */
|
||||
background-color: $ps-bar-default;
|
||||
@include border-radius(4px);
|
||||
@include transition(background-color .2s linear);
|
||||
}
|
||||
|
||||
@mixin scrollbar-hover {
|
||||
background-color: $ps-bar-hover;
|
||||
}
|
||||
|
||||
@mixin in-scrolling {
|
||||
&.ps-in-scrolling {
|
||||
pointer-events: none;
|
||||
&.ps-x>.ps-scrollbar-x-rail{
|
||||
@include scrollbar-rail-hover;
|
||||
>.ps-scrollbar-x {
|
||||
@include scrollbar-hover;
|
||||
}
|
||||
}
|
||||
&.ps-y>.ps-scrollbar-y-rail {
|
||||
@include scrollbar-rail-hover;
|
||||
>.ps-scrollbar-y {
|
||||
@include scrollbar-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ps-container {
|
||||
overflow: hidden !important;
|
||||
|
||||
&.ps-active-x > .ps-scrollbar-x-rail,
|
||||
&.ps-active-y > .ps-scrollbar-y-rail {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@include in-scrolling;
|
||||
|
||||
>.ps-scrollbar-x-rail {
|
||||
@include scrollbar-rail-default;
|
||||
bottom: 3px; /* there must be 'bottom' for ps-scrollbar-x-rail */
|
||||
height: 8px;
|
||||
|
||||
>.ps-scrollbar-x {
|
||||
@include scrollbar-default;
|
||||
bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */
|
||||
height: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
>.ps-scrollbar-y-rail {
|
||||
@include scrollbar-rail-default;
|
||||
right: 3px; /* there must be 'right' for ps-scrollbar-y-rail */
|
||||
width: 8px;
|
||||
|
||||
>.ps-scrollbar-y {
|
||||
@include scrollbar-default;
|
||||
right: 0; /* there must be 'right' for ps-scrollbar-y */
|
||||
width: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include in-scrolling;
|
||||
|
||||
>.ps-scrollbar-x-rail,
|
||||
>.ps-scrollbar-y-rail {
|
||||
@include opacity(0.6);
|
||||
}
|
||||
|
||||
>.ps-scrollbar-x-rail:hover {
|
||||
@include scrollbar-rail-hover;
|
||||
|
||||
>.ps-scrollbar-x {
|
||||
@include scrollbar-hover;
|
||||
}
|
||||
}
|
||||
|
||||
>.ps-scrollbar-y-rail:hover {
|
||||
@include scrollbar-rail-hover;
|
||||
|
||||
>.ps-scrollbar-y {
|
||||
@include scrollbar-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
@import 'themes';
|
||||
|
||||
128
src/css/mixins.scss
Normal file
128
src/css/mixins.scss
Normal file
@@ -0,0 +1,128 @@
|
||||
@mixin scrollbar-rail-default($theme) {
|
||||
display: none;
|
||||
position: absolute; /* please don't change 'position' */
|
||||
opacity: map_get($theme, rail-default-opacity);
|
||||
transition: background-color .2s linear, opacity .2s linear;
|
||||
}
|
||||
|
||||
@mixin scrollbar-rail-hover($theme) {
|
||||
background-color: map_get($theme, rail-hover-bg);
|
||||
opacity: map_get($theme, rail-hover-opacity);
|
||||
}
|
||||
|
||||
@mixin scrollbar-default($theme) {
|
||||
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, height .2s linear, width .2s ease-in-out,
|
||||
border-radius .2s ease-in-out;
|
||||
}
|
||||
|
||||
@mixin scrollbar-hover($theme) {
|
||||
background-color: map_get($theme, bar-hover-bg);
|
||||
}
|
||||
|
||||
@mixin in-scrolling($theme) {
|
||||
&.ps-in-scrolling {
|
||||
&.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layout and theme mixin
|
||||
@mixin ps-container($theme) {
|
||||
-ms-touch-action: auto;
|
||||
touch-action: auto;
|
||||
overflow: hidden !important;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
// Edge
|
||||
@supports (-ms-overflow-style: none) {
|
||||
overflow: auto !important;
|
||||
}
|
||||
// IE10+
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
&.ps-active-x > .ps-scrollbar-x-rail,
|
||||
&.ps-active-y > .ps-scrollbar-y-rail {
|
||||
display: block;
|
||||
background-color: map_get($theme, bar-bg);
|
||||
}
|
||||
|
||||
@include in-scrolling($theme);
|
||||
|
||||
> .ps-scrollbar-x-rail {
|
||||
@include scrollbar-rail-default($theme);
|
||||
bottom: map_get($theme, scrollbar-x-rail-bottom); /* there must be 'bottom' for ps-scrollbar-x-rail */
|
||||
height: map_get($theme, scrollbar-x-rail-height);
|
||||
|
||||
> .ps-scrollbar-x {
|
||||
@include scrollbar-default($theme);
|
||||
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 {
|
||||
@include scrollbar-rail-default($theme);
|
||||
right: map_get($theme, scrollbar-y-rail-right); /* there must be 'right' for ps-scrollbar-y-rail */
|
||||
width: map_get($theme, scrollbar-y-rail-width);
|
||||
|
||||
> .ps-scrollbar-y {
|
||||
@include scrollbar-default($theme);
|
||||
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 {
|
||||
@include in-scrolling($theme);
|
||||
|
||||
> .ps-scrollbar-x-rail,
|
||||
> .ps-scrollbar-y-rail {
|
||||
opacity: map_get($theme, rail-container-hover-opacity);
|
||||
}
|
||||
|
||||
> .ps-scrollbar-x-rail:hover {
|
||||
@include scrollbar-rail-hover($theme);
|
||||
|
||||
> .ps-scrollbar-x {
|
||||
@include scrollbar-hover($theme);
|
||||
}
|
||||
}
|
||||
|
||||
> .ps-scrollbar-y-rail:hover {
|
||||
@include scrollbar-rail-hover($theme);
|
||||
|
||||
> .ps-scrollbar-y {
|
||||
@include scrollbar-hover($theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/css/themes.scss
Normal file
25
src/css/themes.scss
Normal file
@@ -0,0 +1,25 @@
|
||||
$ps-theme-default: (
|
||||
border-radius: $ps-border-radius,
|
||||
rail-default-opacity: $ps-rail-default-opacity,
|
||||
rail-container-hover-opacity: $ps-rail-container-hover-opacity,
|
||||
rail-hover-opacity: $ps-rail-hover-opacity,
|
||||
bar-bg: $ps-bar-bg,
|
||||
bar-container-hover-bg: $ps-bar-container-hover-bg,
|
||||
bar-hover-bg: $ps-bar-hover-bg,
|
||||
rail-hover-bg: $ps-rail-hover-bg,
|
||||
scrollbar-x-rail-bottom: $ps-scrollbar-x-rail-bottom,
|
||||
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
|
||||
.ps-container {
|
||||
@include ps-container($ps-theme-default);
|
||||
}
|
||||
24
src/css/variables.scss
Normal file
24
src/css/variables.scss
Normal file
@@ -0,0 +1,24 @@
|
||||
// Colors
|
||||
$ps-border-radius: 6px !default;
|
||||
|
||||
$ps-rail-default-opacity: 0 !default;
|
||||
$ps-rail-container-hover-opacity: 0.6 !default;
|
||||
$ps-rail-hover-opacity: 0.9 !default;
|
||||
|
||||
$ps-bar-bg: transparent !default;
|
||||
$ps-bar-container-hover-bg: #aaa !default;
|
||||
$ps-bar-hover-bg: #999 !default;
|
||||
$ps-rail-hover-bg: #eee !default;
|
||||
|
||||
// Sizes
|
||||
$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: 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;
|
||||
@@ -1,6 +1,3 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ps = require('../main');
|
||||
|
||||
9
src/js/adaptor/jquery.js
vendored
9
src/js/adaptor/jquery.js
vendored
@@ -1,10 +1,7 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ps = require('../main')
|
||||
, psInstances = require('../plugin/instances');
|
||||
var ps = require('../main');
|
||||
var psInstances = require('../plugin/instances');
|
||||
|
||||
function mountJQuery(jQuery) {
|
||||
jQuery.fn.perfectScrollbar = function (settingOrCommand) {
|
||||
@@ -27,8 +24,6 @@ function mountJQuery(jQuery) {
|
||||
ps.destroy(this);
|
||||
}
|
||||
}
|
||||
|
||||
return $(this);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function oldAdd(element, className) {
|
||||
@@ -38,7 +35,7 @@ exports.remove = function (element, className) {
|
||||
|
||||
exports.list = function (element) {
|
||||
if (element.classList) {
|
||||
return element.classList;
|
||||
return Array.prototype.slice.apply(element.classList);
|
||||
} else {
|
||||
return element.className.split(' ');
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
exports.e = function (tagName, className) {
|
||||
var DOM = {};
|
||||
|
||||
DOM.e = function (tagName, className) {
|
||||
var element = document.createElement(tagName);
|
||||
element.className = className;
|
||||
return element;
|
||||
};
|
||||
|
||||
exports.appendTo = function (child, parent) {
|
||||
DOM.appendTo = function (child, parent) {
|
||||
parent.appendChild(child);
|
||||
return child;
|
||||
};
|
||||
|
||||
function cssGet(element, styleName) {
|
||||
return window.getComputedStyle(element)[styleName];
|
||||
var style = window.getComputedStyle(element);
|
||||
return style
|
||||
? style[styleName]
|
||||
: null;
|
||||
}
|
||||
|
||||
function cssSet(element, styleName, styleValue) {
|
||||
@@ -37,7 +39,7 @@ function cssMultiSet(element, obj) {
|
||||
return element;
|
||||
}
|
||||
|
||||
exports.css = function (element, styleNameOrObject, styleValue) {
|
||||
DOM.css = function (element, styleNameOrObject, styleValue) {
|
||||
if (typeof styleNameOrObject === 'object') {
|
||||
// multiple set with object
|
||||
return cssMultiSet(element, styleNameOrObject);
|
||||
@@ -50,7 +52,7 @@ exports.css = function (element, styleNameOrObject, styleValue) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.matches = function (element, query) {
|
||||
DOM.matches = function (element, query) {
|
||||
if (typeof element.matches !== 'undefined') {
|
||||
return element.matches(query);
|
||||
} else {
|
||||
@@ -66,10 +68,20 @@ exports.matches = function (element, query) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.remove = function (element) {
|
||||
DOM.remove = function (element) {
|
||||
if (typeof element.remove !== 'undefined') {
|
||||
element.remove();
|
||||
} else {
|
||||
element.parentNode.removeChild(element);
|
||||
if (element.parentNode) {
|
||||
element.parentNode.removeChild(element);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DOM.queryChildren = function (element, selector) {
|
||||
return Array.prototype.filter.call(element.childNodes, function (child) {
|
||||
return DOM.matches(child, selector);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = DOM;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var EventElement = function (element) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = (function () {
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var cls = require('./class')
|
||||
, d = require('./dom');
|
||||
var cls = require('./class');
|
||||
var dom = require('./dom');
|
||||
|
||||
exports.toInt = function (x) {
|
||||
if (typeof x === 'string') {
|
||||
return parseInt(x, 10);
|
||||
} else {
|
||||
return ~~x;
|
||||
}
|
||||
var toInt = exports.toInt = function (x) {
|
||||
return parseInt(x, 10) || 0;
|
||||
};
|
||||
|
||||
exports.clone = function (obj) {
|
||||
if (obj === null) {
|
||||
var clone = exports.clone = function (obj) {
|
||||
if (!obj) {
|
||||
return null;
|
||||
} else if (Array.isArray(obj)) {
|
||||
return obj.map(clone);
|
||||
} else if (typeof obj === 'object') {
|
||||
var result = {};
|
||||
for (var key in obj) {
|
||||
result[key] = this.clone(obj[key]);
|
||||
result[key] = clone(obj[key]);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
@@ -28,19 +23,39 @@ 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 = this.clone(original);
|
||||
var result = clone(original);
|
||||
for (var key in source) {
|
||||
result[key] = this.clone(source[key]);
|
||||
result[key] = clone(source[key]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.isEditable = function (el) {
|
||||
return d.matches(el, "input,[contenteditable]") ||
|
||||
d.matches(el, "select,[contenteditable]") ||
|
||||
d.matches(el, "textarea,[contenteditable]") ||
|
||||
d.matches(el, "button,[contenteditable]");
|
||||
return dom.matches(el, "input,[contenteditable]") ||
|
||||
dom.matches(el, "select,[contenteditable]") ||
|
||||
dom.matches(el, "textarea,[contenteditable]") ||
|
||||
dom.matches(el, "button,[contenteditable]");
|
||||
};
|
||||
|
||||
exports.removePsClasses = function (element) {
|
||||
@@ -54,11 +69,11 @@ exports.removePsClasses = function (element) {
|
||||
};
|
||||
|
||||
exports.outerWidth = function (element) {
|
||||
return this.toInt(d.css(element, 'width')) +
|
||||
this.toInt(d.css(element, 'paddingLeft')) +
|
||||
this.toInt(d.css(element, 'paddingRight')) +
|
||||
this.toInt(d.css(element, 'borderLeftWidth')) +
|
||||
this.toInt(d.css(element, 'borderRightWidth'));
|
||||
return toInt(dom.css(element, 'width')) +
|
||||
toInt(dom.css(element, 'paddingLeft')) +
|
||||
toInt(dom.css(element, 'paddingRight')) +
|
||||
toInt(dom.css(element, 'borderLeftWidth')) +
|
||||
toInt(dom.css(element, 'borderRightWidth'));
|
||||
};
|
||||
|
||||
exports.startScrolling = function (element, axis) {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var destroy = require('./plugin/destroy')
|
||||
, initialize = require('./plugin/initialize')
|
||||
, update = require('./plugin/update');
|
||||
var destroy = require('./plugin/destroy');
|
||||
var initialize = require('./plugin/initialize');
|
||||
var update = require('./plugin/update');
|
||||
|
||||
module.exports = {
|
||||
initialize: initialize,
|
||||
|
||||
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);
|
||||
};
|
||||
@@ -1,18 +1,17 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
wheelSpeed: 1,
|
||||
wheelPropagation: false,
|
||||
swipePropagation: true,
|
||||
minScrollbarLength: null,
|
||||
handlers: ['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch'],
|
||||
maxScrollbarLength: null,
|
||||
useBothWheelAxes: false,
|
||||
useKeyboard: true,
|
||||
minScrollbarLength: null,
|
||||
scrollXMarginOffset: 0,
|
||||
scrollYMarginOffset: 0,
|
||||
suppressScrollX: false,
|
||||
suppressScrollY: false,
|
||||
scrollXMarginOffset: 0,
|
||||
scrollYMarginOffset: 0
|
||||
swipePropagation: true,
|
||||
useBothWheelAxes: false,
|
||||
wheelPropagation: false,
|
||||
wheelSpeed: 1,
|
||||
theme: 'default',
|
||||
autoupdate: true
|
||||
};
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var d = require('../lib/dom')
|
||||
, h = require('../lib/helper')
|
||||
, instances = require('./instances');
|
||||
var _ = require('../lib/helper');
|
||||
var dom = require('../lib/dom');
|
||||
var instances = require('./instances');
|
||||
|
||||
module.exports = function (element) {
|
||||
var i = instances.get(element);
|
||||
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (i.observer) {
|
||||
i.observer.disconnect();
|
||||
}
|
||||
|
||||
i.event.unbindAll();
|
||||
d.remove(i.scrollbarX);
|
||||
d.remove(i.scrollbarY);
|
||||
d.remove(i.scrollbarXRail);
|
||||
d.remove(i.scrollbarYRail);
|
||||
h.removePsClasses(element);
|
||||
dom.remove(i.scrollbarX);
|
||||
dom.remove(i.scrollbarY);
|
||||
dom.remove(i.scrollbarXRail);
|
||||
dom.remove(i.scrollbarYRail);
|
||||
_.removePsClasses(element);
|
||||
|
||||
instances.remove(element);
|
||||
};
|
||||
|
||||
@@ -1,51 +1,35 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var h = require('../../lib/helper')
|
||||
, instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
|
||||
function bindClickRailHandler(element, i) {
|
||||
function pageOffset(el) {
|
||||
return el.getBoundingClientRect();
|
||||
}
|
||||
var stopPropagation = window.Event.prototype.stopPropagation.bind;
|
||||
var stopPropagation = function (e) { e.stopPropagation(); };
|
||||
|
||||
i.event.bind(i.scrollbarY, 'click', stopPropagation);
|
||||
i.event.bind(i.scrollbarYRail, 'click', function (e) {
|
||||
var halfOfScrollbarLength = h.toInt(i.scrollbarYHeight / 2);
|
||||
var positionTop = e.pageY - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength;
|
||||
var maxPositionTop = i.containerHeight - 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;
|
||||
}
|
||||
|
||||
element.scrollTop = (i.contentHeight - i.containerHeight) * positionRatio;
|
||||
updateScroll(element, 'top', element.scrollTop + direction * i.containerHeight);
|
||||
updateGeometry(element);
|
||||
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
i.event.bind(i.scrollbarX, 'click', stopPropagation);
|
||||
i.event.bind(i.scrollbarXRail, 'click', function (e) {
|
||||
var halfOfScrollbarLength = h.toInt(i.scrollbarXWidth / 2);
|
||||
var positionLeft = e.pageX - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength;
|
||||
console.log(e.pageX, i.scrollbarXRail.offsetLeft);
|
||||
var maxPositionLeft = i.containerWidth - 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;
|
||||
}
|
||||
|
||||
element.scrollLeft = (i.contentWidth - i.containerWidth) * positionRatio;
|
||||
updateScroll(element, 'left', element.scrollLeft + direction * i.containerWidth);
|
||||
updateGeometry(element);
|
||||
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var d = require('../../lib/dom')
|
||||
, h = require('../../lib/helper')
|
||||
, instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var _ = require('../../lib/helper');
|
||||
var dom = require('../../lib/dom');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
|
||||
function bindMouseScrollXHandler(element, i) {
|
||||
var currentLeft = null;
|
||||
var currentPageX = null;
|
||||
|
||||
function updateScrollLeft(deltaX) {
|
||||
var newLeft = currentLeft + deltaX;
|
||||
var maxLeft = i.containerWidth - i.scrollbarXWidth;
|
||||
var newLeft = currentLeft + (deltaX * i.railXRatio);
|
||||
var maxLeft = Math.max(0, i.scrollbarXRail.getBoundingClientRect().left) + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth));
|
||||
|
||||
if (newLeft < 0) {
|
||||
i.scrollbarXLeft = 0;
|
||||
@@ -24,8 +22,8 @@ function bindMouseScrollXHandler(element, i) {
|
||||
i.scrollbarXLeft = newLeft;
|
||||
}
|
||||
|
||||
var scrollLeft = h.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - i.scrollbarXWidth));
|
||||
element.scrollLeft = scrollLeft;
|
||||
var scrollLeft = _.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - (i.railXRatio * i.scrollbarXWidth))) - i.negativeScrollAdjustment;
|
||||
updateScroll(element, 'left', scrollLeft);
|
||||
}
|
||||
|
||||
var mouseMoveHandler = function (e) {
|
||||
@@ -36,14 +34,14 @@ function bindMouseScrollXHandler(element, i) {
|
||||
};
|
||||
|
||||
var mouseUpHandler = function () {
|
||||
h.stopScrolling(element, 'x');
|
||||
_.stopScrolling(element, 'x');
|
||||
i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||
};
|
||||
|
||||
i.event.bind(i.scrollbarX, 'mousedown', function (e) {
|
||||
currentPageX = e.pageX;
|
||||
currentLeft = h.toInt(d.css(i.scrollbarX, 'left'));
|
||||
h.startScrolling(element, 'x');
|
||||
currentLeft = _.toInt(dom.css(i.scrollbarX, 'left')) * i.railXRatio;
|
||||
_.startScrolling(element, 'x');
|
||||
|
||||
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
|
||||
@@ -58,8 +56,8 @@ function bindMouseScrollYHandler(element, i) {
|
||||
var currentPageY = null;
|
||||
|
||||
function updateScrollTop(deltaY) {
|
||||
var newTop = currentTop + deltaY;
|
||||
var maxTop = i.containerHeight - i.scrollbarYHeight;
|
||||
var newTop = currentTop + (deltaY * i.railYRatio);
|
||||
var maxTop = Math.max(0, i.scrollbarYRail.getBoundingClientRect().top) + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight));
|
||||
|
||||
if (newTop < 0) {
|
||||
i.scrollbarYTop = 0;
|
||||
@@ -69,8 +67,8 @@ function bindMouseScrollYHandler(element, i) {
|
||||
i.scrollbarYTop = newTop;
|
||||
}
|
||||
|
||||
var scrollTop = h.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - i.scrollbarYHeight));
|
||||
element.scrollTop = scrollTop;
|
||||
var scrollTop = _.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - (i.railYRatio * i.scrollbarYHeight)));
|
||||
updateScroll(element, 'top', scrollTop);
|
||||
}
|
||||
|
||||
var mouseMoveHandler = function (e) {
|
||||
@@ -81,14 +79,14 @@ function bindMouseScrollYHandler(element, i) {
|
||||
};
|
||||
|
||||
var mouseUpHandler = function () {
|
||||
h.stopScrolling(element, 'y');
|
||||
_.stopScrolling(element, 'y');
|
||||
i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||
};
|
||||
|
||||
i.event.bind(i.scrollbarY, 'mousedown', function (e) {
|
||||
currentPageY = e.pageY;
|
||||
currentTop = h.toInt(d.css(i.scrollbarY, 'top'));
|
||||
h.startScrolling(element, 'y');
|
||||
currentTop = _.toInt(dom.css(i.scrollbarY, 'top')) * i.railYRatio;
|
||||
_.startScrolling(element, 'y');
|
||||
|
||||
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
|
||||
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var h = require('../../lib/helper')
|
||||
, instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var _ = require('../../lib/helper');
|
||||
var dom = require('../../lib/dom');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
|
||||
function bindKeyboardHandler(element, i) {
|
||||
var hovered = false;
|
||||
@@ -41,21 +40,28 @@ 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;
|
||||
}
|
||||
|
||||
if (!hovered) {
|
||||
var focused = dom.matches(i.scrollbarX, ':focus') ||
|
||||
dom.matches(i.scrollbarY, ':focus');
|
||||
|
||||
if (!hovered && !focused) {
|
||||
return;
|
||||
}
|
||||
|
||||
var activeElement = document.activeElement ? document.activeElement : i.ownerDocument.activeElement;
|
||||
if (activeElement) {
|
||||
// go deeper if element is a webcomponent
|
||||
while (activeElement.shadowRoot) {
|
||||
activeElement = activeElement.shadowRoot.activeElement;
|
||||
if (activeElement.tagName === 'IFRAME') {
|
||||
activeElement = activeElement.contentDocument.activeElement;
|
||||
} else {
|
||||
// go deeper if element is a webcomponent
|
||||
while (activeElement.shadowRoot) {
|
||||
activeElement = activeElement.shadowRoot.activeElement;
|
||||
}
|
||||
}
|
||||
if (h.isEditable(activeElement)) {
|
||||
if (_.isEditable(activeElement)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -65,21 +71,51 @@ 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;
|
||||
break;
|
||||
case 32: // space bar
|
||||
if (e.shiftKey) {
|
||||
deltaY = 90;
|
||||
} else {
|
||||
deltaY = -90;
|
||||
}
|
||||
break;
|
||||
case 34: // page down
|
||||
deltaY = -90;
|
||||
break;
|
||||
@@ -101,8 +137,8 @@ function bindKeyboardHandler(element, i) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.scrollTop = element.scrollTop - deltaY;
|
||||
element.scrollLeft = element.scrollLeft + deltaX;
|
||||
updateScroll(element, 'top', element.scrollTop - deltaY);
|
||||
updateScroll(element, 'left', element.scrollLeft + deltaX);
|
||||
updateGeometry(element);
|
||||
|
||||
shouldPrevent = shouldPreventDefault(deltaX, deltaY);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var h = require('../../lib/helper')
|
||||
, instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
|
||||
function bindMouseWheelHandler(element, i) {
|
||||
var shouldPrevent = false;
|
||||
@@ -55,44 +52,69 @@ function bindMouseWheelHandler(element, i) {
|
||||
deltaY = e.wheelDelta;
|
||||
}
|
||||
|
||||
if (e.shiftKey) {
|
||||
// reverse axis with shift key
|
||||
return [-deltaY, -deltaX];
|
||||
}
|
||||
return [deltaX, deltaY];
|
||||
}
|
||||
|
||||
function mousewheelHandler(e) {
|
||||
// FIXME: this is a quick fix for the select problem in FF and IE.
|
||||
// If there comes an effective way to deal with the problem,
|
||||
// this lines should be removed.
|
||||
if (!h.env.isWebKit && element.querySelector('select:focus')) {
|
||||
return;
|
||||
}
|
||||
function shouldBeConsumedByChild(deltaX, deltaY) {
|
||||
var child = element.querySelector('textarea:hover, select[multiple]:hover, .ps-child:hover');
|
||||
if (child) {
|
||||
if (!window.getComputedStyle(child).overflow.match(/(scroll|auto)/)) {
|
||||
// if not scrollable
|
||||
return false;
|
||||
}
|
||||
|
||||
var maxScrollTop = child.scrollHeight - child.clientHeight;
|
||||
if (maxScrollTop > 0) {
|
||||
if (!(child.scrollTop === 0 && deltaY > 0) && !(child.scrollTop === maxScrollTop && deltaY < 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
var maxScrollLeft = child.scrollLeft - child.clientWidth;
|
||||
if (maxScrollLeft > 0) {
|
||||
if (!(child.scrollLeft === 0 && deltaX < 0) && !(child.scrollLeft === maxScrollLeft && deltaX > 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function mousewheelHandler(e) {
|
||||
var delta = getDeltaFromEvent(e);
|
||||
|
||||
var deltaX = delta[0];
|
||||
var deltaY = delta[1];
|
||||
|
||||
if (shouldBeConsumedByChild(deltaX, deltaY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
shouldPrevent = false;
|
||||
if (!i.settings.useBothWheelAxes) {
|
||||
// deltaX will only be used for horizontal scrolling and deltaY will
|
||||
// only be used for vertical scrolling - this is the default
|
||||
element.scrollTop = element.scrollTop - (deltaY * i.settings.wheelSpeed);
|
||||
element.scrollLeft = element.scrollLeft + (deltaX * i.settings.wheelSpeed);
|
||||
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
|
||||
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
|
||||
} else if (i.scrollbarYActive && !i.scrollbarXActive) {
|
||||
// only vertical scrollbar is active and useBothWheelAxes option is
|
||||
// active, so let's scroll vertical bar using both mouse wheel axes
|
||||
if (deltaY) {
|
||||
element.scrollTop = element.scrollTop - (deltaY * i.settings.wheelSpeed);
|
||||
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
|
||||
} else {
|
||||
element.scrollTop = element.scrollTop + (deltaX * i.settings.wheelSpeed);
|
||||
updateScroll(element, 'top', element.scrollTop + (deltaX * i.settings.wheelSpeed));
|
||||
}
|
||||
shouldPrevent = true;
|
||||
} else if (i.scrollbarXActive && !i.scrollbarYActive) {
|
||||
// useBothWheelAxes and only horizontal bar is active, so use both
|
||||
// wheel axes for horizontal bar
|
||||
if (deltaX) {
|
||||
element.scrollLeft = element.scrollLeft + (deltaX * i.settings.wheelSpeed);
|
||||
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
|
||||
} else {
|
||||
element.scrollLeft = element.scrollLeft - (deltaY * i.settings.wheelSpeed);
|
||||
updateScroll(element, 'left', element.scrollLeft - (deltaY * i.settings.wheelSpeed));
|
||||
}
|
||||
shouldPrevent = true;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
|
||||
function bindNativeScrollHandler(element, i) {
|
||||
i.event.bind(element, 'scroll', function () {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var h = require('../../lib/helper')
|
||||
, instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var _ = require('../../lib/helper');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
|
||||
function bindSelectionHandler(element, i) {
|
||||
function getRangeNode() {
|
||||
@@ -28,8 +26,8 @@ function bindSelectionHandler(element, i) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.scrollTop = element.scrollTop + scrollDiff.top;
|
||||
element.scrollLeft = element.scrollLeft + scrollDiff.left;
|
||||
updateScroll(element, 'top', element.scrollTop + scrollDiff.top);
|
||||
updateScroll(element, 'left', element.scrollLeft + scrollDiff.left);
|
||||
updateGeometry(element);
|
||||
}, 50); // every .1 sec
|
||||
}
|
||||
@@ -39,7 +37,7 @@ function bindSelectionHandler(element, i) {
|
||||
clearInterval(scrollingLoop);
|
||||
scrollingLoop = null;
|
||||
}
|
||||
h.stopScrolling(element);
|
||||
_.stopScrolling(element);
|
||||
}
|
||||
|
||||
var isSelected = false;
|
||||
@@ -57,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) {
|
||||
@@ -70,10 +74,10 @@ function bindSelectionHandler(element, i) {
|
||||
|
||||
if (mousePosition.x < containerGeometry.left + 3) {
|
||||
scrollDiff.left = -5;
|
||||
h.startScrolling(element, 'x');
|
||||
_.startScrolling(element, 'x');
|
||||
} else if (mousePosition.x > containerGeometry.right - 3) {
|
||||
scrollDiff.left = 5;
|
||||
h.startScrolling(element, 'x');
|
||||
_.startScrolling(element, 'x');
|
||||
} else {
|
||||
scrollDiff.left = 0;
|
||||
}
|
||||
@@ -84,14 +88,14 @@ function bindSelectionHandler(element, i) {
|
||||
} else {
|
||||
scrollDiff.top = -20;
|
||||
}
|
||||
h.startScrolling(element, 'y');
|
||||
_.startScrolling(element, 'y');
|
||||
} else if (mousePosition.y > containerGeometry.bottom - 3) {
|
||||
if (mousePosition.y - containerGeometry.bottom + 3 < 5) {
|
||||
scrollDiff.top = 5;
|
||||
} else {
|
||||
scrollDiff.top = 20;
|
||||
}
|
||||
h.startScrolling(element, 'y');
|
||||
_.startScrolling(element, 'y');
|
||||
} else {
|
||||
scrollDiff.top = 0;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var instances = require('../instances')
|
||||
, updateGeometry = require('../update-geometry');
|
||||
var _ = require('../../lib/helper');
|
||||
var instances = require('../instances');
|
||||
var updateGeometry = require('../update-geometry');
|
||||
var updateScroll = require('../update-scroll');
|
||||
|
||||
function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
function shouldPreventDefault(deltaX, deltaY) {
|
||||
@@ -33,8 +32,8 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
}
|
||||
|
||||
function applyTouchMove(differenceX, differenceY) {
|
||||
element.scrollTop = element.scrollTop - differenceY;
|
||||
element.scrollLeft = element.scrollLeft - differenceX;
|
||||
updateScroll(element, 'top', element.scrollTop - differenceY);
|
||||
updateScroll(element, 'left', element.scrollLeft - differenceX);
|
||||
|
||||
updateGeometry(element);
|
||||
}
|
||||
@@ -89,29 +88,37 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
}
|
||||
}
|
||||
function touchMove(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,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;
|
||||
@@ -145,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);
|
||||
@@ -164,7 +174,11 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function (element, supportsTouch, supportsIePointer) {
|
||||
module.exports = function (element) {
|
||||
if (!_.env.supportsTouch && !_.env.supportsIePointer) {
|
||||
return;
|
||||
}
|
||||
|
||||
var i = instances.get(element);
|
||||
bindTouchHandler(element, i, supportsTouch, supportsIePointer);
|
||||
bindTouchHandler(element, i, _.env.supportsTouch, _.env.supportsIePointer);
|
||||
};
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var cls = require('../lib/class')
|
||||
, h = require('../lib/helper')
|
||||
, instances = require('./instances')
|
||||
, updateGeometry = require('./update-geometry');
|
||||
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 clickRailHandler = require('./handler/click-rail')
|
||||
, dragScrollbarHandler = require('./handler/drag-scrollbar')
|
||||
, keyboardHandler = require('./handler/keyboard')
|
||||
, mouseWheelHandler = require('./handler/mouse-wheel')
|
||||
, nativeScrollHandler = require('./handler/native-scroll')
|
||||
, selectionHandler = require('./handler/selection')
|
||||
, touchHandler = require('./handler/touch');
|
||||
var handlers = {
|
||||
'click-rail': require('./handler/click-rail'),
|
||||
'drag-scrollbar': require('./handler/drag-scrollbar'),
|
||||
'keyboard': require('./handler/keyboard'),
|
||||
'wheel': require('./handler/mouse-wheel'),
|
||||
'touch': require('./handler/touch'),
|
||||
'selection': require('./handler/selection')
|
||||
};
|
||||
var nativeScrollHandler = require('./handler/native-scroll');
|
||||
|
||||
module.exports = function (element, userSettings) {
|
||||
userSettings = typeof userSettings === 'object' ? userSettings : {};
|
||||
@@ -25,20 +26,19 @@ module.exports = function (element, userSettings) {
|
||||
// Create a plugin instance.
|
||||
var i = instances.add(element);
|
||||
|
||||
i.settings = h.extend(i.settings, userSettings);
|
||||
i.settings = _.extend(i.settings, userSettings);
|
||||
cls.add(element, 'ps-theme-' + i.settings.theme);
|
||||
|
||||
i.settings.handlers.forEach(function (handlerName) {
|
||||
handlers[handlerName](element);
|
||||
});
|
||||
|
||||
clickRailHandler(element);
|
||||
dragScrollbarHandler(element);
|
||||
mouseWheelHandler(element);
|
||||
nativeScrollHandler(element);
|
||||
selectionHandler(element);
|
||||
|
||||
if (h.env.supportsTouch || h.env.supportsIePointer) {
|
||||
touchHandler(element, h.env.supportsTouch, h.env.supportsIePointer);
|
||||
}
|
||||
if (i.settings.useKeyboard) {
|
||||
keyboardHandler(element);
|
||||
}
|
||||
|
||||
updateGeometry(element);
|
||||
|
||||
if (i.settings.autoupdate) {
|
||||
autoupdate(element);
|
||||
resizer(element);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,77 +1,93 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var d = require('../lib/dom')
|
||||
, defaultSettings = require('./default-setting')
|
||||
, EventManager = require('../lib/event-manager')
|
||||
, guid = require('../lib/guid')
|
||||
, h = require('../lib/helper');
|
||||
var _ = require('../lib/helper');
|
||||
var cls = require('../lib/class');
|
||||
var defaultSettings = require('./default-setting');
|
||||
var dom = require('../lib/dom');
|
||||
var EventManager = require('../lib/event-manager');
|
||||
var guid = require('../lib/guid');
|
||||
|
||||
var instances = {};
|
||||
|
||||
function Instance(element) {
|
||||
var i = this;
|
||||
|
||||
i.settings = h.clone(defaultSettings);
|
||||
i.settings = _.clone(defaultSettings);
|
||||
i.containerWidth = null;
|
||||
i.containerHeight = null;
|
||||
i.contentWidth = null;
|
||||
i.contentHeight = null;
|
||||
|
||||
i.isRtl = d.css(element, 'direction') === "rtl";
|
||||
i.isRtl = dom.css(element, 'direction') === "rtl";
|
||||
i.isNegativeScroll = (function () {
|
||||
var originalScrollLeft = element.scrollLeft;
|
||||
var result = null;
|
||||
element.scrollLeft = -1;
|
||||
result = element.scrollLeft < 0;
|
||||
element.scrollLeft = originalScrollLeft;
|
||||
return result;
|
||||
})();
|
||||
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
|
||||
i.event = new EventManager();
|
||||
i.ownerDocument = element.ownerDocument || document;
|
||||
|
||||
i.scrollbarXRail = d.appendTo(d.e('div', 'ps-scrollbar-x-rail'), element);
|
||||
i.scrollbarX = d.appendTo(d.e('div', 'ps-scrollbar-x'), i.scrollbarXRail);
|
||||
function focus() {
|
||||
cls.add(element, 'ps-focus');
|
||||
}
|
||||
|
||||
function blur() {
|
||||
cls.remove(element, 'ps-focus');
|
||||
}
|
||||
|
||||
i.scrollbarXRail = dom.appendTo(dom.e('div', 'ps-scrollbar-x-rail'), element);
|
||||
i.scrollbarX = dom.appendTo(dom.e('div', 'ps-scrollbar-x'), i.scrollbarXRail);
|
||||
i.scrollbarX.setAttribute('tabindex', 0);
|
||||
i.event.bind(i.scrollbarX, 'focus', focus);
|
||||
i.event.bind(i.scrollbarX, 'blur', blur);
|
||||
i.scrollbarXActive = null;
|
||||
i.scrollbarXWidth = null;
|
||||
i.scrollbarXLeft = null;
|
||||
i.scrollbarXBottom = h.toInt(d.css(i.scrollbarXRail, 'bottom'));
|
||||
i.scrollbarXBottom = _.toInt(dom.css(i.scrollbarXRail, 'bottom'));
|
||||
i.isScrollbarXUsingBottom = i.scrollbarXBottom === i.scrollbarXBottom; // !isNaN
|
||||
i.scrollbarXTop = i.isScrollbarXUsingBottom ? null : h.toInt(d.css(i.scrollbarXRail, 'top'));
|
||||
i.railBorderXWidth = h.toInt(d.css(i.scrollbarXRail, 'borderLeftWidth')) + h.toInt(d.css(i.scrollbarXRail, 'borderRightWidth'));
|
||||
i.railXMarginWidth = h.toInt(d.css(i.scrollbarXRail, 'marginLeft')) + h.toInt(d.css(i.scrollbarXRail, 'marginRight'));
|
||||
i.scrollbarXTop = i.isScrollbarXUsingBottom ? null : _.toInt(dom.css(i.scrollbarXRail, 'top'));
|
||||
i.railBorderXWidth = _.toInt(dom.css(i.scrollbarXRail, 'borderLeftWidth')) + _.toInt(dom.css(i.scrollbarXRail, 'borderRightWidth'));
|
||||
// Set rail to display:block to calculate margins
|
||||
dom.css(i.scrollbarXRail, 'display', 'block');
|
||||
i.railXMarginWidth = _.toInt(dom.css(i.scrollbarXRail, 'marginLeft')) + _.toInt(dom.css(i.scrollbarXRail, 'marginRight'));
|
||||
dom.css(i.scrollbarXRail, 'display', '');
|
||||
i.railXWidth = null;
|
||||
i.railXRatio = null;
|
||||
|
||||
i.scrollbarYRail = d.appendTo(d.e('div', 'ps-scrollbar-y-rail'), element);
|
||||
i.scrollbarY = d.appendTo(d.e('div', 'ps-scrollbar-y'), i.scrollbarYRail);
|
||||
i.scrollbarYRail = dom.appendTo(dom.e('div', 'ps-scrollbar-y-rail'), element);
|
||||
i.scrollbarY = dom.appendTo(dom.e('div', 'ps-scrollbar-y'), i.scrollbarYRail);
|
||||
i.scrollbarY.setAttribute('tabindex', 0);
|
||||
i.event.bind(i.scrollbarY, 'focus', focus);
|
||||
i.event.bind(i.scrollbarY, 'blur', blur);
|
||||
i.scrollbarYActive = null;
|
||||
i.scrollbarYHeight = null;
|
||||
i.scrollbarYTop = null;
|
||||
i.scrollbarYRight = h.toInt(d.css(i.scrollbarYRail, 'right'));
|
||||
i.scrollbarYRight = _.toInt(dom.css(i.scrollbarYRail, 'right'));
|
||||
i.isScrollbarYUsingRight = i.scrollbarYRight === i.scrollbarYRight; // !isNaN
|
||||
i.scrollbarYLeft = i.isScrollbarYUsingRight ? null : h.toInt(d.css(i.scrollbarYRail, 'left'));
|
||||
i.scrollbarYOuterWidth = i.isRtl ? h.outerWidth(i.scrollbarY) : null;
|
||||
i.railBorderYWidth = h.toInt(d.css(i.scrollbarYRail, 'borderTopWidth')) + h.toInt(d.css(i.scrollbarYRail, 'borderBottomWidth'));
|
||||
i.railYMarginHeight = h.toInt(d.css(i.scrollbarYRail, 'marginTop')) + h.toInt(d.css(i.scrollbarYRail, 'marginBottom'));
|
||||
i.scrollbarYLeft = i.isScrollbarYUsingRight ? null : _.toInt(dom.css(i.scrollbarYRail, 'left'));
|
||||
i.scrollbarYOuterWidth = i.isRtl ? _.outerWidth(i.scrollbarY) : null;
|
||||
i.railBorderYWidth = _.toInt(dom.css(i.scrollbarYRail, 'borderTopWidth')) + _.toInt(dom.css(i.scrollbarYRail, 'borderBottomWidth'));
|
||||
dom.css(i.scrollbarYRail, 'display', 'block');
|
||||
i.railYMarginHeight = _.toInt(dom.css(i.scrollbarYRail, 'marginTop')) + _.toInt(dom.css(i.scrollbarYRail, 'marginBottom'));
|
||||
dom.css(i.scrollbarYRail, 'display', '');
|
||||
i.railYHeight = null;
|
||||
i.railYRatio = null;
|
||||
}
|
||||
|
||||
function getId(element) {
|
||||
if (typeof element.dataset === 'undefined') {
|
||||
return element.getAttribute('data-ps-id');
|
||||
} else {
|
||||
return element.dataset.psId;
|
||||
}
|
||||
return element.getAttribute('data-ps-id');
|
||||
}
|
||||
|
||||
function setId(element, id) {
|
||||
if (typeof element.dataset === 'undefined') {
|
||||
element.setAttribute('data-ps-id', id);
|
||||
} else {
|
||||
element.dataset.psId = id;
|
||||
}
|
||||
element.setAttribute('data-ps-id', id);
|
||||
}
|
||||
|
||||
function removeId(element) {
|
||||
if (typeof element.dataset === 'undefined') {
|
||||
element.removeAttribute('data-ps-id');
|
||||
} else {
|
||||
delete element.dataset.psId;
|
||||
}
|
||||
element.removeAttribute('data-ps-id');
|
||||
}
|
||||
|
||||
exports.add = function (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));
|
||||
};
|
||||
@@ -1,12 +1,10 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var cls = require('../lib/class')
|
||||
, d = require('../lib/dom')
|
||||
, h = require('../lib/helper')
|
||||
, instances = require('./instances');
|
||||
var _ = require('../lib/helper');
|
||||
var cls = require('../lib/class');
|
||||
var dom = require('../lib/dom');
|
||||
var instances = require('./instances');
|
||||
var updateScroll = require('./update-scroll');
|
||||
|
||||
function getThumbSize(i, thumbSize) {
|
||||
if (i.settings.minScrollbarLength) {
|
||||
@@ -21,7 +19,7 @@ function getThumbSize(i, thumbSize) {
|
||||
function updateCss(element, i) {
|
||||
var xRailOffset = {width: i.railXWidth};
|
||||
if (i.isRtl) {
|
||||
xRailOffset.left = element.scrollLeft + i.containerWidth - i.contentWidth;
|
||||
xRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth - i.contentWidth;
|
||||
} else {
|
||||
xRailOffset.left = element.scrollLeft;
|
||||
}
|
||||
@@ -30,26 +28,26 @@ function updateCss(element, i) {
|
||||
} else {
|
||||
xRailOffset.top = i.scrollbarXTop + element.scrollTop;
|
||||
}
|
||||
d.css(i.scrollbarXRail, xRailOffset);
|
||||
dom.css(i.scrollbarXRail, xRailOffset);
|
||||
|
||||
var yRailOffset = {top: element.scrollTop, height: i.railYHeight};
|
||||
if (i.isScrollbarYUsingRight) {
|
||||
if (i.isRtl) {
|
||||
yRailOffset.right = i.contentWidth - element.scrollLeft - i.scrollbarYRight - i.scrollbarYOuterWidth;
|
||||
yRailOffset.right = i.contentWidth - (i.negativeScrollAdjustment + element.scrollLeft) - i.scrollbarYRight - i.scrollbarYOuterWidth;
|
||||
} else {
|
||||
yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
|
||||
}
|
||||
} else {
|
||||
if (i.isRtl) {
|
||||
yRailOffset.left = element.scrollLeft + i.containerWidth * 2 - i.contentWidth - i.scrollbarYLeft - i.scrollbarYOuterWidth;
|
||||
yRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth * 2 - i.contentWidth - i.scrollbarYLeft - i.scrollbarYOuterWidth;
|
||||
} else {
|
||||
yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
|
||||
}
|
||||
}
|
||||
d.css(i.scrollbarYRail, yRailOffset);
|
||||
dom.css(i.scrollbarYRail, yRailOffset);
|
||||
|
||||
d.css(i.scrollbarX, {left: i.scrollbarXLeft, width: i.scrollbarXWidth - i.railBorderXWidth});
|
||||
d.css(i.scrollbarY, {top: i.scrollbarYTop, height: i.scrollbarYHeight - i.railBorderYWidth});
|
||||
dom.css(i.scrollbarX, {left: i.scrollbarXLeft, width: i.scrollbarXWidth - i.railBorderXWidth});
|
||||
dom.css(i.scrollbarY, {top: i.scrollbarYTop, height: i.scrollbarYHeight - i.railBorderYWidth});
|
||||
}
|
||||
|
||||
module.exports = function (element) {
|
||||
@@ -60,28 +58,44 @@ module.exports = function (element) {
|
||||
i.contentWidth = element.scrollWidth;
|
||||
i.contentHeight = element.scrollHeight;
|
||||
|
||||
var existingRails;
|
||||
if (!element.contains(i.scrollbarXRail)) {
|
||||
existingRails = dom.queryChildren(element, '.ps-scrollbar-x-rail');
|
||||
if (existingRails.length > 0) {
|
||||
existingRails.forEach(function (rail) {
|
||||
dom.remove(rail);
|
||||
});
|
||||
}
|
||||
dom.appendTo(i.scrollbarXRail, element);
|
||||
}
|
||||
if (!element.contains(i.scrollbarYRail)) {
|
||||
existingRails = dom.queryChildren(element, '.ps-scrollbar-y-rail');
|
||||
if (existingRails.length > 0) {
|
||||
existingRails.forEach(function (rail) {
|
||||
dom.remove(rail);
|
||||
});
|
||||
}
|
||||
dom.appendTo(i.scrollbarYRail, element);
|
||||
}
|
||||
|
||||
if (!i.settings.suppressScrollX && i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth) {
|
||||
i.scrollbarXActive = true;
|
||||
i.railXWidth = i.containerWidth - i.railXMarginWidth;
|
||||
i.scrollbarXWidth = getThumbSize(i, h.toInt(i.railXWidth * i.containerWidth / i.contentWidth));
|
||||
i.scrollbarXLeft = h.toInt(element.scrollLeft * (i.railXWidth - i.scrollbarXWidth) / (i.contentWidth - i.containerWidth));
|
||||
i.railXRatio = i.containerWidth / i.railXWidth;
|
||||
i.scrollbarXWidth = getThumbSize(i, _.toInt(i.railXWidth * i.containerWidth / i.contentWidth));
|
||||
i.scrollbarXLeft = _.toInt((i.negativeScrollAdjustment + element.scrollLeft) * (i.railXWidth - i.scrollbarXWidth) / (i.contentWidth - i.containerWidth));
|
||||
} else {
|
||||
i.scrollbarXActive = false;
|
||||
i.scrollbarXWidth = 0;
|
||||
i.scrollbarXLeft = 0;
|
||||
element.scrollLeft = 0;
|
||||
}
|
||||
|
||||
if (!i.settings.suppressScrollY && i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight) {
|
||||
i.scrollbarYActive = true;
|
||||
i.railYHeight = i.containerHeight - i.railYMarginHeight;
|
||||
i.scrollbarYHeight = getThumbSize(i, h.toInt(i.railYHeight * i.containerHeight / i.contentHeight));
|
||||
i.scrollbarYTop = h.toInt(element.scrollTop * (i.railYHeight - i.scrollbarYHeight) / (i.contentHeight - i.containerHeight));
|
||||
i.railYRatio = i.containerHeight / i.railYHeight;
|
||||
i.scrollbarYHeight = getThumbSize(i, _.toInt(i.railYHeight * i.containerHeight / i.contentHeight));
|
||||
i.scrollbarYTop = _.toInt(element.scrollTop * (i.railYHeight - i.scrollbarYHeight) / (i.contentHeight - i.containerHeight));
|
||||
} else {
|
||||
i.scrollbarYActive = false;
|
||||
i.scrollbarYHeight = 0;
|
||||
i.scrollbarYTop = 0;
|
||||
element.scrollTop = 0;
|
||||
}
|
||||
|
||||
if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
|
||||
@@ -93,6 +107,20 @@ module.exports = function (element) {
|
||||
|
||||
updateCss(element, i);
|
||||
|
||||
cls[i.scrollbarXActive ? 'add' : 'remove'](element, 'ps-active-x');
|
||||
cls[i.scrollbarYActive ? 'add' : 'remove'](element, 'ps-active-y');
|
||||
if (i.scrollbarXActive) {
|
||||
cls.add(element, 'ps-active-x');
|
||||
} else {
|
||||
cls.remove(element, 'ps-active-x');
|
||||
i.scrollbarXWidth = 0;
|
||||
i.scrollbarXLeft = 0;
|
||||
updateScroll(element, 'left', 0);
|
||||
}
|
||||
if (i.scrollbarYActive) {
|
||||
cls.add(element, 'ps-active-y');
|
||||
} else {
|
||||
cls.remove(element, 'ps-active-y');
|
||||
i.scrollbarYHeight = 0;
|
||||
i.scrollbarYTop = 0;
|
||||
updateScroll(element, 'top', 0);
|
||||
}
|
||||
};
|
||||
|
||||
97
src/js/plugin/update-scroll.js
Normal file
97
src/js/plugin/update-scroll.js
Normal file
@@ -0,0 +1,97 @@
|
||||
'use strict';
|
||||
|
||||
var instances = require('./instances');
|
||||
|
||||
var lastTop;
|
||||
var lastLeft;
|
||||
|
||||
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') {
|
||||
throw 'You must provide an element to the update-scroll function';
|
||||
}
|
||||
|
||||
if (typeof axis === 'undefined') {
|
||||
throw 'You must provide an axis to the update-scroll function';
|
||||
}
|
||||
|
||||
if (typeof value === 'undefined') {
|
||||
throw 'You must provide a value to the update-scroll function';
|
||||
}
|
||||
|
||||
if (axis === 'top' && value <= 0) {
|
||||
element.scrollTop = value = 0; // don't allow negative scroll
|
||||
element.dispatchEvent(createDOMEvent('ps-y-reach-start'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value <= 0) {
|
||||
element.scrollLeft = value = 0; // don't allow negative scroll
|
||||
element.dispatchEvent(createDOMEvent('ps-x-reach-start'));
|
||||
}
|
||||
|
||||
var i = instances.get(element);
|
||||
|
||||
if (axis === 'top' && value >= i.contentHeight - i.containerHeight) {
|
||||
// don't allow scroll past container
|
||||
value = i.contentHeight - i.containerHeight;
|
||||
if (value - element.scrollTop <= 1) {
|
||||
// mitigates rounding errors on non-subpixel scroll values
|
||||
value = element.scrollTop;
|
||||
} else {
|
||||
element.scrollTop = value;
|
||||
}
|
||||
element.dispatchEvent(createDOMEvent('ps-y-reach-end'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value >= i.contentWidth - i.containerWidth) {
|
||||
// don't allow scroll past container
|
||||
value = i.contentWidth - i.containerWidth;
|
||||
if (value - element.scrollLeft <= 1) {
|
||||
// mitigates rounding errors on non-subpixel scroll values
|
||||
value = element.scrollLeft;
|
||||
} else {
|
||||
element.scrollLeft = value;
|
||||
}
|
||||
element.dispatchEvent(createDOMEvent('ps-x-reach-end'));
|
||||
}
|
||||
|
||||
if (!lastTop) {
|
||||
lastTop = element.scrollTop;
|
||||
}
|
||||
|
||||
if (!lastLeft) {
|
||||
lastLeft = element.scrollLeft;
|
||||
}
|
||||
|
||||
if (axis === 'top' && value < lastTop) {
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-up'));
|
||||
}
|
||||
|
||||
if (axis === 'top' && value > lastTop) {
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-down'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value < lastLeft) {
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-left'));
|
||||
}
|
||||
|
||||
if (axis === 'left' && value > lastLeft) {
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-right'));
|
||||
}
|
||||
|
||||
if (axis === 'top') {
|
||||
element.scrollTop = lastTop = value;
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-y'));
|
||||
}
|
||||
|
||||
if (axis === 'left') {
|
||||
element.scrollLeft = lastLeft = value;
|
||||
element.dispatchEvent(createDOMEvent('ps-scroll-x'));
|
||||
}
|
||||
|
||||
};
|
||||
@@ -1,30 +1,37 @@
|
||||
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
|
||||
* Licensed under the MIT License
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var d = require('../lib/dom')
|
||||
, destroy = require('./destroy')
|
||||
, initialize = require('./initialize')
|
||||
, instances = require('./instances')
|
||||
, updateGeometry = require('./update-geometry');
|
||||
var _ = require('../lib/helper');
|
||||
var dom = require('../lib/dom');
|
||||
var instances = require('./instances');
|
||||
var updateGeometry = require('./update-geometry');
|
||||
var updateScroll = require('./update-scroll');
|
||||
|
||||
module.exports = function (element) {
|
||||
var i = instances.get(element);
|
||||
|
||||
if (!i.scrollbarXRail || !element.contains(i.scrollbarXRail) ||
|
||||
!i.scrollbarYRail || !element.contains(i.scrollbarYRail)) {
|
||||
// If there's something wrong in the plugin, re-initialise.
|
||||
destroy(element);
|
||||
initialize(element);
|
||||
} else {
|
||||
// Hide scrollbars not to affect scrollWidth and scrollHeight
|
||||
d.css(i.scrollbarXRail, 'display', 'none');
|
||||
d.css(i.scrollbarYRail, 'display', 'none');
|
||||
|
||||
updateGeometry(element);
|
||||
|
||||
d.css(i.scrollbarXRail, 'display', 'block');
|
||||
d.css(i.scrollbarYRail, 'display', 'block');
|
||||
if (!i) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Recalcuate negative scrollLeft adjustment
|
||||
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
|
||||
|
||||
// Recalculate rail margins
|
||||
dom.css(i.scrollbarXRail, 'display', 'block');
|
||||
dom.css(i.scrollbarYRail, 'display', 'block');
|
||||
i.railXMarginWidth = _.toInt(dom.css(i.scrollbarXRail, 'marginLeft')) + _.toInt(dom.css(i.scrollbarXRail, 'marginRight'));
|
||||
i.railYMarginHeight = _.toInt(dom.css(i.scrollbarYRail, 'marginTop')) + _.toInt(dom.css(i.scrollbarYRail, 'marginBottom'));
|
||||
|
||||
// Hide scrollbars not to affect scrollWidth and scrollHeight
|
||||
dom.css(i.scrollbarXRail, 'display', 'none');
|
||||
dom.css(i.scrollbarYRail, 'display', 'none');
|
||||
|
||||
updateGeometry(element);
|
||||
|
||||
// Update top/left scroll to trigger events
|
||||
updateScroll(element, 'top', element.scrollTop);
|
||||
updateScroll(element, 'left', element.scrollLeft);
|
||||
|
||||
dom.css(i.scrollbarXRail, 'display', '');
|
||||
dom.css(i.scrollbarYRail, 'display', '');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user