Compare commits

..

126 Commits

Author SHA1 Message Date
IagoLast
f2b66c76ad 0.6.17 2018-05-10 16:01:24 +02:00
IagoLast
85009c34cd Add release scripts 2018-05-10 16:01:15 +02:00
Ivan Malagon
7e39eb3d68 Hotfix for IE & Firefox bug 2017-09-07 19:10:54 +02:00
Javier Álvarez Medina
085cd7abdd Merge pull request #2 from CartoDB/bug-in-microsoft-edge
Don't try to get the class attribute if function is not available
2017-03-01 15:37:18 +01:00
xavijam
6edd7a183c Don't try to get the class attribute if function is not available 2017-03-01 11:46:44 +01:00
Buti
735c6c0bf3 Merge pull request #1 from CartoDB/touchmove
Avoid to process touchmove event if target has class ps-prevent-touch…
2017-02-14 11:02:53 +01:00
nobuti
553756b346 Avoid to process touchmove event if target has class ps-prevent-touchmove.
This allow us to filter histogram widgets inside ps when touch events happen.
2017-02-13 15:53:34 +01:00
nobuti
4707acc287 Dom changed event.
Updated docs.
2017-01-18 20:14:23 +01:00
Buti
5f0a423128 Merge pull request #1 from nobuti/autoupdate
Autoupdate
2017-01-16 13:05:29 +01:00
nobuti
6d2c6ac8ec Removed old code. 2017-01-12 10:03:37 +01:00
nobuti
d1340f1b85 Debounce FTW. 2017-01-12 09:46:53 +01:00
nobuti
4a988b5a21 iframe resize handler based takes too memory. Back to window.resize old school. 2017-01-12 09:25:17 +01:00
nobuti
1a39d76e48 Better remove resizer. 2017-01-12 07:07:59 +01:00
nobuti
9fc34100df Wait until load to bind the resize handler. 2017-01-12 05:59:31 +01:00
nobuti
d74bdcccec Autoupdate.
It listens new elements addition and element resize in order to trigger the update method to redraw
the scroll.
2017-01-12 05:32:50 +01:00
Hyunje Jun
5f34edc8c7 Merge pull request #603 from luckyorange/master
Replaced obj.constructor with Array.isArray
2017-01-11 00:59:45 +09:00
Hyunje Jun
ce3a199cb3 Release 0.6.16
1. Fix a bug that touch and pointer events handled together
2017-01-10 10:00:46 +09:00
Hayden Gascoigne
9c485584b9 Replaced obj.constructor with Array.isArray 2017-01-09 13:44:32 -06:00
Hyunje Jun
d5db8ca18e Merge pull request #595 from RavWar/chrome-pointer-fix
Bind Touch or Pointer events exclusively, fixes #594
2016-12-19 22:08:54 +09:00
RavWar
89174ed99f Bind Touch or Pointer events exclusively, fixes #594 2016-12-19 16:05:08 +03:00
Hyunje Jun
6e7e3f94fa Release 0.6.15
1. Fix TypeScript typedef
2. Fix jspm meta
2016-12-07 10:14:11 +09:00
Hyunje Jun
7d61475e1d Add yarn.lock 2016-12-07 10:11:49 +09:00
Hyunje Jun
2f8daae695 Merge pull request #591 from unsalted/patch-1
Jquery is not a dependency
2016-12-04 12:24:19 +09:00
Nick Meehan
5ce0d77f87 Jquery is not a dependency
Jquery is not a dependency it is optional and should be treated as such.
Registry override will solve error #578
2016-12-03 13:24:32 -08:00
Jun
f811bbcab5 Merge pull request #583 from ggergo74/FixTypedef
Add explicit void to typedef functions
2016-11-08 00:46:36 +09:00
Gergely Grusz
4593eb9115 Add explicit void to typedef functions
It is needed if we use the noImplicitAny switch in the tsconfig.json file.
Otherwise the typescript compiler won't compile it.
Error messages caused by lack of explicit return types:

