Compare commits

...

74 Commits

Author SHA1 Message Date
Jun
985980a892 Release 0.6.12
1. Fix scrolling for multiple select
2. Change default scrollbar theme
3. Minor bug fixes
2016-07-13 02:28:31 +09:00
Jun
fdc8d64fd9 Fix custom-theme example to be more useful
Not it provides a meaningful example. It also just includes pre-built
css file for the example.
2016-07-13 01:13:08 +09:00
Jun
26852236cc Enhance 'scale scrollbars on hover' feature
Now it's set as default, with a little different form of settings.
2016-07-13 01:13:08 +09:00
Jun
e0510b5fad Merge pull request #513 from cdriscol/trackbar_scaling
Add theme option to scale (grow) rails on hover
2016-07-13 01:12:44 +09:00
Jun
838ccbba77 Make defaultPrevented condition more readable 2016-06-23 10:05:56 +09:00
Jun
4198b23231 Merge pull request #525 from howey-aus/use-native-default-prevented
On keydown, check for e.isDefaultPrevented() [jquery] and e.defaultPrevented [native]
2016-06-23 10:04:22 +09:00
Dan Howe
3eb2a49109 e.isDefaultPrevented is a jQuery property, but the event passed might be a native browser event, so we should also check for "defaultPrevented" if the jQuery props don't exist. 2016-06-23 10:11:18 +10:00
Chris Driscol
1b2c853972 Hover scaling now sets width and height on scrollbar to 100% on hover. 2016-06-14 23:07:00 -06:00
Chris Driscol
e9d7cc97c8 Adding custom-theme scss used for custom-theme example. Added ability to set a hover scale size in the theme which will scale the X and Y rails when hovered. 2016-06-01 16:50:34 -06:00
Jun
9016f207e9 Fix scrolling for multiple select
Solve #481
2016-05-27 02:25:51 +09:00
Jun
aec4e37f61 Release 0.6.11
1. Add support of iframe for keyboard event
2. Add 'handlers' option
3. Drop support for IE <= 9
4. Allow children native scroll
5. Enhance browser compatibility
6. Minor bug fixes
2016-04-22 21:28:00 +09:00
DanielApt
269a1dc402 Merge pull request #486 from tkhyn/master
Rounding error fix when scrollbar is all the way down or right
2016-04-14 22:43:22 +01:00
Thomas Khyn
2cac43ef39 Taking the absolute value is actually not necessary 2016-04-14 12:25:50 +12:00
Thomas Khyn
b0a38741df Mitigates rounding errors due to non-subpixel scroll values 2016-04-14 12:09:24 +12:00
Hyunje Alex Jun
edaeccebf2 Place minified js files under /dist/js 2016-03-21 01:24:26 +09:00
Jun
42364c4d43 Merge pull request #468 from tonypine/master
Use only getAttribute and setAttribute to maximize browser compatibility, due to partial support of the .dataset method
2016-03-05 20:17:54 +09:00
vsn4ik
f20a8532ff Use files for npm and move CONTRIBUTING.md 2016-03-05 17:46:00 +09:00
DanielApt
7621a2488c Merge pull request #447 from antoinegomez/patch-1
Add support of iframe for keyboard event
2016-03-03 00:22:06 +00:00
tonypine
205c6d0223 Use only getAttribute and setAttribute to maximize browser compatibility, due to partial support of the .dataset method 2016-03-01 11:26:35 -03:00
DanielApt
ad5cd4fe53 Add JSDelivr to readme
Now that we have closed #439, document it.
2016-02-26 17:54:19 +00:00
DanielApt
dc951a3804 Remove console log 2016-02-22 22:41:11 +00:00
DanielApt
9996b1c8e3 Document scrolling of children 2016-02-22 22:36:20 +00:00
DanielApt
f14b6a0d47 Allow children native scroll
Partly uses @DEFusion's #459 pull-request. Closes #455
2016-02-22 22:32:06 +00:00
Hyunje Alex Jun
9580e08886 Add templates for GitHub issues and pull requests
Also add CONTRIBUTING.md, which was originally a page in Wiki
2016-02-22 23:02:06 +09:00
Hyunje Alex Jun
a2b2a77de1 Change variable definition style
Use 'var' everytime, instead of using ','.
2016-02-22 22:45:32 +09:00
Hyunje Alex Jun
e63d4c03cb Rename dom module variable name 'd' to 'dom'
Enhance readability.
2016-02-22 21:49:36 +09:00
Hyunje Alex Jun
d277a363b0 Rename helper module variable 'h' to '_'
Enhance readability.
2016-02-22 21:49:33 +09:00
Hyunje Alex Jun
4a661f181f Drop support on IE<=9
They cannot be called modern anymore.
2016-02-22 21:40:39 +09:00
Hyunje Alex Jun
bd7134f33d Add 'handlers' option to configure scrolling methods
Please refer to README.md and examples/options-handlers.html for the
usage.
2016-02-22 20:58:48 +09:00
Hyunje Alex Jun
6f63623b93 Modify helper.clone to clone an array too 2016-02-22 20:58:47 +09:00
Jun
cfc658d648 Merge pull request #458 from ciffel/fix-stopPropagation
Fix stopPropagationOnClick handler
2016-02-22 19:57:02 +09:00
Jun
181265261b Merge pull request #461 from pra85/patch-1
Fix a typo in Readme
2016-02-22 01:28:45 +09:00
Prayag Verma
db65fe0f6a Fix a typo in Readme
`destory` → `destroy`
2016-02-21 19:11:10 +05:30
Mingc
7e0d5f5dc5 Fix stopPropagationOnClick handler 2016-02-18 15:08:45 +08:00
DanielApt
e0d6243f24 Add JSFiddles to README.md 2016-02-05 17:55:16 +00:00
DanielApt
3d91c6f098 Merge pull request #424 from azala/master
Fixes touch event handling in nested scrollbar containers
2016-02-01 17:58:17 +00:00
Antoine Gomez
636eaffd41 Add support of iframe for keyboard event
Really simple piece of code to add support of iframe in keyboard event activeElement test.
2016-01-27 18:49:45 +01:00
DanielApt
3ba211133d Merge pull request #446 from zedtux/patch-1
Update README.md
2016-01-26 23:32:47 +00:00
Guillaume Hain
40b1510d49 Update README.md
Add titles to the different way to install perfect-scrollbar and add the Rails gem link
2016-01-26 16:26:52 +01:00
Hyunje Alex Jun
b959edbf78 Release 0.6.10
1. Add missing fix for touch/trackpad scrolling in IE10+ and Edge
2016-01-24 04:26:59 +09:00
Hyunje Alex Jun
c49cf7905e Re-apply missing IE10+ and Edge fix for touch/trackpad 2016-01-24 04:25:51 +09:00
Hyunje Alex Jun
f4cb31f8d8 Release 0.6.9
1. Add accessibility support with keyboard
2. Fix events not triggered when scrolling past boundaries
3. Fix touch/trackpad scrolling in IE10+ and Edge
4. Add theme feature
5. Remove transition and border-radius mixins from styles
2016-01-24 03:15:38 +09:00
Hyunje Alex Jun
965e315b30 Merge pull request #434 from wujekbogdan/Get-rid-of-border-radius-and-transition-mixins
replaced mixins with autoprefixer
2016-01-24 03:13:51 +09:00
DanielApt
3e76ce9d3e Merge branch 'pr/433' 2016-01-23 17:24:22 +00:00
Jun
2413028ad4 Merge pull request #401 from TheBoef/master
Touchpad/Trackpad scrolling IE10+ and Edge
2016-01-23 15:52:37 +09:00
Hyunje Alex Jun
cc0fded8cb 2015 -> 2016 and add LICENSE 2016-01-05 11:29:24 +09:00
Hyunje Alex Jun
fbfe505408 Remove comments from source files
Abundant comments.
2016-01-05 11:27:42 +09:00
Hyunje Alex Jun
c76aa08113 Update README.md
'#' is not a comment prefix in JavaScript. Use '//'.
2015-12-27 20:12:07 +09:00
DanielApt
4d7f441d1f Merge pull request #422 from axelboc/master
Fix events not triggered when scrolling past boundaries
2015-12-26 13:37:29 +01:00
Hyunje Alex Jun
4f6ed64b17 Make keyboard handler consistent when focused
Resolve #437
2015-12-23 23:34:37 +09:00
wujekbogdan
2fe45b3a97 typo fix. 2015-12-10 11:50:19 +01:00
wujekbogdan
57b1404e29 - removed transition() and border-radius() mixins
- added gulp-autoprefixer
2015-12-10 11:46:35 +01:00
wujekbogdan
bcfe954803 - fixed indentation (2 spaces)
- added missing new lines at the end of files
- removed 'ps-theme-big-and-ugly' theme
- improved readme.md. Added an example on how to create custom themes with scss.
2015-12-10 10:21:44 +01:00
Hyunje Alex Jun
31434f81d4 Release 0.6.8
1. Fix broken drag scrolling out of viewport
2. Fix untriggered scroll events
3. Remove select element hack for Firefox
4. Set scrollbar size to 0 when inactive
5. Add tabindex properties to scrollbars
2015-12-10 13:46:20 +09:00
Hyunje Alex Jun
8a3ed6d0b7 Add tabindex properties to scrollbars
Resolve #425
2015-12-10 13:36:19 +09:00
Hyunje Alex Jun
1dfbbe9e56 Set scrollbar size to 0 when inactive
Resolve #415
2015-12-10 13:17:59 +09:00
Hyunje Alex Jun
eb02d5ae65 Remove select element hack for Firefox
The select scrolling bug has been resolved in the latest version of
Firefox.