node_modules/perfect-scrollbar/perfect-scrollbar.d.ts(16,3):
error TS7010: 'initialize', which lacks return-type annotation, implicitly has an 'any' return type.
node_modules/perfect-scrollbar/perfect-scrollbar.d.ts(17,3):
error TS7010: 'update', which lacks return-type annotation, implicitly has an 'any' return type.
node_modules/perfect-scrollbar/perfect-scrollbar.d.ts(18,3):
error TS7010: 'destroy', which lacks return-type annotation, implicitly has an 'any' return type.
2016-11-07 16:33:42 +01:00
Jun
b3b1bc2454 Update README.md
Add perfect-scrollbar limitations.
2016-11-06 22:41:15 +09:00
Hyunje Jun
25e5be13ff Release 0.6.14
1. Include TypeScript definition
2016-11-04 16:31:23 +09:00
Hyunje Jun
f683b01959 Include TypeScript definition in published files 2016-11-04 16:30:33 +09:00
Hyunje Jun
6d2f203441 Release 0.6.13
1. Add meta and alt key handling in keyboard scrolling - #549
2. Implement reverse wheel axis on shift key - #548
3. Add TypeScript definition - #552
4. Fix click propagation on scrollbar thumbs - #526 #547
5. Implement correct click-rail handler - #568
6. Minor bug fixes
2016-10-18 16:51:59 +09:00
Hyunje Jun
a4808f662e Implement right click-rail handler
Resolve #568.
2016-10-18 16:50:52 +09:00
Hyunje Jun
98fa15167a Remove 'stopPropagationOnClick'
It was wrong fix.
2016-10-18 16:38:13 +09:00
Hyunje Jun
06929ae685 Don't consume if child's not scrollable
Resolve #541.
2016-10-18 16:28:52 +09:00
Hyunje Jun
aa63ff0370 Disable selection scroll on key pressed
Resolve #570.
2016-10-18 16:01:03 +09:00
Hyunje Jun
c7ddde69c2 Add example to change theme 2016-10-18 15:45:19 +09:00
Hyunje Jun
69e3fb2688 Apply hover style for drag scrolling
Resolve #555.
2016-10-18 14:59:27 +09:00
Hyunje Jun
fad7f8b4a6 Add TypeScript definition
Resolve #552.
2016-10-18 12:58:42 +09:00
Hyunje Jun
0deb4c9bc7 Don't use pointer-events: none
Resolve #526 and #547.
2016-10-18 12:45:58 +09:00
Hyunje Jun
11fcd09a99 Reverse wheel scroll axis on shift pressed
Resolve #548.
2016-10-18 11:55:03 +09:00
Hyunje Jun
0fc5c69b3f Add metaKey and altKey handling in keyboard handler
Resolve #549.
2016-10-18 11:49:20 +09:00
Hyunje Jun
898928b686 Don't do type-safe comparison on null
Resolve #537.
2016-10-18 11:00:22 +09:00
Hyunje Jun
ce7146121f Set touch-action to auto
Resolve #480.
2016-10-18 10:18:55 +09:00
Jun
908cee5490 Merge pull request #535 from lpetrov/invalid-state-error-on-scroll-update
Fixes https://github.com/noraesae/perfect-scrollbar/issues/534 (Calli…
2016-08-13 12:55:29 +09:00
Jun
b3880ca638 Merge pull request #551 from maximeloizeau/touch-scrolling-bug
Touch scrolling bug
2016-08-12 08:58:42 +09:00
Maxime Loizeau
7123891d4d Updated code styling to match repo recommendations 2016-08-11 15:55:20 +01:00
Maxime Loizeau
4c00a7fdb9 Prevent infinite update when touching without moving 2016-08-11 15:50:46 +01:00
Jun
3719dd614c Merge pull request #536 from frg/jspm-dependencies
Defined dependencies for jspm
2016-07-27 18:56:35 +09:00
Jean Farrugia
68dbc427ea added jspm dependencies 2016-07-20 07:47:22 +02:00
Lyubomir Petrov
34135d6ef0 Fixes https://github.com/noraesae/perfect-scrollbar/issues/534 (Calling .update from an ps-scroll-y triggers an InvalidStateError #534) 2016-07-19 15:57:17 +03:00
Jun
0ab95f2d57 Drop TravisCI testing on Node 0.12 2016-07-13 02:33:53 +09:00
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
Hyunje Alex Jun
66fd8bfd6a Release 0.6.7
Quick fix for 0.6.6.
2015-10-03 21:48:58 +09:00
Hyunje Alex Jun
4aa28add99 Add missing '.min' in compressed JS files 2015-10-03 21:48:02 +09:00
49 changed files with 5397 additions and 597 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

View File

@@ -1,6 +1,5 @@
language: node_js
node_js:
- 0.12
- 4
deploy:
provider: releases

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.