Resolve #311
2015-12-10 12:59:23 +09:00
wujekbogdan
6fbaa00403 no message 2015-12-09 22:08:57 +01:00
wujekbogdan
c14feba0bf added an example on how to create custom themes. 2015-12-09 22:08:48 +01:00
wujekbogdan
6fbfd5c90d updated README.md file. Added documentation for 'theme' parameter. 2015-12-09 22:01:10 +01:00
wujekbogdan
eddd2c2731 themeable perfect-scrollbar
- added „theme” parameter
- replaced all the CSS visual styles with SCSS variables
- added $ps-theme-default SCSS map that holds all the variables
- added $theme parameter to all the mixins
2015-12-09 18:19:02 +01:00
mdsa
4c08b0e089 Fixes touch event handling in nested scrollbar containers 2015-11-23 04:31:05 -08:00
Axel Bocciarelli
c04b662a1b fix events not triggered when scrolling too past boundaries
Instead of returning when scrolling past the container's boundaries,
override `value` to the max allowed and let the other custom events
fire if needed.
2015-11-23 08:59:59 +11:00
Axel Bocciarelli
5ba86c2217 Merge remote-tracking branch 'noraesae/master' 2015-11-23 08:55:18 +11:00
DanielApt
6e32d3ddce Merge pull request #420 from axelboc/master
Dispatch custom events on `update` and fix scroll-end event not being triggered when dragging
2015-11-19 23:46:44 +00:00
Axel Bocciarelli
9f9f15f83c fix lint error 2015-11-19 11:50:31 +11:00
Axel Bocciarelli
7e04a2e72b trigger events on update
Dispatch the custom events on `Ps.update`:

```
container.scrollTop = 50;
Ps.update(container);
```

This is useful for controlling the scroll position via left/right
arrows and enabling/disabling these arrows on scroll or when the
start/end is reached. This also allows for the events to be dispatched
on page load by calling `Ps.update` right after `Ps.initialise`.
2015-11-19 11:26:28 +11:00
Axel Bocciarelli
24b34d3dea fix scroll-end events not triggered
... when dragging the scrollbar to the end with the mouse.
2015-11-19 11:05:57 +11:00
DanielApt
e1910cde3e use pageX/YOffset instead of scrollX/Y
As pointed out by @pliasetski these properties are not supported in IE11 and below

This fixes #409
2015-11-16 22:25:11 +00:00
DanielApt
bbf3d4db9f Remove usages of scrollbarYTop and scrollbarXLeft
#390
2015-11-10 22:41:56 +00:00
DanielApt
3b134d6193 Fix broken drag scrolling when left is out of viewport
Related to #390
2015-11-09 23:11:33 +00:00
DanielApt
e9024292cd Fix broken drag scrolling when top is out of viewport
Addresses issue no. 390 #390
2015-11-08 22:03:35 +00:00
TheBoef
e4dda6f408 Touchpad/Trackpad scrolling IE10+ and Edge
Right now you can't scroll with your touchpad/trackpad on a element that
has the perfect scrollbar in IE10+ and Edge.
By using the property '-ms-overflow-style' (Supported in IE10+ and Edge)
too hide the overflow instead of the default 'overflow' property, you
keep the scrolling with touchpad/trackpad functionality.
2015-10-14 23:59:19 +02:00
Hyunje Alex Jun
fd53ae0b48 Add a custom release NPM script. 2015-10-03 21:50:46 +09:00
42 changed files with 1036 additions and 502 deletions