169
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,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
@@ -155,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);
@@ -218,10 +241,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 +261,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 +287,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**
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`
### stopPropagationOnClick
When set to false, when clicking on a rail, the click event will be allowed to propagate.
**Default: true**
### autoupdate
When set to true, the scroll will be updated when an element is added or removed from the content.
**Default**: `true`
### theme
A string. It's a class name added to the container element. The class name is prepended with `ps-theme-`. So default theme class name is `ps-theme-default`. In order to create custom themes with scss use `ps-container($theme)` mixin, where `$theme` is a scss map.
**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
@@ -350,6 +400,9 @@ This event fires when scrolling reaches the start of the x-axis.
### ps-x-reach-end
This event fires when scrolling reaches the end of the x-axis.
### ps-dom-change
This event fires when dom elements have been added to or removed from the content.
You can listen to these events either with vanilla JavaScript
```javascript
document.addEventListener('ps-scroll-x', function () {
@@ -363,24 +416,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 +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:

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

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

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

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()
@@ -65,12 +71,12 @@ gulp.task('js:min', ['clean:js:min'], function () {
.pipe(insert.prepend(version))
.pipe(rename(function (path) {
if (path.basename === 'global') {
path.basename = 'perfect-scrollbar';
path.basename = 'perfect-scrollbar.min';
} else {
path.basename = 'perfect-scrollbar.' + path.basename;
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,11 +1,11 @@
{
"name": "perfect-scrollbar",
"version": "0.6.6",
"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"
}
],
@@ -26,11 +26,19 @@
"engines": {
"node": ">= 0.12.0"
},
"files": [
"dist",
"src",
"index.js",
"jquery.js",
"perfect-scrollbar.d.ts"
],
"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",
@@ -41,9 +49,19 @@
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
},
"jspm": {
"main": "./index.js",
"registry": "jspm"
},
"typings": "perfect-scrollbar.d.ts",
"scripts": {
"test": "gulp",
"before-deploy": "gulp && gulp compress"
"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
View 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;
}

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

128
src/css/mixins.scss Normal file
View 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
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 = {};
@@ -17,7 +14,10 @@ DOM.appendTo = function (child, parent) {
};
function cssGet(element, styleName) {
return window.getComputedStyle(element)[styleName];
var style = window.getComputedStyle(element);
return style
? style[styleName]
: null;
}
function cssSet(element, styleName, styleValue) {

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) {
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 {
@@ -24,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) {
@@ -50,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) {

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

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

View File

@@ -1,20 +1,17 @@
/* 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,
scrollYMarginOffset: 0,
stopPropagationOnClick: true,
suppressScrollX: false,
suppressScrollY: false,
swipePropagation: true,
useBothWheelAxes: false,
useKeyboard: true,
useSelectionScroll: false,
wheelPropagation: false,
wheelSpeed: 1
wheelSpeed: 1,
theme: 'default',
autoupdate: true
};

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);
@@ -14,12 +11,16 @@ module.exports = function (element) {
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);
};

View File

@@ -1,56 +1,32 @@
/* 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 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.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 maxPositionTop = i.railYRatio * (i.railYHeight - i.scrollbarYHeight);
var positionRatio = positionTop / maxPositionTop;
var positionTop = e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top;
var direction = positionTop > i.scrollbarYTop ? 1 : -1;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
updateScroll(element, 'top', (i.contentHeight - i.containerHeight) * positionRatio);
updateScroll(element, 'top', element.scrollTop + direction * i.containerHeight);
updateGeometry(element);
e.stopPropagation();
});
if (i.settings.stopPropagationOnClick) {
i.event.bind(i.scrollbarX, 'click', stopPropagation);
}
i.event.bind(i.scrollbarX, 'click', stopPropagation);
i.event.bind(i.scrollbarXRail, 'click', function (e) {
var halfOfScrollbarLength = h.toInt(i.scrollbarXWidth / 2);
var positionLeft = i.railXRatio * (e.pageX - window.scrollX - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength);
var maxPositionLeft = i.railXRatio * (i.railXWidth - i.scrollbarXWidth);
var positionRatio = positionLeft / maxPositionLeft;
var positionLeft = e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left;
var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
updateScroll(element, 'left', ((i.contentWidth - i.containerWidth) * positionRatio) - i.negativeScrollAdjustment);
updateScroll(element, 'left', element.scrollLeft + direction * i.containerWidth);
updateGeometry(element);
e.stopPropagation();

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;
}
}
@@ -66,16 +71,40 @@ function bindKeyboardHandler(element, i) {
switch (e.which) {
case 37: // left
deltaX = -30;
if (e.metaKey) {
deltaX = -i.contentWidth;
} else if (e.altKey) {
deltaX = -i.containerWidth;
} else {
deltaX = -30;
}
break;
case 38: // up
deltaY = 30;
if (e.metaKey) {
deltaY = i.contentHeight;
} else if (e.altKey) {
deltaY = i.containerHeight;
} else {
deltaY = 30;
}
break;
case 39: // right
deltaX = 30;
if (e.metaKey) {
deltaX = i.contentWidth;
} else if (e.altKey) {
deltaX = i.containerWidth;
} else {
deltaX = 30;
}
break;
case 40: // down
deltaY = -30;
if (e.metaKey) {
deltaY = -i.contentHeight;
} else if (e.altKey) {
deltaY = -i.containerHeight;
} else {
deltaY = -30;
}
break;
case 33: // page up
deltaY = 90;

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;
@@ -56,23 +52,30 @@ function bindMouseWheelHandler(element, i) {
deltaY = e.wheelDelta;
}
if (e.shiftKey) {
// reverse axis with shift key
return [-deltaY, -deltaX];
}
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 (!window.getComputedStyle(child).overflow.match(/(scroll|auto)/)) {
// if not scrollable
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 +84,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;
@@ -58,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) {
@@ -71,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;
}
@@ -85,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;
}

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,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();
}
}
}
}
@@ -127,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;
@@ -146,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);
@@ -165,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);
};

View File

@@ -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,23 +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);
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);
if (i.settings.autoupdate) {
autoupdate(element);
resizer(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) {

15
src/js/plugin/resizer.js Normal file
View 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));
};

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,33 +1,15 @@
/* 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 lastTop;
var lastLeft;
upEvent.initEvent('ps-scroll-up', true, true);
downEvent.initEvent('ps-scroll-down', true, true);
leftEvent.initEvent('ps-scroll-left', true, true);
rightEvent.initEvent('ps-scroll-right', true, true);
yEvent.initEvent('ps-scroll-y', true, true);
xEvent.initEvent('ps-scroll-x', true, true);
xStartEvent.initEvent('ps-x-reach-start', true, true);
xEndEvent.initEvent('ps-x-reach-end', true, true);
yStartEvent.initEvent('ps-y-reach-start', true, true);
yEndEvent.initEvent('ps-y-reach-end', true, true);
var createDOMEvent = function (name) {
var event = document.createEvent("Event");
event.initEvent(name, true, true);
return event;
};
module.exports = function (element, axis, value) {
if (typeof element === 'undefined') {
@@ -43,29 +25,39 @@ module.exports = function (element, axis, value) {
}
if (axis === 'top' && value <= 0) {
element.scrollTop = 0;
element.dispatchEvent(yStartEvent);
return; // don't allow negative scroll
element.scrollTop = value = 0; // don't allow negative scroll
element.dispatchEvent(createDOMEvent('ps-y-reach-start'));
}
if (axis === 'left' && value <= 0) {
element.scrollLeft = 0;
element.dispatchEvent(xStartEvent);
return; // don't allow negative scroll
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) {
element.scrollTop = i.contentHeight - i.containerHeight;
element.dispatchEvent(yEndEvent);
return; // don't allow scroll past container
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) {
element.scrollLeft = i.contentWidth - i.containerWidth;
element.dispatchEvent(xEndEvent);
return; // don't allow scroll past container
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) {
@@ -77,29 +69,29 @@ module.exports = function (element, axis, value) {
}
if (axis === 'top' && value < lastTop) {
element.dispatchEvent(upEvent);
element.dispatchEvent(createDOMEvent('ps-scroll-up'));
}
if (axis === 'top' && value > lastTop) {
element.dispatchEvent(downEvent);
element.dispatchEvent(createDOMEvent('ps-scroll-down'));
}
if (axis === 'left' && value < lastLeft) {
element.dispatchEvent(leftEvent);
element.dispatchEvent(createDOMEvent('ps-scroll-left'));
}
if (axis === 'left' && value > lastLeft) {
element.dispatchEvent(rightEvent);
element.dispatchEvent(createDOMEvent('ps-scroll-right'));
}
if (axis === 'top') {
element.scrollTop = lastTop = value;
element.dispatchEvent(yEvent);
element.dispatchEvent(createDOMEvent('ps-scroll-y'));
}
if (axis === 'left') {
element.scrollLeft = lastLeft = value;
element.dispatchEvent(xEvent);
element.dispatchEvent(createDOMEvent('ps-scroll-x'));
}
};

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

4005
yarn.lock Normal file

File diff suppressed because it is too large Load Diff