8
.github/ISSUE_TEMPLATE.md vendored Normal file
View 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
View 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

View File

@@ -1,9 +0,0 @@
.DS_Store
/.eslintrc
/.gitignore
/.travis.yml
/gulpfile.js
/examples
node_modules

74
CONTRIBUTING.md Normal file
View 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
View 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.

130
README.md
View File

@@ -52,16 +52,26 @@ 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
@@ -74,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)
@@ -83,9 +94,17 @@ 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)
#### JSFiddle
You can fork the following JSFiddles for testing and experimenting purposes:
* [Perfect Scrollbar](https://jsfiddle.net/DanielApt/xv0rrxv3/)
* [Perfect Scrollbar (jQuery)](https://jsfiddle.net/DanielApt/gbfLazpx/)
## Requirements
@@ -155,7 +174,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);
@@ -218,10 +237,10 @@ require.config({
and load `perfectScrollbar` in the initialiser of your app:
```javascript
# for vanilla JS:
// for vanilla JS:
window.Ps = require('perfectScrollbar');
# for jQuery:
// for jQuery:
require('perfectScrollbarJQuery');
```
@@ -238,25 +257,25 @@ define([
'perfectScrollbarJquery'
],
function (angular) {
var myApp = angular.module('myApp', [])
.run(function() {
var app = angular.module('myApp', []);
app.run(function () {
window.Ps = require('perfectScrollbar');
require('perfectScrollbarJQuery');
})
return myApp;
});
return app;
});
```
And initialise perfectScrollbar in a controller:
```javascript
# by vanilla JS:
// by vanilla JS:
var container = document.getElementById('imgLoader');
Ps.initialize(container);
Ps.update(container);
# or by jQuery:
var imgLoader = $("#imgLoader")
// or by jQuery:
var imgLoader = $('#imgLoader')
imgLoader.perfectScrollbar();
```
@@ -264,57 +283,84 @@ imgLoader.perfectScrollbar();
perfect-scrollbar supports optional parameters.
### handlers
It is a list of handlers to use to scroll the element.
**Default**: `['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch']`
**Disabled by default**: `'selection'`
### wheelSpeed
The scroll speed applied to mousewheel event.
**Default: 1**
**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**
**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**
**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**
**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**
**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**
**Default**: `false`
### suppressScrollX
When set to true, the scroll bar in X axis will not be available, regardless of the content width.
**Default: false**
**Default**: `false`
### suppressScrollY
When set to true, the scroll bar in Y axis will not be available, regardless of the content height.
**Default: false**
**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**
**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**
**Default**: `0`
### stopPropagationOnClick
When set to false, when clicking on a rail, the click event will be allowed to propagate.
**Default: true**
**Default**: `true`
### theme
A string. It's a class name added to the container element. The class name is prepended with `ps-theme-`. So default theme class name is `ps-theme-default`. In order to create custom themes with scss use `ps-container($theme)` mixin, where `$theme` is a scss map.
**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.
### useSelectionScroll
When set to true, you can scroll the container by selecting text and move the cursor.
**Default: false**
## Events
@@ -363,24 +409,20 @@ $(document).on('ps-scroll-x', function () {
})
```
## Contribution
## Tips
#### Please read [Contributing](https://github.com/noraesae/perfect-scrollbar/wiki/Contributing) in the wiki before making any contribution.
### Scrolling children inside perfect-scrollbar
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).
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.
@@ -396,7 +438,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:

View 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
View 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; }

View File

@@ -0,0 +1,27 @@
<!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="Default" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'), {
theme: 'square'
});
};
</script>
</body>
</html>

View 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,
)));
}

View File

@@ -38,10 +38,11 @@
<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')
, axis = document.getElementById('axis')
, direction = document.getElementById('direction')
, startEnd = document.getElementById('start-end');
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 () {
@@ -83,7 +84,6 @@
document.addEventListener('ps-x-reach-end', function () {
startEnd.innerHTML = 'Reached end of <em>X-Axis</em>'
});
</script>
</body>
</html>

View 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>

View File

@@ -1,19 +1,20 @@
'use strict';
var gulp = require('gulp')
, browserify = require('browserify')
, buffer = require('vinyl-buffer')
, connect = require('gulp-connect')
, del = require('del')
, eslint = require('gulp-eslint')
, insert = require('gulp-insert')
, path = require('path')
, rename = require('gulp-rename')
, sass = require('gulp-sass')
, source = require('vinyl-source-stream')
, stream = require('event-stream')
, 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';
@@ -29,7 +30,7 @@ gulp.task('clean:js', function () {
});
gulp.task('clean:js:min', function () {
return del(['./dist/js/min/*.js']);
return del(['./dist/js/*.min.js']);
});
var jsEntries = [
@@ -37,6 +38,11 @@ var jsEntries = [
'./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 () {
var tasks = jsEntries.map(function (src) {
return browserify([src]).bundle()
@@ -70,7 +76,7 @@ gulp.task('js:min', ['clean:js:min'], function () {
path.basename = 'perfect-scrollbar.' + path.basename + '.min';
}
}))
.pipe(gulp.dest('./dist/js/min'))
.pipe(gulp.dest('./dist/js'))
.pipe(connect.reload());
});
return stream.merge.apply(null, tasks);
@@ -87,6 +93,7 @@ gulp.task('clean:css:min', 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'))
@@ -96,6 +103,7 @@ gulp.task('css', ['clean:css'], 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'));

View File

@@ -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
View File

@@ -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');

View File

@@ -1,6 +1,6 @@
{
"name": "perfect-scrollbar",
"version": "0.6.7",
"version": "0.6.12",
"description": "Minimalistic but perfect custom scrollbar plugin",
"author": "Hyunje Alex Jun <me@noraesae.net>",
"contributors": [
@@ -26,11 +26,18 @@
"engines": {
"node": ">= 0.12.0"
},
"files": [
"dist",
"src",
"index.js",
"jquery.js"
],
"devDependencies": {
"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": "^1.0.0",
"gulp-insert": "^0.5.0",
@@ -43,7 +50,8 @@
},
"scripts": {
"test": "gulp",
"before-deploy": "gulp && gulp compress"
"before-deploy": "gulp && gulp compress",
"release": "rm -rf dist && gulp && npm publish"
},
"license": "MIT"
}

View File

@@ -1,123 +1,3 @@
// Colors
$ps-rail-hover: #eee;
$ps-bar-default: #aaa;
$ps-bar-hover: #999;
// Helper mixins
@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);
opacity: 0;
@include transition(background-color .2s linear, opacity .2s linear);
}
@mixin scrollbar-rail-hover {
background-color: $ps-rail-hover;
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 {
-ms-touch-action: none;
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 {
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';

127
src/css/mixins.scss Normal file
View File

@@ -0,0 +1,127 @@
@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 {
pointer-events: none;
&.ps-x > .ps-scrollbar-x-rail {
@include scrollbar-rail-hover($theme);
> .ps-scrollbar-x {
@include scrollbar-hover($theme);
}
}
&.ps-y > .ps-scrollbar-y-rail {
@include scrollbar-rail-hover($theme);
> .ps-scrollbar-y {
@include scrollbar-hover($theme);
}
}
}
}
// Layout and theme mixin
@mixin ps-container($theme) {
-ms-touch-action: none;
touch-action: none;
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
View 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
View 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;

View File

@@ -1,6 +1,3 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var ps = require('../main');

View File

@@ -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 jQuery(this);
});
};
}

View File

@@ -1,6 +1,3 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
function oldAdd(element, className) {

View File

@@ -1,6 +1,3 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var DOM = {};

View File

@@ -1,6 +1,3 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var EventElement = function (element) {

View File

@@ -1,6 +1,3 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
module.exports = (function () {

View File

@@ -1,22 +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) {
var toInt = exports.toInt = function (x) {
return parseInt(x, 10) || 0;
};
exports.clone = function (obj) {
var clone = exports.clone = function (obj) {
if (obj === null) {
return null;
} else if (obj.constructor === Array) {
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 {
@@ -25,18 +24,18 @@ exports.clone = function (obj) {
};
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) {
@@ -50,11 +49,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) {

View File

@@ -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,

View File

@@ -1,9 +1,7 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
module.exports = {
handlers: ['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch'],
maxScrollbarLength: null,
minScrollbarLength: null,
scrollXMarginOffset: 0,
@@ -13,8 +11,7 @@ module.exports = {
suppressScrollY: false,
swipePropagation: true,
useBothWheelAxes: false,
useKeyboard: true,
useSelectionScroll: false,
wheelPropagation: false,
wheelSpeed: 1
wheelSpeed: 1,
theme: 'default'
};

View File

@@ -1,11 +1,8 @@
/* 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);
@@ -15,11 +12,11 @@ module.exports = function (element) {
}
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);
};

View File

@@ -1,25 +1,22 @@
/* 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')
, updateScroll = require('../update-scroll');
var _ = require('../../lib/helper');
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(); };
if (i.settings.stopPropagationOnClick) {
i.event.bind(i.scrollbarY, 'click', stopPropagation);
}
i.event.bind(i.scrollbarYRail, 'click', function (e) {
var halfOfScrollbarLength = h.toInt(i.scrollbarYHeight / 2);
var positionTop = i.railYRatio * (e.pageY - window.scrollY - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength);
var halfOfScrollbarLength = _.toInt(i.scrollbarYHeight / 2);
var positionTop = i.railYRatio * (e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength);
var maxPositionTop = i.railYRatio * (i.railYHeight - i.scrollbarYHeight);
var positionRatio = positionTop / maxPositionTop;
@@ -39,8 +36,8 @@ function bindClickRailHandler(element, i) {
i.event.bind(i.scrollbarX, 'click', stopPropagation);
}
i.event.bind(i.scrollbarXRail, 'click', function (e) {
var halfOfScrollbarLength = h.toInt(i.scrollbarXWidth / 2);
var positionLeft = i.railXRatio * (e.pageX - window.scrollX - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength);
var halfOfScrollbarLength = _.toInt(i.scrollbarXWidth / 2);
var positionLeft = i.railXRatio * (e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength);
var maxPositionLeft = i.railXRatio * (i.railXWidth - i.scrollbarXWidth);
var positionRatio = positionLeft / maxPositionLeft;

View File

@@ -1,13 +1,10 @@
/* 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')
, updateScroll = require('../update-scroll');
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;
@@ -15,7 +12,7 @@ function bindMouseScrollXHandler(element, i) {
function updateScrollLeft(deltaX) {
var newLeft = currentLeft + (deltaX * i.railXRatio);
var maxLeft = i.scrollbarXRail.getBoundingClientRect().left + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth));
var maxLeft = Math.max(0, i.scrollbarXRail.getBoundingClientRect().left) + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth));
if (newLeft < 0) {
i.scrollbarXLeft = 0;
@@ -25,7 +22,7 @@ function bindMouseScrollXHandler(element, i) {
i.scrollbarXLeft = newLeft;
}
var scrollLeft = h.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - (i.railXRatio * i.scrollbarXWidth))) - i.negativeScrollAdjustment;
var scrollLeft = _.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - (i.railXRatio * i.scrollbarXWidth))) - i.negativeScrollAdjustment;
updateScroll(element, 'left', scrollLeft);
}
@@ -37,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')) * i.railXRatio;
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);
@@ -60,7 +57,7 @@ function bindMouseScrollYHandler(element, i) {
function updateScrollTop(deltaY) {
var newTop = currentTop + (deltaY * i.railYRatio);
var maxTop = i.scrollbarYRail.getBoundingClientRect().top + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight));
var maxTop = Math.max(0, i.scrollbarYRail.getBoundingClientRect().top) + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight));
if (newTop < 0) {
i.scrollbarYTop = 0;
@@ -70,7 +67,7 @@ function bindMouseScrollYHandler(element, i) {
i.scrollbarYTop = newTop;
}
var scrollTop = h.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - (i.railYRatio * i.scrollbarYHeight)));
var scrollTop = _.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - (i.railYRatio * i.scrollbarYHeight)));
updateScroll(element, 'top', scrollTop);
}
@@ -82,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')) * i.railYRatio;
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);

View File

@@ -1,12 +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')
, updateScroll = require('../update-scroll');
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;
@@ -42,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;
}
}

View File

@@ -1,12 +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')
, updateScroll = require('../update-scroll');
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindMouseWheelHandler(element, i) {
var shouldPrevent = false;
@@ -59,20 +55,22 @@ function bindMouseWheelHandler(element, i) {
return [deltaX, deltaY];
}
function shouldBeConsumedByTextarea(deltaX, deltaY) {
var hoveredTextarea = element.querySelector('textarea:hover');
if (hoveredTextarea) {
var maxScrollTop = hoveredTextarea.scrollHeight - hoveredTextarea.clientHeight;
function shouldBeConsumedByChild(deltaX, deltaY) {
var child = element.querySelector('textarea:hover, select[multiple]:hover, .ps-child:hover');
if (child) {
if (child.tagName !== 'TEXTAREA' && !window.getComputedStyle(child).overflow.match(/(scroll|auto)/)) {
return false;
}
var maxScrollTop = child.scrollHeight - child.clientHeight;
if (maxScrollTop > 0) {
if (!(hoveredTextarea.scrollTop === 0 && deltaY > 0) &&
!(hoveredTextarea.scrollTop === maxScrollTop && deltaY < 0)) {
if (!(child.scrollTop === 0 && deltaY > 0) && !(child.scrollTop === maxScrollTop && deltaY < 0)) {
return true;
}
}
var maxScrollLeft = hoveredTextarea.scrollLeft - hoveredTextarea.clientWidth;
var maxScrollLeft = child.scrollLeft - child.clientWidth;
if (maxScrollLeft > 0) {
if (!(hoveredTextarea.scrollLeft === 0 && deltaX < 0) &&
!(hoveredTextarea.scrollLeft === maxScrollLeft && deltaX > 0)) {
if (!(child.scrollLeft === 0 && deltaX < 0) && !(child.scrollLeft === maxScrollLeft && deltaX > 0)) {
return true;
}
}
@@ -81,19 +79,12 @@ function bindMouseWheelHandler(element, i) {
}
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;
}
var delta = getDeltaFromEvent(e);
var deltaX = delta[0];
var deltaY = delta[1];
if (shouldBeConsumedByTextarea(deltaX, deltaY)) {
if (shouldBeConsumedByChild(deltaX, deltaY)) {
return;
}

View File

@@ -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 () {

View File

@@ -1,12 +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')
, updateScroll = require('../update-scroll');
var _ = require('../../lib/helper');
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindSelectionHandler(element, i) {
function getRangeNode() {
@@ -40,7 +37,7 @@ function bindSelectionHandler(element, i) {
clearInterval(scrollingLoop);
scrollingLoop = null;
}
h.stopScrolling(element);
_.stopScrolling(element);
}
var isSelected = false;
@@ -71,10 +68,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;
}
@@ -85,14 +82,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;
}

View File

@@ -1,11 +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')
, updateScroll = require('../update-scroll');
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) {
@@ -90,6 +88,9 @@ function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
}
}
function touchMove(e) {
if (!inLocalTouch && i.settings.swipePropagation) {
touchStart(e);
}
if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) {
var touch = getTouch(e);
@@ -165,7 +166,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);
};

View File

@@ -1,21 +1,20 @@
/* 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');
// 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,23 +24,14 @@ 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);
if (i.settings.useSelectionScroll) {
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);
};

View File

@@ -1,26 +1,24 @@
/* 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;
@@ -33,61 +31,63 @@ function Instance(element) {
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.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
d.css(i.scrollbarXRail, 'display', 'block');
i.railXMarginWidth = h.toInt(d.css(i.scrollbarXRail, 'marginLeft')) + h.toInt(d.css(i.scrollbarXRail, 'marginRight'));
d.css(i.scrollbarXRail, 'display', '');
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'));
d.css(i.scrollbarYRail, 'display', 'block');
i.railYMarginHeight = h.toInt(d.css(i.scrollbarYRail, 'marginTop')) + h.toInt(d.css(i.scrollbarYRail, 'marginBottom'));
d.css(i.scrollbarYRail, 'display', '');
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) {

View File

@@ -1,13 +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')
, updateScroll = require('./update-scroll');
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) {
@@ -31,7 +28,7 @@ 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) {
@@ -47,10 +44,10 @@ function updateCss(element, i) {
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) {
@@ -63,48 +60,42 @@ module.exports = function (element) {
var existingRails;
if (!element.contains(i.scrollbarXRail)) {
existingRails = d.queryChildren(element, '.ps-scrollbar-x-rail');
existingRails = dom.queryChildren(element, '.ps-scrollbar-x-rail');
if (existingRails.length > 0) {
existingRails.forEach(function (rail) {
d.remove(rail);
dom.remove(rail);
});
}
d.appendTo(i.scrollbarXRail, element);
dom.appendTo(i.scrollbarXRail, element);
}
if (!element.contains(i.scrollbarYRail)) {
existingRails = d.queryChildren(element, '.ps-scrollbar-y-rail');
existingRails = dom.queryChildren(element, '.ps-scrollbar-y-rail');
if (existingRails.length > 0) {
existingRails.forEach(function (rail) {
d.remove(rail);
dom.remove(rail);
});
}
d.appendTo(i.scrollbarYRail, element);
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.railXRatio = i.containerWidth / i.railXWidth;
i.scrollbarXWidth = getThumbSize(i, h.toInt(i.railXWidth * i.containerWidth / i.contentWidth));
i.scrollbarXLeft = h.toInt((i.negativeScrollAdjustment + element.scrollLeft) * (i.railXWidth - i.scrollbarXWidth) / (i.contentWidth - i.containerWidth));
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.railYRatio = i.containerHeight / i.railYHeight;
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.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;
updateScroll(element, 'top', 0);
}
if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
@@ -116,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);
}
};

View File

@@ -1,22 +1,19 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var instances = require('./instances');
var upEvent = document.createEvent('Event')
, downEvent = document.createEvent('Event')
, leftEvent = document.createEvent('Event')
, rightEvent = document.createEvent('Event')
, yEvent = document.createEvent('Event')
, xEvent = document.createEvent('Event')
, xStartEvent = document.createEvent('Event')
, xEndEvent = document.createEvent('Event')
, yStartEvent = document.createEvent('Event')
, yEndEvent = document.createEvent('Event')
, lastTop
, lastLeft;
var upEvent = document.createEvent('Event');
var downEvent = document.createEvent('Event');
var leftEvent = document.createEvent('Event');
var rightEvent = document.createEvent('Event');
var yEvent = document.createEvent('Event');
var xEvent = document.createEvent('Event');
var xStartEvent = document.createEvent('Event');
var xEndEvent = document.createEvent('Event');
var yStartEvent = document.createEvent('Event');
var yEndEvent = document.createEvent('Event');
var lastTop;
var lastLeft;
upEvent.initEvent('ps-scroll-up', true, true);
downEvent.initEvent('ps-scroll-down', true, true);
@@ -43,29 +40,39 @@ module.exports = function (element, axis, value) {
}
if (axis === 'top' && value <= 0) {
element.scrollTop = 0;
element.scrollTop = value = 0; // don't allow negative scroll
element.dispatchEvent(yStartEvent);
return; // don't allow negative scroll
}
if (axis === 'left' && value <= 0) {
element.scrollLeft = 0;
element.scrollLeft = value = 0; // don't allow negative scroll
element.dispatchEvent(xStartEvent);
return; // don't allow negative scroll
}
var i = instances.get(element);
if (axis === 'top' && value > i.contentHeight - i.containerHeight) {
element.scrollTop = i.contentHeight - i.containerHeight;
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(yEndEvent);
return; // don't allow scroll past container
}
if (axis === 'left' && value > i.contentWidth - i.containerWidth) {
element.scrollLeft = i.contentWidth - i.containerWidth;
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(xEndEvent);
return; // don't allow scroll past container
}
if (!lastTop) {

View File

@@ -1,12 +1,10 @@
/* 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');
module.exports = function (element) {
var i = instances.get(element);
@@ -19,17 +17,21 @@ module.exports = function (element) {
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
// Recalculate rail margins
d.css(i.scrollbarXRail, 'display', 'block');
d.css(i.scrollbarYRail, 'display', 'block');
i.railXMarginWidth = h.toInt(d.css(i.scrollbarXRail, 'marginLeft')) + h.toInt(d.css(i.scrollbarXRail, 'marginRight'));
i.railYMarginHeight = h.toInt(d.css(i.scrollbarYRail, 'marginTop')) + h.toInt(d.css(i.scrollbarYRail, 'marginBottom'));
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
d.css(i.scrollbarXRail, 'display', 'none');
d.css(i.scrollbarYRail, 'display', 'none');
dom.css(i.scrollbarXRail, 'display', 'none');
dom.css(i.scrollbarYRail, 'display', 'none');
updateGeometry(element);
d.css(i.scrollbarXRail, 'display', '');
d.css(i.scrollbarYRail, 'display', '');
// 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', '');
};