Compare commits

...

304 Commits
0.4.1 ... 0.6.8

Author SHA1 Message Date
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
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
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
Hyunje Alex Jun
d6ede33202 Release 0.6.6
1. Add custom events
2. Support higher Node.js versions
3. Add useSelectionScroll option
4. Bug fixes
2015-10-03 21:44:26 +09:00
Hyunje Alex Jun
1c3b409d12 Remove 'bump' and 'release' tasks from gulpfile.js
There is only one JSON left for the project and it's better to bump the
version manually.
2015-10-03 21:43:59 +09:00
Hyunje Alex Jun
17e5f67519 Make selection scroll optional
It's not essential but rather causes several problems.
2015-10-03 21:37:24 +09:00
Hyunje Alex Jun
002034fd54 Return an Array object from class.list
To fix #383
2015-10-03 21:21:56 +09:00
Hyunje Alex Jun
8761735a54 Update Travis CI and NPM configuration
To be compatible with their newest versions.
2015-10-03 21:16:23 +09:00
Hyunje Alex Jun
c285521caa Lint update-scroll.js
With the new .eslintrc
2015-10-03 20:45:38 +09:00
Hyunje Alex Jun
3d2d50c308 Update .eslintrc
To make it compatible with new versions of ESLint and specify other
options.
2015-10-03 20:44:38 +09:00
DanielApt
a0d39e1b49 Make sure scroll is at the start/end when the reach start/end event fires 2015-09-29 15:28:58 +01:00
DanielApt
e288476ba0 Update README.md with new events 2015-09-28 11:13:25 +01:00
DanielApt
e9bc40bd37 Update events example to show new reach events 2015-09-28 11:09:51 +01:00
DanielApt
0b8fe0ac0b Dispatch events when reaching start / end of axes 2015-09-28 11:08:59 +01:00
Jun
a3676556b2 Merge pull request #386 from DanielApt/events
Dispatch scroll events
2015-09-24 19:44:31 +09:00
DanielApt
39893fc6f2 Add example for events 2015-09-24 11:02:33 +01:00
DanielApt
6c5b9d249e Add missing parentheses 2015-09-24 09:53:59 +01:00
DanielApt
2ef7e81ce9 Add Events to the README 2015-09-23 21:05:28 +01:00
DanielApt
3b90c734e4 Dispatch custom scroll events with new updateScroll function 2015-09-23 20:49:37 +01:00
Hyunje Alex Jun
afebe908b1 NPM version bump.
https://github.com/npm/npm-registry-couchapp/issues/148
2015-08-18 04:16:20 +09:00
Hyunje Alex Jun
6cbb4a9b9d Release 0.6.5
1. Add shift+space support.
2. Bug fixes.
2015-08-18 03:54:56 +09:00
Hyunje Alex Jun
51f33a44b5 Remove unused garbage rails before append a new one.
This patch fixes #376.
2015-08-18 03:51:12 +09:00
Hyunje Alex Jun
8eac54d49f Add a queryChildren method to dom.js 2015-08-18 03:26:15 +09:00
Hyunje Alex Jun
ed4e335978 Declare a module object DOM in dom.js
To refer in the sibling methods.
2015-08-18 03:23:27 +09:00
Jun
272bb4983a Merge pull request #379 from srcn/master
Add shift+space support for keyboard
2015-08-17 21:43:02 +09:00
srcn
f200bea4cc add shift+space support for keyboard 2015-08-17 15:19:30 +03:00
Hyunje Alex Jun
b1d7aa0e64 Release 0.6.4
1. Add null-check for instances.
2. Add 'stopPropgationOnClick' option.
2015-07-25 02:28:12 +09:00
Hyunje Alex Jun
49e39f513d Update README.md 2015-07-25 02:26:55 +09:00
Jun
89f4226778 Merge pull request #366 from dorilla/feature/stop-propagation-on-click
Allow the clicking of a rail to propagate
2015-07-25 02:23:42 +09:00
Dan Maglasang
79f4cfcf5f Update README.md 2015-07-22 22:47:33 -04:00
Dan Maglasang
158b113d18 Allow the clicking of a rail to propagate 2015-07-22 22:43:38 -04:00
Hyunje Alex Jun
6c642d8a47 Just early return instead of throwing an error for no instance. 2015-07-14 12:22:40 +09:00
Hyunje Alex Jun
f9f20eeb6f Add null-check when updating or destroying an instance.
Throw an error when an instance is not found.
2015-07-07 15:25:16 +09:00
Hyunje Alex Jun
1f082a2e04 Release 0.6.3
1. Improve toInt
2. Stop propagating click event through scrollbar rails.
3. IE touch device fix.
4. RTL support.
5. Other minor fixes.
2015-06-22 22:21:25 +09:00
Hyunje Alex Jun
b19c5e0765 Chmod 644 README.md 2015-06-22 21:38:43 +09:00
ahspw
3dbf20a5d0 perfect RTL support 2015-06-22 21:36:43 +09:00
guandai
db855ceca1 update readme 2015-06-22 21:28:47 +09:00
Jun
84b74926e3 Merge pull request #347 from danthewolfe/ie-touch-device
IE touch device fix
2015-06-17 13:02:22 +09:00
dan
d6bd30f2da IE touch device fix
Add vendor specific css for IE to handle let javascript handle touch events instead of letting css attempt to handle them. Without this CSS property IE touch devices do not work.
2015-06-16 15:43:00 -04:00
Hyunje Alex Jun
fc28ceb4ea Stop propagating click event through scrollbar rails.
Fixes #326.
2015-04-29 13:08:03 +09:00
Hyunje Alex Jun
ca4d835129 Simplify parseInt.
Because `~~` isn't necessarily faster than `parseInt` in every browser.
Now I think it'd be better to make it readable and simple.
2015-04-15 21:41:11 +09:00
Jun
88b4e2fc19 Merge pull request #321 from juxtapos/toInt-fix
changed toInt()'s function behavior
2015-04-15 21:39:10 +09:00
Claus Augusti
de32082a62 changed the toInt()'s function behavior so that it returns 0 on empty strings 2015-04-15 13:56:38 +02:00
DanielApt
7ba25d020c Add an editor config file 2015-04-14 13:57:45 +09:00
Jun
08d559561e Merge pull request #320 from jaronkk/scrollbar-margins
Support large and percentage margins on scrollbar rails
2015-04-14 13:56:47 +09:00
Jaron Kennel
046ce954fd Fix gulp watch to call sass instead of css 2015-04-13 13:12:09 -04:00
Jaron Kennel
a40ab40695 Fix clicking and dragging the scrollbar rails with large margin values.
Fix initial rail height/width calculation: Set the rails to display:block temporarily to correctly calculate percentage margins
Account for scrolltop/left on the document.
2015-04-13 13:12:00 -04:00
Hyunje Alex Jun
2cd65684e2 Release 0.6.2
1. Reattach rails when removed.
2. Check if parentNode exists when DOM-removing.
3. Consume mousewheel event for hovered textarea.
4. Other minor fixes.
2015-04-11 02:24:49 +09:00
Hyunje Alex Jun
a0b3754a0d Lint.
Missing semicolon.
2015-04-11 02:24:49 +09:00
Hyunje Alex Jun
dc7b14d0e1 Consume mousewheel event when there's hovered textarea.
Only when it needs to be scrolled.
2015-04-11 02:16:37 +09:00
Jun
a5aab04264 Merge pull request #309 from DanielApt/remove-patch
Check if parentNode exists
2015-04-08 18:53:16 +09:00
DanielApt
aca7683de1 Change tab size to 2 2015-04-02 10:18:46 +01:00
Hyunje Alex Jun
c21cfb6ed0 Add version information to built files. 2015-04-02 02:10:25 +09:00
Hyunje Alex Jun
e4b21c7069 Remove -ms-filter for opacity.
The plugin doesn't support old IEs.
2015-04-02 01:12:44 +09:00
DanielApt
bb58ab98e3 Fix failing test 2015-03-27 18:28:51 +00:00
DanielApt
633f1f53d3 Check if parentNode exists
We need to check if parentNode exists, as in some scenarios it does not (e.g. phantomjs < 2)
2015-03-27 16:58:10 +00:00
Hyunje Alex Jun
4a7f27356a Change the way to re-attach rails when they're detached.
Instead of destroying and re-initialising the plugin, just re-append
them.
2015-03-11 22:07:14 +09:00
Hyunje Alex Jun
2e071274db Release 0.6.1
1. jQuery adaptor error fix.
2015-03-06 02:02:25 +09:00
Jun
b23ad2834e Merge pull request #297 from BR0kEN-/issue-296
Fixed an issue #296 with undefined function in jQuery plugin.
2015-03-06 00:50:35 +09:00
Sergey Bondarenko
cbdf812de8 Issue #296 has been fixed 2015-03-05 14:41:12 +02:00
Jun
5e363b876f Merge pull request #293 from DanielApt/patch-1
#277 has been closed, remove reference to it in README.md
2015-03-03 03:00:20 +09:00
DanielApt
cbf96b3302 #227 has been closed, remove reference to it in README.md 2015-03-02 17:57:00 +00:00
Hyunje Alex Jun
9354fb064a Release 0.6.0
It's a huge change! #277

1. Use Browserify to make the source tree modular.
2. Be independent from jQuery.
3. npm with browserify compatibility.
4. Separate a bower repo.
5. Bug Fixes.
2015-03-03 02:37:59 +09:00
Hyunje Alex Jun
4d060c7df5 Fix typo in .travis.yml 2015-03-03 02:37:59 +09:00
Hyunje Alex Jun
4984102cd3 Remove bower_components from .gitignore
It's not used.
2015-03-03 02:32:27 +09:00
Hyunje Alex Jun
fb5c6ef74f Add .npmignore 2015-03-03 02:32:26 +09:00
Hyunje Alex Jun
c280c270b8 Merge pull request #287 from DanielApt/nojs-fallback
No longer require to manually add overflow:hidden, plugin does this. [#285]
2015-02-22 19:16:43 +01:00
DanielApt
73ff93984b overflow:hidden no longer required - Update README.md 2015-02-21 20:37:42 +00:00
DanielApt
9ca1539ab4 Use overflow:auto instead of scroll 2015-02-21 12:53:42 +00:00
Hyunje Alex Jun
05ccc0a5cb Merge pull request #286 from rangermeier/master
False selection detection when typing something into input
2015-02-20 19:57:00 +01:00
Rupert Angermeier
42cf8d3679 Adapt fallback for selection
Thanks @darthmaim for pointing this out
2015-02-19 16:31:27 +01:00
DanielApt
313f62d2f8 Update examples to use no-js fallback of overflow: scroll 2015-02-18 16:36:10 +00:00
DanielApt
6af7500d6b Hide overflow only on .ps-container 2015-02-18 16:17:42 +00:00
DanielApt
f7dbb9b485 Ignore .idea (jetbrains) files 2015-02-18 15:31:54 +00:00
Rupert Angermeier
8290c4f726 Fix issue with false selection detection
`selection.rangeCount` will return 1 when user is typing something in a
form widget. This will consequently trigger unvoluntary scrolling when
the mouse is moved outside of scrollable area. Checking the actual
length of selected text doesn't trigger this behaviour.
2015-02-18 13:34:36 +01:00
Hyunje Alex Jun
b4a51fc454 Hide scrollbars only when updated manually.
Resolve #283.
2015-02-17 01:46:13 +00:00
Hyunje Alex Jun
a12def5213 Fix typo in dom.matches 2015-02-17 01:28:33 +00:00
Hyunje Alex Jun
c4790bb656 Add IE support for dataset.
IE doesn't support dateset, so use a raw `data-ps-id`
attribute.
2015-02-17 01:26:44 +00:00
Hyunje Alex Jun
86a23cb74e Don't use Bower in the same repo anymore.
It has been separated into another repo:
https://github.com/noraesae/perfect-scrollbar-bower
2015-02-12 22:50:29 +00:00
Hyunje Alex Jun
17aac6c8c8 Fix wrong links in example.
`.global.` is no more used.
2015-02-12 20:08:09 +00:00
Hyunje Alex Jun
41ca0246ad Change the output dir name from out to dist. 2015-02-12 19:56:27 +00:00
Hyunje Alex Jun
9668a79468 Add automatic release with TravisCI. 2015-02-12 19:39:14 +00:00
Hyunje Alex Jun
30b4f27e03 Add a compress task to Gulp. 2015-02-12 19:33:24 +00:00
Hyunje Alex Jun
11997131f4 Add AMD support. 2015-02-12 18:45:04 +00:00
Hyunje Alex Jun
7a8b47179c Change global outputs' names to just perfect-scrollbar. 2015-02-12 18:32:17 +00:00
Hyunje Alex Jun
ab40b55c8f Add CommonJS support for the jQuery adaptor. 2015-02-12 18:25:17 +00:00
Hyunje Alex Jun
64ea58514b Update README.md 2015-02-11 17:02:22 +00:00
Hyunje Alex Jun
68d468c465 Add NPM and CommonJS compatibility. 2015-02-11 17:00:48 +00:00
Hyunje Alex Jun
db2b282431 Remove postinstall script.
Temporarily until the development ends.
2015-02-11 17:00:48 +00:00
Hyunje Alex Jun
ff3a3c04b2 Add a table example. 2015-02-11 16:00:19 +00:00
Hyunje Alex Jun
81dd8e9eb0 Add a guard to check if activeElement exists. 2015-02-11 16:00:19 +00:00
Hyunje Alex Jun
b5d0958e82 If scrollbar's detached, reinitialise the plugin in update. 2015-02-11 16:00:19 +00:00
Hyunje Alex Jun
c8fe0b9269 Add missing updates in handlers. 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
b000c771af Fix typo in touch handler. 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
a52a945226 Modularise handlers. 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
0acf3602f0 Fix RTL outer width problem.
`offsetWidth` doesn't work for hidden elements.
2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
48eb80bd7f Rewrite examples with a native JavaScript version. 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
89c3bdb1cf Fix typos. 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
ee455fafa5 Implement adaptors. 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
6f5a9088aa Replace $.contains with Node.contains
Now completely independent from jQuery.
2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
f8b20a9fc9 Fix typo in helper.removePsClasses 2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
70acad4941 Implment a native event manager.
Now we're about to be independent from jQuery!
2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
95540bdd9e Change to eslint from jshint.
It's way better. Original files have been linted.
2015-02-11 15:53:42 +00:00
Hyunje Alex Jun
5d62b130e9 Remove .csslintrc
It's no longer used.
2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
80cfa8dc0e Add a live reload task in Gulp. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
fa7e169b9f Separate initialize, update and destroy functions. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
7ab6c5e5ef Fix a CSS bug that an unwanted scrollbar appears. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
427284337f Separate $.one event handler. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
796a0a9093 Remove output directory from the repository. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
bbab2a3c53 Separate env helpers. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
aa58a8298e Remove variable cleaning. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
1541f73add More independent. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
ff5ca3d804 Remove includePadding option.
It's supported by default.
2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
3f002c49a1 Remove $this. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
a496ff1a75 Make DOM manipulation independent from jQuery. 2015-02-11 15:53:41 +00:00
Hyunje Alex Jun
9a89e73cf9 Separate event class factory module. 2015-02-11 15:53:40 +00:00
Hyunje Alex Jun
6d1f558c02 Separate a class module. 2015-02-11 15:53:40 +00:00
Hyunje Alex Jun
339e478674 Separate main.js into some modules.
Helper functions and the plugin function are separated.
2015-02-11 15:53:40 +00:00
Hyunje Alex Jun
d54c7d6640 Change paths in examples. 2015-02-11 15:53:17 +00:00
Hyunje Alex Jun
74fc0daf49 Use browserify. 2015-02-11 15:53:17 +00:00
Hyunje Alex Jun
c0cf399841 Remove perfect-scrollbar.jquery.json
It's no longer used.
2015-02-11 15:53:17 +00:00
Hyunje Alex Jun
804d94d3a0 Migrate into Gulp. 2015-02-11 15:53:08 +00:00
Hyunje Alex Jun
254b22877c Release 0.5.9
1. Change how `in-scrolling` works.
2. Bug fixes.

This is the last release of an old-styled version. In the next version,
it may change a lot. Please stay tuned!
2015-02-11 15:43:34 +00:00
Hyunje Alex Jun
1a6197cbed Add a table example. 2015-02-05 20:06:05 +00:00
Hyunje Alex Jun
2fc41e7045 Add a guard to check if activeElement exists. 2015-02-05 19:18:35 +00:00
Hyunje Alex Jun
bd22fc0e58 2014 -> 2015.
Happy new year!
2015-01-08 17:36:54 +00:00
Hyunje Alex Jun
3b3431e226 Merge pull request #270 from DanielApt/SCSS_Colors
Define the used colors as variables
2014-12-17 00:22:25 +09:00
DanielApt
373838d825 Define the used colors as variables 2014-12-16 13:21:16 +00:00
Hyunje Alex Jun
b927c177ca Change how .in-scrolling works.
Now we add `.ps-in-scrolling` class in a container div.
`pointer-events: none;` is also added for the class.
2014-12-09 23:57:52 +00:00
Hyunje Alex Jun
d6558c492d Merge pull request #259 from smithl/patch-1
Update README.md
2014-12-02 18:27:10 +00:00
Smith
e1db204dd4 Update README.md
Your english isn't bad at all - great work on the plugin! Here are a few text updates to the readme.
2014-12-02 09:47:34 -08:00
Hyunje Alex Jun
dcdefebded Release 0.5.8
1. Improve mouse handler logic.
2. Add rail margin detection.
3. Add swipePropagation option.
4. Bug fixes.
2014-12-02 11:40:46 +00:00
Hyunje Alex Jun
fae5c001d4 Update README.md
Add `swipePropagation`.
2014-12-02 11:38:54 +00:00
Hyunje Alex Jun
febcaa3603 Add an example for scrollbar margin. 2014-12-02 11:34:45 +00:00
Hyunje Alex Jun
20576ac717 Merge pull request #252 from tkhyn/master
Detects margins around the rails
2014-12-02 11:34:07 +00:00
Hyunje Alex Jun
7ce708216d Small style fixes for preventDefault functions. 2014-12-02 11:24:36 +00:00
DI-john
931be25635 propagate mobile swipe gestures to page where appropriate 2014-12-02 11:00:37 +00:00
Thomas Khyn
74d0fcb1de Detects margins around the rails 2014-11-17 14:18:37 +13:00
Hyunje Alex Jun
9b3301fd0c Merge pull request #251 from tatarinov/master
Renamed 'int' helper in 'getInt' #250
2014-11-14 12:27:05 +00:00
tatarinov
a94df46fe3 Removed unnecessary semicolon 2014-11-14 10:25:19 +04:00
tatarinov
20053e9cf1 Renamed 'int' helper in 'getInt' #250 2014-11-14 10:04:07 +04:00
Hyunje Alex Jun
aaab294dc4 Add an example for always-visible scrollbars. 2014-11-11 14:40:03 +00:00
Hyunje Alex Jun
e9fcc0f02a Temporary fix for mousewheel problem of select in FF and IE.
Resolve #247.
2014-11-11 13:29:09 +00:00
Alexandr Subbotin
05b20f45ef decrease mouse handlers count and every-time class checking during mousemove 2014-11-11 13:28:58 +00:00
Hyunje Alex Jun
3821413589 Release 0.5.7.
1. IE mouse pointer event bug fix.
2. Use scss for stylesheet.
3. Clear intervals when destroyed.
4. Bug fixes.
2014-11-05 19:02:45 +00:00
Hyunje Alex Jun
08a387d9c1 Add removable-list-element example. 2014-11-05 19:02:00 +00:00
Hyunje Alex Jun
1849e64122 Remove remaining inline display style.
It caused regression bugs.
2014-11-05 18:51:52 +00:00
Hyunje Alex Jun
f9c3dc0b20 Change name of variable breakingProcess.
It's too ambiguous to understand the purpose of the variable.
2014-10-31 19:25:43 +00:00
Hyunje Alex Jun
aa92487ed3 Clear intervals if the plugin is destroyed. 2014-10-31 19:25:13 +00:00
Hyunje Alex Jun
a3bf38ada2 Update README.md
Add FAQ.
2014-10-31 19:16:36 +00:00
Hyunje Alex Jun
d24f9bd41b Use scss for stylesheet.
We can build the scss source to .css and .min.css files with the
`grunt build` command.
2014-10-31 02:20:22 +00:00
Hyunje Alex Jun
5be50316ca Merge pull request #239 from darthmaim/bugfix_ie10_pointertype
Don't handle mouse pointer events as touch in IE10.
2014-10-30 18:21:43 +00:00
Konrad Liebig
94be67d998 Don't handle mouse pointer events as touch in IE10 2014-10-30 17:04:20 +01:00
Hyunje Alex Jun
17fd46a07d Release 0.5.6.
1. Add scrolling with selection.
2. Bug fixes.
2014-10-28 18:02:22 +00:00
Hyunje Alex Jun
f099448e44 Change how scrollbar rails are being hidden.
Inline CSS change is bad practice.
2014-10-28 18:01:23 +00:00
Hyunje Alex Jun
d0b97e4039 Add selection handler.
Now perfect-scrollbar supports scrolling by selection.
2014-10-28 17:49:16 +00:00
Hyunje Alex Jun
f2342f2678 Change the way to handle event class name.
Use factory pattern to handle it, instead of using + operator of
string.
2014-10-28 16:41:36 +00:00
Hyunje Alex Jun
967c30a5e4 Shouldn't prevent default for touchStart.
Default touch event shouldn't be prevented.
2014-10-28 14:33:07 +00:00
Hyunje Alex Jun
7cf8303b30 Release 0.5.5.
1. Bug fixes.
2014-10-24 12:06:04 +01:00
Hyunje Alex Jun
7dd6335965 Filter touch events not to be handled.
In IE 10/11, MSPointer event is fired by mouse. It shouldn't be handled.

Also, Exception has occurred with event.targetTouches, and this commit
fixed it too.
2014-10-24 12:03:55 +01:00
Hyunje Alex Jun
494d68fe02 Merge pull request #231 from suxxes/patch-1
Correction for railBorderYWidth calculation
2014-10-22 16:10:07 +01:00
Fedor
3dde3ebb0c Correction for railBorderYWidth calculation 2014-10-22 17:09:45 +04:00
Hyunje Alex Jun
12086573fc Update README.md
Add `npm` to install section.
2014-10-21 21:43:07 +01:00
Hyunje Alex Jun
a98c77d160 Release 0.5.4
1. Inner scrollbar problem fix.
2. Inner scrollbar touch event problem fix.
3. Bug fixes.
2014-10-21 21:31:02 +01:00
Hyunje Alex Jun
48e1c688b2 Add additional information to package.json 2014-10-21 21:29:34 +01:00
Hyunje Alex Jun
991e664b18 Stop propagation and prevent default for touch events.
Fix #228.
2014-10-21 21:14:23 +01:00
Hyunje Alex Jun
ee4fc96b7a Bind touch handlers only when it's supported.
Fix #227.
2014-10-21 21:06:16 +01:00
Hyunje Alex Jun
664dec23d6 No longer support old IEs. 2014-10-21 20:58:43 +01:00
Hyunje Alex Jun
65869821c1 Use > CSS selector.
This patch will resolve inner scrollbar problems.
2014-10-21 20:53:55 +01:00
Hyunje Alex Jun
4f7595a34f Release 0.5.3.
1. Focusable element bug fix for ShadowDom element.
2. Int conversion enhancement.
3. Add IE Pointer handler.
4. Ctrl+Home/End support.
5. Iframe support.
2014-10-14 01:38:04 +01:00
Hyunje Alex Jun
97a44c29a8 Add grunt task to release new version. 2014-10-14 01:37:05 +01:00
Nicolás Moncada
467cdb17ed Adding an example using iframe. 2014-10-14 01:11:06 +01:00
Nicolás Moncada
6ac02fae2b It makes compatible with iframes. 2014-10-14 01:11:06 +01:00
Hyunje Alex Jun
d4ec7fca6d Merge pull request #219 from MathieuLorber/input-in-shadowdom
ShadowDom form elements are considered for preventing scrolling by keyevent
2014-10-14 01:46:03 +02:00
Gene Diaz Jr
0022bd5595 Added cdn information
mirror on cdnjs.com http://cdnjs.com/libraries/jquery.perfect-scrollbar

Modified by @noraesae, as I wouldn't want to update README every time
I bump up the version.
2014-10-14 00:39:09 +01:00
Hyunje Alex Jun
1b1195288b Add ctrl key support for keyboard handler.
Originally written by @wikenator.
2014-10-14 00:29:51 +01:00
loliver
e6590da884 IE Pointer Events
Added support for PointerEvents (and MSPointerEvents) to support touch
in IE10 and 11.

Modified by @noraesae.
2014-10-14 00:13:04 +01:00
Hyunje Alex Jun
e98bfec4f2 Remove IE6 specific fixes.
Just don't use IE6.
2014-10-13 23:47:47 +01:00
Hyunje Alex Jun
f7d90464e0 More code refactoring.
It's never enough.
2014-10-13 23:47:47 +01:00
Hyunje Alex Jun
337c0be9e2 Add int() helper instead of parseInt.
parseInt is a good option for string-int conversion,
but none for float-int conversion because of performance issue.

This is also to make the code clean.
2014-10-13 23:24:20 +01:00
Hyunje Alex Jun
36c988faba Code refactoring. 2014-10-13 23:24:20 +01:00
Mathieu Lorber
a573d2cd9d ShadowDom form elements are considered for preventing scrolling by keyevent 2014-10-01 11:49:16 +02:00
Hyunje Alex Jun
f231110f21 Merge pull request #217 from josemalonsom/patch-1
Minor corrections in example.
2014-09-29 21:54:11 +01:00
josemalonsom
503b05f5ae Minor corrections in example.
Just a couple of minor corrections in the CSS of the example "How to use".
2014-09-29 22:18:05 +02:00
Hyunje Alex Jun
abab1e47a4 Release 0.5.2.
1. Hide suppressed scrollbar rails.
2014-09-28 01:30:58 +01:00
Hyunje Alex Jun
c1b40168f6 Hide scrollbar rails when they're suppressed.
They were displayed even though suppresed. In this patch,
the scrollbar rails won't be displayed unless they're needed.
2014-09-28 01:28:38 +01:00
Hyunje Alex Jun
937463cf75 Change name. 2014-09-24 19:35:43 +01:00
Hyunje Alex Jun
424e577dbc Bump up version in bower.json 2014-09-16 11:28:40 +01:00
Hyunje Alex Jun
575280e9c2 Release 0.5.1.
1. Change dragging logic.
2. Remove jquery-mousewheel dependency.
3. Bug fixes.
2014-09-15 22:58:28 +01:00
Hyunje Alex Jun
d3181f0b0d Mousewheel fixes for Firefox and IE 10.
Now tested with the latest versions of following browsers.

In OS X:
Chrome
Firefox
Safari

In Windows:
Chrome
Firefox
Internet Explorer 10
Opera
Safari
2014-09-15 22:53:40 +01:00
Hyunje Alex Jun
0fc81dfa83 Remove Firefox hack for MozMousePixelScroll.
It just works fine without it.
2014-09-15 21:53:23 +01:00
Hyunje Alex Jun
1d315786a0 Hide scrollbars while updating to stop affecting geometries.
Scrollbars keep affecting the geometries and it leads to wrong
scrollWidth and scrollHeight. So hide them in advance and show
them again after updating.
2014-09-15 21:45:27 +01:00
Hyunje Alex Jun
32a0caf2d8 Change wheelSpeed of text-content example.
The default value is changed.
2014-09-15 21:40:15 +01:00
Hyunje Alex Jun
22bffa9ba8 Add update functionality to options-default example.
It's useful to test the plugin with the update function.
2014-09-15 14:05:34 +01:00
Hyunje Alex Jun
babd3949c7 Update README.md
Gitter doesn't work well.
2014-08-31 01:35:43 +01:00
Hyunje Alex Jun
cbdccf9736 Remove jquery-mousewheel dependencies.
Tested under OS X.
2014-08-25 00:35:51 +01:00
Hyunje Alex Jun
a63c136c09 Change main property to use non-minified files for bower.
https://github.com/noraesae/perfect-scrollbar/issues/133
2014-08-24 23:30:29 +01:00
SideraX
d272206181 Update package.json to be compatible with browerify.
Updated: non-minified source is preferred for the `main` property.
2014-08-24 23:23:33 +01:00
Hyunje Alex Jun
a022621df8 Change dragging logic.
Using `updateBarSizeAndPosition` instead of manual update of scrollbar
CSS styles.
2014-08-07 13:25:46 +01:00
Hyunje Alex Jun
2b87bbe081 Update README.md
Add Gitter and Travis CI status.
2014-08-06 20:39:16 +01:00
Hyunje Alex Jun
cee1e3f015 Merge pull request #188 from d42f/master
Update perfect-scrollbar.css
2014-08-06 20:27:10 +01:00
d42f
c5f442a70e Update perfect-scrollbar.css
remove spaces
2014-07-29 13:56:38 +04:00
Hyunje Alex Jun
6b35561bb3 Release 0.4.11.
1. Add active- class when scrolls are active
2. Add maxScrollbarLength option
3. Bug fixes
2014-07-16 18:57:45 +01:00
Hyunje Alex Jun
57cc39e6e8 Add 'maxScrollbarLength' option in README.md 2014-07-16 18:56:46 +01:00
Hyunje Alex Jun
3adb98cd40 Merge pull request #174 from ivan1986/patch-1
add maxScrollbarLength.
2014-07-16 18:53:04 +01:00
Martijn Saly
4e90f8c170 Keydown now checks if the event was preventDefault()'ed. 2014-07-16 18:42:40 +01:00
Karol Tomoki Yamazaki
eb13d331d9 Consider border of scrollbar rails.
Fixes #176 https://github.com/noraesae/perfect-scrollbar/issues/176
2014-07-16 18:40:57 +01:00
Hyunje Alex Jun
c6f2e6abd3 Merge pull request #159 from sarunas/master
Add ps-visible class on container then scrollbar is active.
2014-07-16 18:37:21 +01:00
Hyunje Alex Jun
845452f654 Merge pull request #173 from jlcarvalho/patch-1
Update README.md.
2014-07-16 18:35:51 +01:00
Ivan Borzenkov
49a2a694b9 add maxScrollbarLength 2014-07-09 21:16:16 +04:00
jlcarvalho
1f8a37894b Update README.md
The container must have the properties height and overflow.
2014-07-09 11:26:54 -03:00
Šarūnas Dubinskas
fd56fdfe02 Add ps-active-* class on container then scrollbar is active 2014-07-07 10:42:37 +03:00
Hyunje Alex Jun
6fa5f198e2 Add help text for wheelPropagation option. 2014-07-05 18:01:24 +01:00
Hyunje Alex Jun
f8759f713c Unify jQuery version dependencies. 2014-07-05 17:46:17 +01:00
Hyunje Alex Jun
4b3b057838 Merge pull request #152 from slopjong/hotfix/version-removed-from-dist-files
Removed version from dist file names. Fixes #150.
2014-05-17 10:55:42 +01:00
slopjong
b5675c4d5b Removed version from dist file names 2014-05-17 06:55:21 +02:00
Hyunje Alex Jun
6e2d95f309 Change emails in json files. 2014-04-29 14:22:02 +01:00
Hyunje Alex Jun
630f0686a9 Release 0.4.10.
1. Add opposite-sided scrollbar feature
2. RTL support
3. Bug fixes
2014-04-27 11:49:33 +01:00
Hyunje Alex Jun
bd99960ed1 Add missing variables when cleaned. 2014-04-27 11:43:21 +01:00
ahspw
b8231ecd79 add rtl support
Conflicts:
	src/perfect-scrollbar.js
2014-04-27 11:41:14 +01:00
Hyunje Alex Jun
4a8e8066ab Implement opposite-sided scrollbars.
Now when you use `top` for the x-axis scrollbar or `left` for the y-axis
scrollbar, the scrollbars will be displayed on the opposite side.
2014-04-27 11:01:11 +01:00
ahspw
61e1e6893d fix some typos 2014-04-25 22:00:29 +01:00
Hyunje Alex Jun
8d30c29602 Update names and licenses. 2014-04-10 23:39:49 +01:00
Hyunje Alex Jun
f77fa0b05b Merge pull request #132 from Feasul/patch-2
Prevent scrollbar rail disappearance during scrolling.
2014-04-05 20:05:37 +01:00
Andrey Nikitenko
6559492079 Update perfect-scrollbar.css
prevent scrollbar rail from disappearing when mouse pointer leaves scrollbar area while dragging the scrollbar
2014-04-04 16:24:47 +03:00
Hyunje Alex Jun
70fcb3a6c4 Update README.md
Use innerWidth and innerHeight for 'includePadding' option.
2014-04-02 00:58:41 +09:00
Hyunje Alex Jun
4357617540 Release 0.4.9.
1. Update jquery-mousewheel to 3.1.9
2. CommonJS compatible
3. Add 'includePadding' option
4. Bug fixes
2014-04-02 00:46:07 +09:00
Hyunje Alex Jun
0f5384948e Prevent default when using 'useBothWheelAxes' option. 2014-04-02 00:42:00 +09:00
Hyunje Alex Jun
9a589639b0 Merge pull request #119 from noraesae/mousewheel-speed
Change mousewheel delta calculation logic.
2014-04-02 00:26:06 +09:00
Hyunje Alex Jun
b26933e6a5 Merge pull request #131 from Feasul/patch-1
Use innerWidth/Height instead of outerWidth/Height to determine the width/height of container.
2014-04-02 00:23:21 +09:00
Andrew
32718ae9cc As per jQuery docs the innerWidth method is the one that includes padding (https://api.jquery.com/innerWidth/), while the previously used outerWidth includes border width as well (https://api.jquery.com/outerWidth/). Therefore the use of innerWidth makes more sense for getting the container width with padding in the code (plus a setting name includePadding suggest only padding width is taken into account as an extra for container width determination and might be confusing otherwise). The same goes to innerHeight vs outerHeight. 2014-04-01 14:27:54 +03:00
Hyunje Alex Jun
fdcedcbbf5 Apply deltaFactor for the delta calculation of mousewheel. 2014-03-23 06:05:00 +09:00
Hyunje Alex Jun
9225275e6c Don't use 'wheelSpeed' value for keyboard scrolling. 2014-03-23 06:05:00 +09:00
Hyunje Alex Jun
84360fb730 Merge pull request #124 from strichter/master
Fix scrolling within nested scrollable DIVs.
2014-03-23 05:07:24 +09:00
Stephan Richter
1a335902cc Fix scrolling within nested scrollable DIVs.
Fixes https://github.com/noraesae/perfect-scrollbar/issues/101
2014-03-22 11:29:07 -04:00
Hyunje Alex Jun
2ccb8f18d5 Use strict mode for function scopes.
Global strict mode is problematic when the script is concatenated
with non-strict scripts.
2014-03-11 16:09:39 +09:00
Hyunje Alex Jun
da05a85ed6 Update README.md 2014-03-10 16:43:04 +09:00
Hyunje Alex Jun
57e5710ab0 Add a description for the 'includePadding' option in README.md 2014-03-10 16:36:26 +09:00
Oleg Kalistratov
9420d1b6a9 Add 'includePadding' option (use container outerWidth/outerHeight instead of width/head) 2014-03-10 16:31:50 +09:00
Hyunje Alex Jun
ee7d3bf62c Add an 'Install' section in README.md 2014-03-10 16:26:50 +09:00
Moritz Meyer
275a928532 create bower json and ignore bower_components directory 2014-03-10 16:09:18 +09:00
Steve Lamb
fc24bbc631 CommonJS compatibility 2014-03-10 01:41:50 +09:00
Joshua Balloch
b45a94971c update readme 2014-03-10 01:41:50 +09:00
Rupert Angermeier
0544fe7241 Fix delta calculation in mouswheel handler
Remove division by 10, makes scrolling slower than in previous versions.
Reverts 88d286957766e981a4f4c720f213164fc0f3f099
2014-03-10 01:41:18 +09:00
Rupert Angermeier
bc6ef6480a Don't scroll by keyevent while form element has focus 2014-03-10 01:41:18 +09:00
Hyunje Alex Jun
04391d4dec Additional typo fix for the patch below. 2014-03-10 01:41:18 +09:00
Ilan
fa03b68938 Fixed typo in CSS: missing space in "-webkit-transition:background-color.2s linear". 2014-03-10 01:41:18 +09:00
Hyunje Alex Jun
fa51f455fe Avoid the 'divide by zero' problem in bindMobileTouchHandler. 2014-03-10 01:41:18 +09:00
Hyunje Alex Jun
aa0b57c51d Change delta calculation in mousewheel handler.
The new version of jquery-mousewheel's delta values are changed,
and should use the new calculation for the values.
2014-03-10 01:41:18 +09:00
Triangle717
a9000d4b6d Update jquery-mousewheel to 3.1.9 2014-01-24 13:37:50 -05:00
Hyunje Alex Jun
4c0163a2f6 Release 0.4.8.
1. Bug fixes.
2014-01-22 11:21:35 +09:00
Hyunje Alex Jun
f1491e777d Fix the bug that scrollbar rails show when they shouldn't.
Now, the scrollbar rails show even if the content is smaller than the
container. This patch fixes it.
2014-01-22 11:17:29 +09:00
Hyunje Alex Jun
c1c41e6d14 CSS fixes for IE. 2014-01-21 21:38:45 +09:00
Hyunje Alex Jun
e159cbbda5 Release 0.4.7.
1. Don't prevent the default scrolling for the inactive axis.
2. Enhance the scrolling logic.
3. Implement Home, End, Page Up, Page Down and Spacebar for the key
   scrolling.
4. Bug fixes.
2014-01-21 12:30:13 +09:00
Hyunje Alex Jun
b8d8218c03 Add a getEventClassName() function.
Each scrollbar object should have its own event class name. Unless,
When the one scrollbar is destroyed, another one's event will be
unbinded too.

The getEventClassName() function returns a unique event class name.
2014-01-21 12:22:04 +09:00
Hyunje Alex Jun
d58e109d98 Add an example about the callback to check if it reaches the end. 2014-01-21 11:57:30 +09:00
Hyunje Alex Jun
de3bc97437 Merge pull request #92 from asiviero/master
Implement Home, End, Page Up, Page Down and Spacebar.
2014-01-20 18:55:54 -08:00
Andre Siviero
63c6d67ad5 Implemments Home, End, pageUp, pageDown and Spacebar 2014-01-20 20:14:26 -02:00
Hyunje Alex Jun
40b46a4071 Change the scrolling logic.
Add a scroll handler to handle the previously unhandled events,
and remove updateBarSizeAndPosition() where it's not needed anymore.
2014-01-15 00:23:21 +09:00
Hyunje Alex Jun
71838b9f72 Don't prevent the default scrolling for the inactive axis. 2013-12-14 16:33:15 +09:00
Hyunje Alex Jun
693bc9b784 Change the names in perfect-scrollbar.jquery.json.
Change 'J' to 'j'.
2013-12-06 11:41:08 +09:00
Hyunje Alex Jun
23722670c2 Release 0.4.6.
1. Following options are added.
 - suppressScrollX, suppressScrollY, scrollXMarginOffset and
   scrollYMarginOffset
2013-12-06 11:28:41 +09:00
Hyunje Alex Jun
e390a89f57 Add an example for the scroll suppression feature.
The 'suppressScrollX' and 'suppressScrollY' features were added and
this patch add the example for the features.
2013-12-06 11:25:48 +09:00
Hyunje Alex Jun
6595d602b1 Merge pull request #77 from adrianonantua/master
Added 4 new setting options (suppressScrollX, suppressScrollY, scrollXMarginOffset and scrollYMarginOffset)
2013-12-05 18:25:25 -08:00
Adrian Carneiro
05fadaa786 README.md formatting 2013-11-06 15:28:39 -05:00
Adrian Carneiro
fa806adb55 Added 4 new setting options (suppressScrollX, suppressScrollY, scrollXMarginOffset and scrollYMarginOffset)
Added 4 new setting options (suppressScrollX, suppressScrollY,
scrollXMarginOffset and scrollYMarginOffset)
2013-11-06 15:20:30 -05:00
Hyunje Alex Jun
ad0e1e4fab Release 0.4.5.
Patch notes
1. AMD compatibility.
2. Add 'useBothWheelAxes' feature.
3. Implement keyboard scrolling.
4. Implement visible rails.
2013-09-30 23:37:59 +09:00
Hyunje Alex Jun
43c7b22678 Add click handlers on scrollbar rails to scroll to the position. 2013-09-30 23:32:50 +09:00
Hyunje Alex Jun
51db8add43 Implement visible rail feature.
Now the scrollbars are wrapped by rail elements, and
the styles and scripts are heavily changed to implement the feature.
2013-09-30 23:32:50 +09:00
Hyunje Alex Jun
8ea7291469 Implement keyboard scrolling.
Now when the element is hovered by mouse cursor, it can be scrolled
with arrow keys on the keyboard.
2013-09-30 17:24:12 +09:00
Hyunje Alex Jun
c4632c97ed Change the event namespace to 'perfect-scrollbar'.
There's no reason to use 'perfect-scroll'.
It's weird.
2013-09-30 17:04:26 +09:00
Hyunje Alex Jun
7fec407295 Update README.md.
Fix some texts and add a notation for using example codes.
2013-09-30 16:26:21 +09:00
Hyunje Alex Jun
67635e54d7 Add an example for 'useBothWheelAxes' option. 2013-09-30 16:19:24 +09:00
Hyunje Alex Jun
b0c8e91f18 Change the title in example codes and update jQuery to 1.10. 2013-09-30 15:48:51 +09:00
Hyunje Alex Jun
18c9517205 Merge pull request #64 from jakubmal/flexible-scroll
Use vertical scroll for horizontal scrollbar if only horizontal scrollbar is present.
2013-09-29 23:47:44 -07:00
Jakub Malinowski
16998f95f1 Added optional useBothWheelAxes to allow more flexible scrolling if only one axe is scrollable 2013-09-28 00:53:57 +02:00
Hyunje Alex Jun
7a65e01ab5 Merge pull request #63 from julien/master
Make it AMD compatible.
2013-09-23 19:54:27 -07:00
Julien Castelain
067b10d83d Make it AMD compatible 2013-09-20 11:04:29 +02:00
Hyunje Alex Jun
58261f2ace Release 0.4.4.
Patch notes
1. Bug fixes.
2013-09-09 10:44:48 +09:00
Hyunje Alex Jun
ebef76a2c6 Add unbind for 'document'.
The function call is needed cause there are mouse handlers
for the element.
2013-09-09 10:12:35 +09:00
Hyunje Alex Jun
be5e338869 Update jshintrc.
Added strict, laxcomma and camelcase options.
Removed the es5 option.
2013-08-31 02:24:43 +09:00
Hyunje Alex Jun
cf8cea8b13 Fix that wheelPropagation option doesn't work in Firefox. 2013-08-06 15:14:55 +09:00
Fabian Vogelsteller
74f97e330e reduced the risk of memory leaks 2013-08-06 14:18:21 +09:00
Hyunje Alex Jun
b461fa895b Release 0.4.3.
Patch notes
1. Quick fix for the scrolling problem in Firefox.
2013-08-01 02:16:44 +09:00
Hyunje Alex Jun
af7194114a Fix Firefox scrolling problem in OS X.
In OS X, there was the problem that the mousewheel event's
preventDefault() doesn't work well. This patch fixes the problem.
2013-08-01 02:03:44 +09:00
Hyunje Alex Jun
540834308e Fix typos in README.md. 2013-08-01 01:33:10 +09:00
Hyunje Alex Jun
bdda167317 Release 0.4.2.
Patch notes
1. Change the logic to detect touch devices.
2. Add minScrollbarLength setting.
2013-08-01 01:09:15 +09:00
Hyunje Alex Jun
123b1d724b Fix the formula between scroll position and scrollbar position.
With @Mordhak's suggestion, fixed the formula to calculate the values.
This patch will resolve the scroll position problem when the
minScrollbarLength setting is applied.
2013-08-01 01:03:33 +09:00
Hyunje Alex Jun
68032d168b Merge pull request #48 from itsdrewmiller/master
Add minScrollbarLength setting.
2013-07-31 08:42:40 -07:00
Drew Miller
ab2a018c93 minScrollbarLength setting
I couldn't figure out the rebasing stuff so I just deleted my fork and
redid the work.  I believe I followed the contributing guidlines
correctly as well.
2013-07-17 12:53:02 -04:00
Zeno Zeng
68c297fe2c Use supportsTouch instead of isMobile. 2013-07-08 23:25:24 +09:00
Hyunje Alex Jun
09c0fb89d2 Use travis-ci. 2013-07-08 23:08:49 +09:00
61 changed files with 3000 additions and 935 deletions

View File

@@ -1,3 +0,0 @@
{
"adjoining-classes": false
}

14
.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
# EditorConfig: http://editorconfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Indentation for JS & SCSS
[*.{js, scss}]
indent_style = space
indent_size = 2

40
.eslintrc Normal file
View File

@@ -0,0 +1,40 @@
{
"env": {
"node": true,
"browser": true
},
"globals": {
"$": true,
"define": true
},
"extends": "eslint:recommended",
"rules": {
"eqeqeq": 2,
"no-multi-spaces": 2,
"curly": 2,
"semi": 2,
"no-with": 2,
"strict": [2, "global"],
"radix": 2,
"no-use-before-define": 2,
"block-spacing": 2,
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
"camelcase": 2,
"comma-spacing": [2, {"before": false, "after": true}],
"eol-last": 2,
"no-multiple-empty-lines": 2,
"indent": [2, 2],
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
"linebreak-style": [2, "unix"],
"new-parens": 2,
"no-trailing-spaces": 2,
"semi-spacing": 2,
"space-before-blocks": [2, "always"],
"space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
"space-in-parens": 2,
"space-infix-ops": 2,
"space-return-throw-case": 2,
"space-unary-ops": 2,
"spaced-comment": 2
}
}

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
.DS_Store
node_modules
/dist
.idea

View File

@@ -1,60 +0,0 @@
{
"passfail" : false,
"maxerr" : 100,
"browser" : true,
"node" : true,
"rhino" : false,
"couch" : false,
"wsh" : false,
"jquery" : true,
"prototypejs" : false,
"mootools" : false,
"dojo" : false,
"predef" : [
"require",
"define"
],
"debug" : false,
"devel" : true,
"es5" : true,
"strict" : false,
"globalstrict" : true,
"asi" : false,
"laxbreak" : false,
"bitwise" : true,
"boss" : false,
"curly" : true,
"eqeqeq" : true,
"eqnull" : false,
"evil" : false,
"expr" : false,
"forin" : false,
"immed" : true,
"latedef" : true,
"loopfunc" : false,
"noarg" : true,
"regexp" : true,
"regexdash" : false,
"scripturl" : true,
"shadow" : false,
"supernew" : false,
"undef" : true,
"newcap" : true,
"noempty" : false,
"nonew" : true,
"nomen" : false,
"onevar" : false,
"plusplus" : false,
"sub" : false,
"trailing" : true,
"white" : true,
"indent" : 2
}

9
.npmignore Normal file
View File

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

15
.travis.yml Normal file
View File

@@ -0,0 +1,15 @@
language: node_js
node_js:
- 0.12
- 4
deploy:
provider: releases
api_key:
secure: jMfEk/5oF5NybZlrI2/QA3Gs2fYvE38GQQPyTVBgH5gBZqnaH4ij28fegxercTuzqO4AMGK7BvAmxNd6Wf95CYt72uuiRKFCpRto3/8kBh6TNS1SWQCB6U/heccr4hHGvPViCkkidPCAzAjRLe0TIkrHhJt1nQ5u/d6ZI3++e/0=
file: ./dist/perfect-scrollbar.zip
on:
repo: noraesae/perfect-scrollbar
branch: master
tags: true
before_deploy:
- npm run before-deploy

View File

@@ -1,86 +0,0 @@
'use strict';
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('perfect-scrollbar.jquery.json'),
version: grunt.file.readJSON('package.json').version,
banner: '/*! <%= pkg.title || pkg.name %> - v<%= version %>\n' +
'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
clean: {
files: ['min']
},
// Task configuration.
uglify: {
options: {
banner: '<%= banner %>'
},
min: {
files: {
'min/perfect-scrollbar-<%= version %>.min.js': ['src/perfect-scrollbar.js'],
'min/perfect-scrollbar-<%= version %>.with-mousewheel.min.js': [
'src/perfect-scrollbar.js',
'src/jquery.mousewheel.js'
]
}
},
},
jshint: {
gruntfile: {
options: {
jshintrc: '.jshintrc'
},
src: 'Gruntfile.js'
},
src: {
options: {
jshintrc: '.jshintrc'
},
src: 'src/perfect-scrollbar.js'
}
},
csslint: {
strict: {
options: {
csslintrc: '.csslintrc',
import: 2
},
src: ['src/perfect-scrollbar.css']
}
},
cssmin: {
options: {
banner: '<%= banner %>'
},
minify: {
expand: true,
cwd: 'src/',
src: ['perfect-scrollbar.css'],
dest: 'min/',
ext: '-<%= version %>.min.css'
}
}
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-csslint');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('default', 'List commands', function () {
grunt.log.writeln("");
grunt.log.writeln("Run 'grunt lint' to lint the source files");
grunt.log.writeln("Run 'grunt build' to minify the source files");
});
grunt.registerTask('lint', ['jshint', 'csslint']);
grunt.registerTask('build', ['clean', 'uglify', 'cssmin']);
};

439
README.md
View File

@@ -1,120 +1,371 @@
perfect-scrollbar
=================
# `perfect-scrollbar`
Tiny but perfect jQuery scrollbar plugin
Minimalistic but perfect custom scrollbar plugin
Why perfect-scrollbar?
------------------
[![Travis CI](https://travis-ci.org/noraesae/perfect-scrollbar.svg?branch=master)](https://travis-ci.org/noraesae/perfect-scrollbar)
I worked on the personal project recently, and I was trying to find the jQuery scrollbar plugin that's *perfect*. But there was no *perfect* scrollbar plugin. That's why I decided to make one.
If you want information of old versions&lt;0.6.0, please refer to
[an old documentation](https://github.com/noraesae/perfect-scrollbar/tree/0.5.9).
perfect-scrollbar is very tiny but *perfect*(for me, and maybe for the most of developers) jQuery scrollbar plugin.
I hope you love this!
## Why perfect-scrollbar?
Demo: http://noraesae.github.com/perfect-scrollbar/
I was once working on a personal project, and trying to find the jQuery
scrollbar plugin that's *perfect*. But there was no *perfect* one.
That's why I decided to make one.
What means *perfect*?
---------------------
perfect-scrollbar is minimalistic but *perfect* (for me, and maybe for most developers)
scrollbar plugin working with jQuery or vanilla JavaScript as well.
I hope you love it!
## [Demo](http://noraesae.github.com/perfect-scrollbar/)
[It's on the GitHub Pages](http://noraesae.github.com/perfect-scrollbar/).
## What does *perfect* mean?
*perfect* means...
* There should be no css change on any original element.
* The scrollbar should not affect the original design layout.
* The design of the scrollbar should be (nearly) fully customizable.
* If the size of the container or the content changes, the scrollbar size and position should be able to change.
* If the size of the container or the content changes, the scrollbar
size and position should be able to change.
* *New!* It should work with vanilla JavaScript and major tools like
NPM or Browserify.
Then perfect-scrollbar is really *perfect*?
-------------------------------------------
## Then perfect-scrollbar is really *perfect*?
Yes! the only thing that's not *perfect* is my English.
* perfect-scrollbar has some requirements, but doesn't change or add any style on original elements.
* perfect-scrollbar is designed not to have width or height. It's fixed on the right and bottom side of the container.
* You can change nearly all css styles of the scrollbar. The scrollbar design has no dependency on scripts.
* perfect-scrollbar support 'update' function. Whenever you need to update the size or position of the scrollbar, just update.
* Additionally, perfect-scrollbar do use 'scrollTop' and 'scrollLeft', not absolute position or something messy.
* perfect-scrollbar has some requirements, but doesn't change or add
any style on original elements.
* perfect-scrollbar is designed not to have width or height. It's fixed
on the right and bottom side of the container.
* You can change nearly all css styles of the scrollbar. The scrollbar
design has no dependency on scripts.
* perfect-scrollbar supports an 'update' function. Whenever you need
to update the size or position of the scrollbar, just update.
* Additionally, perfect-scrollbar uses 'scrollTop' and 'scrollLeft',
not absolute positioning or something messy.
* perfect-scrollbar supports RTL perfectly on both WebKit and Gecko based browsers.
It's cool, isn't it?
Requirements
------------
## Install
To make this plugin *perfect*, some requirements were not avoidable. But they're all very trivial and there's nothing to worry about.
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`.
```
$ npm install perfect-scrollbar
```
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).
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
have been fixed.
```
$ git clone https://github.com/noraesae/perfect-scrollbar.git
$ cd perfect-scrollbar/src
$ npm install
$ gulp # will lint and build the source code.
```
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)
repository. The plugin is registered as `perfect-scrollbar`.
```
$ bower install perfect-scrollbar
```
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).
## Requirements
To make this plugin *perfect*, some requirements were unavoidable.
But, they're all very trivial and there is nothing to worry about.
The following requirements should meet.
* the container must have a 'position' css style.
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 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.
* the scrollbar-x must have a 'bottom' css style, and the scrollbar-y
must have a 'right' css style.
The requirement below is for perfect-scrollbar &lt;= 0.3.4
## How to use
* there must be the *one* content element(like div) for the container.
Optional parameters
-------------------
First of all, please check if the container element meets the
requirements.
```html
<link rel='stylesheet' href='dist/css/perfect-scrollbar.css' />
<style>
#container {
position: relative;
height: 100%; /* Or whatever you want (eg. 400px) */
}
</style>
```
I would recommend using the plugin with NPM and CommonJS module system
like Browserify.
```javascript
var Ps = require('perfect-scrollbar');
```
Or you can just load the script file as usual.
```html
<script src='dist/js/perfect-scrollbar.js'></script>
```
To initialise the plugin, `Ps.initialize` is used.
```javascript
var container = document.getElementById('container');
Ps.initialize(container);
```
It can be initialised with optional parameters.
```javascript
Ps.initialize(container, {
wheelSpeed: 2,
wheelPropagation: true,
minScrollbarLength: 20
});
```
If the size of your container or content changes, call `update`.
```javascript
Ps.update(container);
```
If you want to destory the scrollbar, use `destroy`.
```javascript
Ps.destroy(container);
```
If you want to scroll to somewhere, just use a `scrollTop`
property and update.
```javascript
container.scrollTop = 0;
Ps.update(container);
```
You can also get information about how to use the plugin
from code in the `examples` directory of the source tree.
## jQuery
As you may already know, perfect-scrollbar was a jQuery plugin.
And it *is* as well. There's a jQuery adaptor and the plugin can
be used in the same way it used to be used before.
I also recommend using NPM and CommonJS here, but it's not mandatory.
```javascript
var $ = require('jquery');
require('perfect-scrollbar/jquery')($);
```
For sure, you can just import a built script.
```html
<script src='dist/js/perfect-scrollbar.jquery.js'></script>
```
After importing it, you can use the plugin in the usual way.
```javascript
$('#container').perfectScrollbar(); // Initialize
$('#container').perfectScrollbar({ ... }); // with options
$('#container').perfectScrollbar('update'); // Update
$('#container').perfectScrollbar('destroy'); // Destroy
```
## RequireJS usage
For RequireJS loader, no need to write shim, simply import two libs:
```javascript
require.config({
paths: {
perfectScrollbarJQuery: '.../perfect-scrollbar.jquery',
perfectScrollbar: '.../perfect-scrollbar',
}
...
})
```
and load `perfectScrollbar` in the initialiser of your app:
```javascript
# for vanilla JS:
window.Ps = require('perfectScrollbar');
# for jQuery:
require('perfectScrollbarJQuery');
```
## AngularJS + RequireJS usage
With the require.config settings above, at the beginning of your app module
definition, you can have following code:
```javascript
define([
'angular',
'perfectScrollbar',
'perfectScrollbarJquery'
],
function (angular) {
var myApp = angular.module('myApp', [])
.run(function() {
window.Ps = require('perfectScrollbar');
require('perfectScrollbarJQuery');
})
return myApp;
});
```
And initialise perfectScrollbar in a controller:
```javascript
# by vanilla JS:
var container = document.getElementById('imgLoader');
Ps.initialize(container);
Ps.update(container);
# or by jQuery:
var imgLoader = $("#imgLoader")
imgLoader.perfectScrollbar();
```
## Optional parameters
perfect-scrollbar supports optional parameters.
### wheelSpeed
The scroll speed applied to mousewheel event.
Default: 10
**Default: 1**
### wheelPropagation
If this option is true, when the scroll reach 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**
How to Use
----------
### minScrollbarLength
When set to an integer value, the thumb part of the scrollbar will not shrink below that number of pixels.
**Default: null**
```html
<style>
#Demo { position: 'relative'; }
</style>
<div id='Demo'>
<div>
...
</div>
</div>
```
When the html document is like above, just use like this:
### maxScrollbarLength
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**
### suppressScrollX
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**
### 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**
### 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**
### stopPropagationOnClick
When set to false, when clicking on a rail, the click event will be allowed to propagate.
**Default: true**
### useSelectionScroll
When set to true, you can scroll the container by selecting text and move the cursor.
**Default: false**
## Events
perfect-scrollbar dispatches custom events.
### ps-scroll-y
This event fires when the y-axis is scrolled in either direction.
### ps-scroll-x
This event fires when the x-axis is scrolled in either direction.
### ps-scroll-up
This event fires when scrolling upwards.
### ps-scroll-down
This event fires when scrolling downwards.
### ps-scroll-left
This event fires when scrolling to the left.
### ps-scroll-right
This event fires when scrolling to the right.
### ps-y-reach-start
This event fires when scrolling reaches the start of the y-axis.
### ps-y-reach-end
This event fires when scrolling reaches the end of the y-axis (useful for infinite scroll).
### ps-x-reach-start
This event fires when scrolling reaches the start of the x-axis.
### ps-x-reach-end
This event fires when scrolling reaches the end of the x-axis.
You can listen to these events either with vanilla JavaScript
```javascript
$('#Demo').perfectScrollbar();
document.addEventListener('ps-scroll-x', function () {
// ...
})
```
With optional parameters:
or with jQuery
```javascript
$("#Demo").perfectScrollbar({
wheelSpeed: 20,
wheelPropagation: true
$(document).on('ps-scroll-x', function () {
// ...
})
```
If the size of your container or content changes:
```javascript
$('#Demo').perfectScrollbar('update');
```
If you want to destory the scrollbar:
```javascript
$('#Demo').perfectScrollbar('destroy');
```
## Contribution
If you want to scroll to somewhere, just use scroll-top css and update.
```javascript
$("#Demo").scrollTop(0);
$("#Demo").perfectScrollbar('update');
```
Very helpful friends
--------------------
perfect-scrollbar supports [jquery-mousewheel](https://github.com/brandonaaron/jquery-mousewheel). If you want to use mousewheel features, please include jquery-mousewheel before using perfect-scrollbar.
If you want to make this plugin's update function more responsive, [jquery-resize](https://github.com/cowboy/jquery-resize) can be helpful.
Contribution
------------
#### Please read [Contributing](https://github.com/noraesae/perfect-scrollbar/wiki/Contributing) in the wiki before making any contibution.
#### Please read [Contributing](https://github.com/noraesae/perfect-scrollbar/wiki/Contributing) in the wiki before making any contribution.
I *really* welcome contributions! Please feel free to fork and issue pull requests when...
@@ -123,34 +374,32 @@ I *really* welcome contributions! Please feel free to fork and issue pull reques
* 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)
For IE problems, please refer to [IE Support](https://github.com/noraesae/perfect-scrollbar#ie-support).
IE Support
----------
## IE Support
This plugin supports old IE browsers in the **minimum** range. The plugin is tested in IEs >= IE6 and works(not well, but works).
The plugin would work in IEs >= IE9 (not well, though).
**But the project will not accept the patches to fix IE problems in IE 6/7/8.**
**The patches to fix problems in IE<=8 won't be accepted.**
From jQuery 2.0, jQuery also will not support IE 6/7/8. I also think that supporting old browsers really breaks the web development conventions.
When old IEs should be supported, please fork the project and
make patches personally.
When old IEs should be supported, please fork the project and make patches personally.
## Helpdesk
License
-------
If you have any idea to improve this project or any problem
using this, please feel free to upload an
[issue](https://github.com/noraesae/perfect-scrollbar/issues).
The MIT License (MIT) Copyright (c) 2012 HyeonJe Jun.
For common problems there is a
[FAQ](https://github.com/noraesae/perfect-scrollbar/wiki/FAQ) wiki page. Please check the page before uploading an issue.
## License
The MIT License (MIT) Copyright (c) 2015 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.
**It means, you can freely fork and modify this project for commercial or non-comercial use!**
Helpdesk
--------
If you have any idea to improve this project or any problems using this, please feel free to contact me.
Email: noraesae@yuiazu.net

View File

@@ -0,0 +1,41 @@
<!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>
h1 { text-align: center; }
.container { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.container .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
</style>
<style>
/* to make scrollbars always visible */
.always-visible.ps-container > .ps-scrollbar-x-rail,
.always-visible.ps-container > .ps-scrollbar-y-rail {
opacity: 0.6;
}
</style>
</head>
<body>
<h1>Default</h1>
<div class="container">
<div class="content">
</div>
</div>
<h1>Always visible</h1>
<div class="container always-visible">
<div class="content">
</div>
</div>
<script>
window.onload = function () {
[].forEach.call(document.querySelectorAll('.container'), function (el) {
Ps.initialize(el);
});
};
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

89
examples/events.html Normal file
View File

@@ -0,0 +1,89 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
p {
text-align: center;
}
.container {
position: relative;
margin: 0px auto;
padding: 0px;
width: 600px;
height: 400px;
overflow: auto;
}
.container .content {
background-image: url('./azusa.jpg');
width: 1280px;
height: 720px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">
</div>
</div>
<p><strong>Axis</strong> <span id="axis">&hellip;</span></p>
<p><strong>Direction</strong> <span id="direction">&hellip;</span></p>
<p><strong>Start / End</strong> <span id="start-end">(scroll to the start or end of an axis)</span></p>
<script>
var container = document.querySelector('.container')
, axis = document.getElementById('axis')
, direction = document.getElementById('direction')
, startEnd = document.getElementById('start-end');
Ps.initialize(container);
document.addEventListener('ps-scroll-y', function () {
axis.innerHTML = 'Y Axis';
});
document.addEventListener('ps-scroll-x', function () {
axis.innerHTML = 'X Axis';
});
document.addEventListener('ps-scroll-up', function () {
direction.innerHTML = 'up';
});
document.addEventListener('ps-scroll-down', function () {
direction.innerHTML = 'down';
});
document.addEventListener('ps-scroll-left', function () {
direction.innerHTML = 'left';
});
document.addEventListener('ps-scroll-right', function () {
direction.innerHTML = 'right';
});
document.addEventListener('ps-y-reach-start', function () {
startEnd.innerHTML = 'Reached start of <em>Y-Axis</em>';
});
document.addEventListener('ps-y-reach-end', function () {
startEnd.innerHTML = 'Reached end of <em>Y-Axis</em>';
});
document.addEventListener('ps-x-reach-start', function () {
startEnd.innerHTML = 'Reached start of <em>X-Axis</em>';
});
document.addEventListener('ps-x-reach-end', function () {
startEnd.innerHTML = 'Reached end of <em>X-Axis</em>'
});
</script>
</body>
</html>

View File

@@ -0,0 +1,20 @@
<!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">
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px;}
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
</head>
<body>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
</body>
</html>

22
examples/iframe.html Normal file
View File

@@ -0,0 +1,22 @@
<!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>
#iframe { width: 100%; min-height: 450px; border: 0; }
html { direction: rtl; }
</style>
</head>
<body>
<iframe src="iframe-content.html" id="iframe"></iframe>
<script>
var iframe = document.querySelector('#iframe');
iframe.onload = function () {
Ps.initialize(iframe.contentDocument.querySelector('#Default'))
};
</script>
</body>
</html>

40
examples/jquery.html Normal file
View File

@@ -0,0 +1,40 @@
<!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="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../dist/js/perfect-scrollbar.jquery.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
</head>
<body>
<h1 style="text-align:center">Default; wheelSpeed:1</h1>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<h1 style="text-align:center">Fast: wheelSpeed:10</h1>
<div id="FastWheelSpeed" class="contentHolder">
<div class="content">
</div>
</div>
<h1 style="text-align:center">Slow: wheelSpeed:0.1</h1>
<div id="SlowWheelSpeed" class="contentHolder">
<div class="content">
</div>
</div>
<script>
$(document).ready(function ($) {
$('#Default').perfectScrollbar();
$('#FastWheelSpeed').perfectScrollbar({wheelSpeed: 10});
$('#SlowWheelSpeed').perfectScrollbar({wheelSpeed: 0.1});
});
</script>
</body>
</html>

View File

@@ -1,29 +1,40 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="../src/jquery.mousewheel.js"></script>
<script src="../src/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; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
});
</script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
</head>
<body>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<p style='text-align: center'>
Width <input type='text' id='width' value='600'>
Height <input type='text' id='height' value='400'>
<button onclick='updateSize()'>Change!</button>
</p>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
};
var updateSize = function () {
var width = parseInt($('#width').value, 10);
var height = parseInt($('#height').value, 10);
var container = $('#Default');
container.style.width = width + 'px';
container.style.height = height + 'px';
Ps.update(document.querySelector('#Default'));
};
</script>
</body>
</html>

View File

@@ -0,0 +1,33 @@
<!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: 640px; height: 360px; overflow: auto; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 12800px; height: 7200px; }
.spacer { text-align:center }
</style>
</head>
<body>
<h1 style="text-align:center">No minimum</h1>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<h1 style="text-align:center">100px minimum</h1>
<div id="LongThumb" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#LongThumb'), {minScrollbarLength: 100});
};
</script>
</body>
</html>

View File

@@ -0,0 +1,40 @@
<!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; }
.spacer { text-align:center }
h2 { text-align: center; }
</style>
</head>
<body>
<h2>Default</h2>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<h2>suppressScrollX: true</h2>
<div id="SuppressScrollX" class="contentHolder">
<div class="content">
</div>
</div>
<h2>suppressScrollY: true</h2>
<div id="SuppressScrollY" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#SuppressScrollX'), {suppressScrollX: true});
Ps.initialize($('#SuppressScrollY'), {suppressScrollY: true});
};
</script>
</body>
</html>

View File

@@ -0,0 +1,40 @@
<!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: 640px; height: 360px; overflow: auto; }
.contentHolder .content-x { background-image: url('./azusa.jpg'); width: 1920px; height: 360px; }
.contentHolder .content-y { background-image: url('./azusa.jpg'); width: 640px; height: 1080px; }
.spacer { text-align:center; }
</style>
</head>
<body>
<h1 style="text-align:center">Default.</h1>
<div id="Default" class="contentHolder">
<div class="content-x">
</div>
</div>
<h1 style="text-align:center">Can scroll X axis with Y axis wheel.</h1>
<div id="CanScrollWithYAxis" class="contentHolder">
<div class="content-x">
</div>
</div>
<h1 style="text-align:center">Can scroll Y axis with X axis wheel.</h1>
<div id="CanScrollWithXAxis" class="contentHolder">
<div class="content-y">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#CanScrollWithYAxis'), {useBothWheelAxes: true});
Ps.initialize($('#CanScrollWithXAxis'), {useBothWheelAxes: true});
};
</script>
</body>
</html>

View File

@@ -1,24 +1,15 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>perfect-scrollbar example - use wheelPropagation to control propagation of scrolling at extremities</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="../src/jquery.mousewheel.js"></script>
<script src="../src/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; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#NoWheelPropagation').perfectScrollbar({wheelPropagation:true});
});
</script>
<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; }
.spacer { text-align:center }
</style>
</head>
<body>
<h1 style="text-align:center">Default; wheelPropagation:false</h1>
@@ -27,7 +18,7 @@
</div>
</div>
<h1 style="text-align:center">wheelPropagation:true</h1>
<div id="NoWheelPropagation" class="contentHolder">
<div id="WheelPropagation" class="contentHolder">
<div class="content">
</div>
</div>
@@ -35,6 +26,13 @@
Note<br>that<br>there<br>is<br>plenty<br>of<br>text<br>after<br>the<br>image<br>to<br>ensure<br>that<br>it<br>is<br>possible<br>to<br>down<br>
after<br>the<br>bottom<br>of<br>the<br>image<br>has<br>been<br>reached<br>to<br>enable<br>the<br>wheel<br>propagation<br>to<br>be<br>tested<br>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#WheelPropagation'), {wheelPropagation: true});
};
</script>
</body>
</html>

View File

@@ -1,42 +1,40 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>perfect-scrollbar example - use wheelSpeed to change speed of scrolling</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="../src/jquery.mousewheel.js"></script>
<script src="../src/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; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#FastWheelSpeed').perfectScrollbar({wheelSpeed:100});
$('#SlowWheelSpeed').perfectScrollbar({wheelSpeed:1});
});
</script>
<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; }
.spacer { text-align:center }
</style>
</head>
<body>
<h1 style="text-align:center">Default; wheelSpeed:10</h1>
<h1 style="text-align:center">Default; wheelSpeed:1</h1>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<h1 style="text-align:center">Fast: wheelSpeed:100</h1>
<h1 style="text-align:center">Fast: wheelSpeed:10</h1>
<div id="FastWheelSpeed" class="contentHolder">
<div class="content">
</div>
</div>
<h1 style="text-align:center">Slow: wheelSpeed:1</h1>
<h1 style="text-align:center">Slow: wheelSpeed:0.1</h1>
<div id="SlowWheelSpeed" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#FastWheelSpeed'), {wheelSpeed: 10});
Ps.initialize($('#SlowWheelSpeed'), {wheelSpeed: 0.1});
};
</script>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<!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>
#test {
border: 1px solid gray;
max-height: 300px;
width: 400px;
overflow: auto;
position: relative;
}
#test .element {
margin: 1px;
background-color: #cec;
height: 44px;
line-height: 44px;
}
</style>
</head>
<body>
<div id="test" class="wrapper">
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
<div class='element'>Hello! Click <a href='#'>here</a> to remove this!</div>
</div>
<script type="text/javascript">
var $ = document.querySelector.bind(document);
window.onload = function () {
var test = $('#test');
Ps.initialize(test);
[].forEach.call(test.querySelectorAll('.element'), function (el) {
el.querySelector('a').addEventListener('click', function () {
el.parentNode.removeChild(el);
Ps.update(test);
});
});
};
</script>
</body>
</html>

28
examples/rtl.html Normal file
View File

@@ -0,0 +1,28 @@
<!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; }
.spacer { text-align:center }
html { direction: rtl; }
</style>
</head>
<body>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
};
</script>
</body>
</html>

View File

@@ -0,0 +1,37 @@
<!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; }
.spacer { text-align:center }
/* Change the alignment of scrollbars */
/* Recommended: You can just modify the CSS file directly. */
.ps-container .ps-scrollbar-x-rail {
top: 3px;
bottom: auto; /* If using `top`, there shouldn't be a `bottom`. */
}
.ps-container .ps-scrollbar-y-rail {
left: 3px;
right: auto; /* If using `left`, there shouldn't be a `right`. */
}
</style>
</head>
<body>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
};
</script>
</body>
</html>

View File

@@ -0,0 +1,45 @@
<!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>
h1 { text-align: center; }
.container { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.container .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.large-margin .ps-scrollbar-x-rail {
margin: 0 25%;
opacity: 0.5;
background-color: #eee;
}
.large-margin .ps-scrollbar-y-rail {
margin: 100px 0;
opacity: 0.5;
background-color: #eee;
}
</style>
</head>
<body>
<h1>Default</h1>
<div class="container">
<div class="content">
</div>
</div>
<h1>Margins</h1>
<div class="container large-margin">
<div class="content">
</div>
</div>
<script>
window.onload = function () {
[].forEach.call(document.querySelectorAll('.container'), function (el) {
Ps.initialize(el);
});
};
</script>
</body>
</html>

View File

@@ -0,0 +1,83 @@
<!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>
#table {
font-size: 20px;
}
#table thead, #table tbody, #table tr {
display: block;
width: 600px;
border-spacing: 0;
border-collapse: collapse;
}
#table tbody {
height: 100px;
overflow-y: auto;
overflow-x:hidden;
position: relative;
}
#table tbody td, #table thead th {
display: block;
border: 1px solid black;
width: 200px;
float: left;
box-sizing: border-box;
}
</style>
</head>
<body>
<div id="table" class="wrapper">
<table id='table'>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Occupation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alex</td>
<td>20</td>
<td>Student</td>
</tr>
<tr>
<td>Paul</td>
<td>23</td>
<td>Engineer</td>
</tr>
<tr>
<td>Chris</td>
<td>19</td>
<td>Human being</td>
</tr>
<tr>
<td>Alex</td>
<td>20</td>
<td>Student</td>
</tr>
<tr>
<td>Paul</td>
<td>23</td>
<td>Engineer</td>
</tr>
<tr>
<td>Chris</td>
<td>19</td>
<td>Human being</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#table tbody'));
};
</script>
</body>
</html>

View File

@@ -1,45 +1,59 @@
<!DOCTYPE HTML>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Ul-content</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="../src/jquery.mousewheel.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
#description {
border: 1px solid gray;
height:150px;
width: 400px;
overflow: hidden;
position: absolute;
overflow: auto;
position: relative;
}
</style>
<script type="text/javascript">
$(document).ready(function ($) {
$('#description').perfectScrollbar({
wheelSpeed: 20,
wheelPropagation: false
});
});
</script>
</head>
<body>
<div id="description" class="wrapper">
<div>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
</div>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
</div>
<button id='redraw'>Redraw</button>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#description'), {
useSelectionScroll: true
});
};
$('#redraw').addEventListener('click', function () {
var oldHtml = $('#description').innerHTML;
$('#description').innerHTML = '';
setTimeout(function () {
$('#description').innerHTML = '' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>' +
'<p>The command takes options applicable</p>';
Ps.update($('#description'));
}, 500);
});
</script>
</body>
</html>

126
gulpfile.js Normal file
View File

@@ -0,0 +1,126 @@
'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 version = '/* perfect-scrollbar v' + require('./package').version + ' */\n';
gulp.task('lint', function () {
return gulp.src(['./src/**/*.js', './gulpfile.js'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failOnError());
});
gulp.task('clean:js', function () {
return del(['./dist/js/*.js']);
});
gulp.task('clean:js:min', function () {
return del(['./dist/js/min/*.js']);
});
var jsEntries = [
'./src/js/adaptor/global.js',
'./src/js/adaptor/jquery.js'
];
gulp.task('js', ['clean:js'], function () {
var tasks = jsEntries.map(function (src) {
return browserify([src]).bundle()
.pipe(source(path.basename(src)))
.pipe(buffer())
.pipe(insert.prepend(version))
.pipe(rename(function (path) {
if (path.basename === 'global') {
path.basename = 'perfect-scrollbar';
} else {
path.basename = 'perfect-scrollbar.' + path.basename;
}
}))
.pipe(gulp.dest('./dist/js'))
.pipe(connect.reload());
});
return stream.merge.apply(null, tasks);
});
gulp.task('js:min', ['clean:js:min'], function () {
var tasks = jsEntries.map(function (src) {
return browserify([src]).bundle()
.pipe(source(path.basename(src)))
.pipe(buffer())
.pipe(uglify())
.pipe(insert.prepend(version))
.pipe(rename(function (path) {
if (path.basename === 'global') {
path.basename = 'perfect-scrollbar.min';
} else {
path.basename = 'perfect-scrollbar.' + path.basename + '.min';
}
}))
.pipe(gulp.dest('./dist/js/min'))
.pipe(connect.reload());
});
return stream.merge.apply(null, tasks);
});
gulp.task('clean:css', function () {
return del(['./dist/css/perfect-scrollbar.css']);
});
gulp.task('clean:css:min', function () {
return del(['./dist/css/perfect-scrollbar.min.css']);
});
gulp.task('css', ['clean:css'], function () {
return gulp.src('./src/css/main.scss')
.pipe(sass())
.pipe(insert.prepend(version))
.pipe(rename('perfect-scrollbar.css'))
.pipe(gulp.dest('./dist/css'))
.pipe(connect.reload());
});
gulp.task('css:min', ['clean:css:min'], function () {
return gulp.src('./src/css/main.scss')
.pipe(sass({outputStyle: 'compressed'}))
.pipe(insert.prepend(version))
.pipe(rename('perfect-scrollbar.min.css'))
.pipe(gulp.dest('./dist/css'));
});
gulp.task('build', ['js', 'js:min', 'css', 'css:min']);
gulp.task('connect', ['build'], function () {
connect.server({
root: __dirname,
livereload: true
});
});
gulp.task('watch', function () {
gulp.watch(['src/js/**/*'], ['js']);
gulp.watch(['src/css/**/*'], ['css']);
});
gulp.task('serve', ['connect', 'watch']);
gulp.task('compress', function () {
return gulp.src('./dist/**')
.pipe(zip('perfect-scrollbar.zip'))
.pipe(gulp.dest('./dist'));
});
gulp.task('default', ['lint', 'build']);

6
index.js Normal file
View File

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

6
jquery.js vendored Normal file
View File

@@ -0,0 +1,6 @@
/* 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,5 +0,0 @@
/*! perfect-scrollbar - v0.4.1
* http://noraesae.github.com/perfect-scrollbar/
* Copyright (c) 2013 HyeonJe Jun; Licensed MIT */
.ps-container .ps-scrollbar-x{position:absolute;bottom:3px;height:8px;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;opacity:0;filter:alpha(opacity=0);-o-transition:opacity .2s linear;-webkit-transition:opacity.2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.ps-container.ie6 .ps-scrollbar-x{font-size:0}.ps-container:hover .ps-scrollbar-x,.ps-container.hover .ps-scrollbar-x{opacity:.6;filter:alpha(opacity=60)}.ps-container .ps-scrollbar-x:hover,.ps-container .ps-scrollbar-x.hover{opacity:.9;filter:alpha(opacity=90);cursor:default}.ps-container .ps-scrollbar-x.in-scrolling{opacity:.9;filter:alpha(opacity=90)}.ps-container .ps-scrollbar-y{position:absolute;right:3px;width:8px;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;opacity:0;filter:alpha(opacity=0);-o-transition:opacity .2s linear;-webkit-transition:opacity.2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.ps-container.ie .ps-scrollbar-y{font-size:0}.ps-container:hover .ps-scrollbar-y,.ps-container.hover .ps-scrollbar-y{opacity:.6;filter:alpha(opacity=60)}.ps-container .ps-scrollbar-y:hover,.ps-container .ps-scrollbar-y.hover{opacity:.9;filter:alpha(opacity=90);cursor:default}.ps-container .ps-scrollbar-y.in-scrolling{opacity:.9;filter:alpha(opacity=90)}

View File

@@ -1,4 +0,0 @@
/*! perfect-scrollbar - v0.4.1
* http://noraesae.github.com/perfect-scrollbar/
* Copyright (c) 2013 HyeonJe Jun; Licensed MIT */
(function(e){var t={wheelSpeed:10,wheelPropagation:!1};e.fn.perfectScrollbar=function(o,r){return this.each(function(){var l=e.extend(!0,{},t);if("object"==typeof o?e.extend(!0,l,o):r=o,"update"===r)return e(this).data("perfect-scrollbar-update")&&e(this).data("perfect-scrollbar-update")(),e(this);if("destroy"===r)return e(this).data("perfect-scrollbar-destroy")&&e(this).data("perfect-scrollbar-destroy")(),e(this);if(e(this).data("perfect-scrollbar"))return e(this).data("perfect-scrollbar");var n,s,a,c,i,p,f,u,d=e(this).addClass("ps-container"),h=e("<div class='ps-scrollbar-x'></div>").appendTo(d),g=e("<div class='ps-scrollbar-y'></div>").appendTo(d),v=parseInt(h.css("bottom"),10),b=parseInt(g.css("right"),10),m=function(){var e=parseInt(u*c/s,10);d.scrollTop(e),h.css({bottom:v-e})},w=function(){var e=parseInt(p*a/n,10);d.scrollLeft(e),g.css({right:b-e})},T=function(){h.css({left:p+d.scrollLeft(),bottom:v-d.scrollTop(),width:i}),g.css({top:u+d.scrollTop(),right:b-d.scrollLeft(),height:f})},C=function(){n=d.width(),s=d.height(),a=d.prop("scrollWidth"),c=d.prop("scrollHeight"),a>n?(i=parseInt(n*n/a,10),p=parseInt(d.scrollLeft()*n/a,10)):(i=0,p=0,d.scrollLeft(0)),c>s?(f=parseInt(s*s/c,10),u=parseInt(d.scrollTop()*s/c,10)):(f=0,u=0,d.scrollTop(0)),u>=s-f&&(u=s-f),p>=n-i&&(p=n-i),T()},I=function(e,t){var o=e+t,r=n-i;p=0>o?0:o>r?r:o,h.css({left:p+d.scrollLeft()})},L=function(e,t){var o=e+t,r=s-f;u=0>o?0:o>r?r:o,g.css({top:u+d.scrollTop()})},y=function(){var t,o;h.bind("mousedown.perfect-scroll",function(e){o=e.pageX,t=h.position().left,h.addClass("in-scrolling"),e.stopPropagation(),e.preventDefault()}),e(document).bind("mousemove.perfect-scroll",function(e){h.hasClass("in-scrolling")&&(w(),I(t,e.pageX-o),e.stopPropagation(),e.preventDefault())}),e(document).bind("mouseup.perfect-scroll",function(){h.hasClass("in-scrolling")&&h.removeClass("in-scrolling")})},P=function(){var t,o;g.bind("mousedown.perfect-scroll",function(e){o=e.pageY,t=g.position().top,g.addClass("in-scrolling"),e.stopPropagation(),e.preventDefault()}),e(document).bind("mousemove.perfect-scroll",function(e){g.hasClass("in-scrolling")&&(m(),L(t,e.pageY-o),e.stopPropagation(),e.preventDefault())}),e(document).bind("mouseup.perfect-scroll",function(){g.hasClass("in-scrolling")&&g.removeClass("in-scrolling")})},D=function(){var e=function(e,t){var o=d.scrollTop();if(0===o&&t>0&&0===e)return!l.wheelPropagation;if(o>=c-s&&0>t&&0===e)return!l.wheelPropagation;var r=d.scrollLeft();return 0===r&&0>e&&0===t?!l.wheelPropagation:r>=a-n&&e>0&&0===t?!l.wheelPropagation:!0};d.bind("mousewheel.perfect-scroll",function(t,o,r,n){d.scrollTop(d.scrollTop()-n*l.wheelSpeed),d.scrollLeft(d.scrollLeft()+r*l.wheelSpeed),C(),e(r,n)&&t.preventDefault()})},X=function(){var t=function(e,t){d.scrollTop(d.scrollTop()-t),d.scrollLeft(d.scrollLeft()-e),C()},o={},r=0,l={},n=null,s=!1;e(window).bind("touchstart.perfect-scroll",function(){s=!0}),e(window).bind("touchend.perfect-scroll",function(){s=!1}),d.bind("touchstart.perfect-scroll",function(e){var t=e.originalEvent.targetTouches[0];o.pageX=t.pageX,o.pageY=t.pageY,r=(new Date).getTime(),null!==n&&clearInterval(n),e.stopPropagation()}),d.bind("touchmove.perfect-scroll",function(e){if(!s&&1===e.originalEvent.targetTouches.length){var n=e.originalEvent.targetTouches[0],a={};a.pageX=n.pageX,a.pageY=n.pageY;var c=a.pageX-o.pageX,i=a.pageY-o.pageY;t(c,i),o=a;var p=(new Date).getTime();l.x=c/(p-r),l.y=i/(p-r),r=p,e.preventDefault()}}),d.bind("touchend.perfect-scroll",function(){n=setInterval(function(){return.01>Math.abs(l.x)&&.01>Math.abs(l.y)?(clearInterval(n),void 0):(t(30*l.x,30*l.y),l.x*=.8,l.y*=.8,void 0)},10)})},Y=function(){h.remove(),g.remove(),d.unbind(".perfect-scroll"),e(window).unbind(".perfect-scroll"),d.data("perfect-scrollbar",null),d.data("perfect-scrollbar-update",null),d.data("perfect-scrollbar-destroy",null)},x=function(t){d.addClass("ie").addClass("ie"+t);var o=function(){var t=function(){e(this).addClass("hover")},o=function(){e(this).removeClass("hover")};d.bind("mouseenter.perfect-scroll",t).bind("mouseleave.perfect-scroll",o),h.bind("mouseenter.perfect-scroll",t).bind("mouseleave.perfect-scroll",o),g.bind("mouseenter.perfect-scroll",t).bind("mouseleave.perfect-scroll",o)},r=function(){T=function(){h.css({left:p+d.scrollLeft(),bottom:v,width:i}),g.css({top:u+d.scrollTop(),right:b,height:f}),h.hide().show(),g.hide().show()},m=function(){var e=parseInt(u*c/s,10);d.scrollTop(e),h.css({bottom:v}),h.hide().show()},w=function(){var e=parseInt(p*a/n,10);d.scrollLeft(e),g.hide().show()}};6===t&&(o(),r())},S=/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent),A=function(){var e=navigator.userAgent.toLowerCase().match(/(msie) ([\w.]+)/);e&&"msie"===e[1]&&x(parseInt(e[2],10)),C(),y(),P(),S&&X(),d.mousewheel&&D(),d.data("perfect-scrollbar",d),d.data("perfect-scrollbar-update",C),d.data("perfect-scrollbar-destroy",Y)};return A(),d})}})(jQuery);

File diff suppressed because one or more lines are too long

View File

@@ -1,15 +1,50 @@
{
"name": "perfect-scrollbar",
"version": "0.4.1",
"version": "0.6.8",
"description": "Minimalistic but perfect custom scrollbar plugin",
"author": "Hyunje Alex Jun <me@noraesae.net>",
"contributors": [
{
"name": "Hyunje Alex Jun",
"email": "me@noraesae.net"
}
],
"main": "./index.js",
"repository": {
"type": "git",
"url": "https://github.com/noraesae/perfect-scrollbar"
},
"bugs": {
"url": "https://github.com/noraesae/perfect-scrollbar/issues"
},
"keywords": [
"jquery-plugin",
"frontend",
"scroll",
"scrollbar"
],
"engines": {
"node": ">= 0.8.0"
"node": ">= 0.12.0"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-uglify": "~0.1.1",
"grunt-contrib-cssmin": "~0.6.1",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-clean": "~0.4.1"
}
"browserify": "^11.2.0",
"del": "^2.0.2",
"event-stream": "^3.3.1",
"gulp": "^3.9.0",
"gulp-connect": "^2.2.0",
"gulp-eslint": "^1.0.0",
"gulp-insert": "^0.5.0",
"gulp-rename": "^1.2.2",
"gulp-sass": "^2.0.4",
"gulp-uglify": "^1.4.1",
"gulp-zip": "^3.0.2",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"test": "gulp",
"before-deploy": "gulp && gulp compress",
"release": "rm -rf dist && gulp && npm publish"
},
"license": "MIT"
}

View File

@@ -1,37 +0,0 @@
{
"name": "perfect-scrollbar",
"title": "perfect-scrollbar",
"description": "Tiny but perfect jquery scrollbar plugin.",
"version": "0.4.1",
"author": {
"name": "HyeonJe Jun",
"email": "noraesae@yuiazu.net",
"url": "https://github.com/noraesae/"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/noraesae/perfect-scrollbar#license"
}
],
"dependencies": {
"jquery": ">=1.8"
},
"keywords": [
"ui",
"scroll",
"scrollbar"
],
"homepage": "http://noraesae.github.com/perfect-scrollbar/",
"docs": "https://github.com/noraesae/perfect-scrollbar/",
"download": "http://noraesae.github.com/perfect-scrollbar/",
"demo": "http://noraesae.github.com/perfect-scrollbar/",
"bugs": "https://github.com/noraesae/perfect-scrollbar/issues/",
"maintainers": [
{
"name": "HyeonJe Jun",
"email": "noraesae@yuiazu.net",
"url": "https://github.com/noraesae/"
}
]
}

123
src/css/main.scss Normal file
View File

@@ -0,0 +1,123 @@
// 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;
}
}
}
}

View File

@@ -1,84 +0,0 @@
/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
* Version: 3.0.6
*
* Requires: 1.2.2+
*/
(function($) {
var types = ['DOMMouseScroll', 'mousewheel'];
if ($.event.fixHooks) {
for ( var i=types.length; i; ) {
$.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
for ( var i=types.length; i; ) {
this.addEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i=types.length; i; ) {
this.removeEventListener( types[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
unmousewheel: function(fn) {
return this.unbind("mousewheel", fn);
}
});
function handler(event) {
var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
// Old school scrollwheel delta
if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
// New school multidimensional scroll (touchpads) deltas
deltaY = delta;
// Gecko
if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
deltaY = 0;
deltaX = -1*delta;
}
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
})(jQuery);

17
src/js/adaptor/global.js Normal file
View File

@@ -0,0 +1,17 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var ps = require('../main');
if (typeof define === 'function' && define.amd) {
// AMD
define(ps);
} else {
// Add to a global object.
window.PerfectScrollbar = ps;
if (typeof window.Ps === 'undefined') {
window.Ps = ps;
}
}

46
src/js/adaptor/jquery.js vendored Normal file
View File

@@ -0,0 +1,46 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var ps = require('../main')
, psInstances = require('../plugin/instances');
function mountJQuery(jQuery) {
jQuery.fn.perfectScrollbar = function (settingOrCommand) {
return this.each(function () {
if (typeof settingOrCommand === 'object' ||
typeof settingOrCommand === 'undefined') {
// If it's an object or none, initialize.
var settings = settingOrCommand;
if (!psInstances.get(this)) {
ps.initialize(this, settings);
}
} else {
// Unless, it may be a command.
var command = settingOrCommand;
if (command === 'update') {
ps.update(this);
} else if (command === 'destroy') {
ps.destroy(this);
}
}
return jQuery(this);
});
};
}
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], mountJQuery);
} else {
var jq = window.jQuery ? window.jQuery : window.$;
if (typeof jq !== 'undefined') {
mountJQuery(jq);
}
}
module.exports = mountJQuery;

45
src/js/lib/class.js Normal file
View File

@@ -0,0 +1,45 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
function oldAdd(element, className) {
var classes = element.className.split(' ');
if (classes.indexOf(className) < 0) {
classes.push(className);
}
element.className = classes.join(' ');
}
function oldRemove(element, className) {
var classes = element.className.split(' ');
var idx = classes.indexOf(className);
if (idx >= 0) {
classes.splice(idx, 1);
}
element.className = classes.join(' ');
}
exports.add = function (element, className) {
if (element.classList) {
element.classList.add(className);
} else {
oldAdd(element, className);
}
};
exports.remove = function (element, className) {
if (element.classList) {
element.classList.remove(className);
} else {
oldRemove(element, className);
}
};
exports.list = function (element) {
if (element.classList) {
return Array.prototype.slice.apply(element.classList);
} else {
return element.className.split(' ');
}
};

87
src/js/lib/dom.js Normal file
View File

@@ -0,0 +1,87 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var DOM = {};
DOM.e = function (tagName, className) {
var element = document.createElement(tagName);
element.className = className;
return element;
};
DOM.appendTo = function (child, parent) {
parent.appendChild(child);
return child;
};
function cssGet(element, styleName) {
return window.getComputedStyle(element)[styleName];
}
function cssSet(element, styleName, styleValue) {
if (typeof styleValue === 'number') {
styleValue = styleValue.toString() + 'px';
}
element.style[styleName] = styleValue;
return element;
}
function cssMultiSet(element, obj) {
for (var key in obj) {
var val = obj[key];
if (typeof val === 'number') {
val = val.toString() + 'px';
}
element.style[key] = val;
}
return element;
}
DOM.css = function (element, styleNameOrObject, styleValue) {
if (typeof styleNameOrObject === 'object') {
// multiple set with object
return cssMultiSet(element, styleNameOrObject);
} else {
if (typeof styleValue === 'undefined') {
return cssGet(element, styleNameOrObject);
} else {
return cssSet(element, styleNameOrObject, styleValue);
}
}
};
DOM.matches = function (element, query) {
if (typeof element.matches !== 'undefined') {
return element.matches(query);
} else {
if (typeof element.matchesSelector !== 'undefined') {
return element.matchesSelector(query);
} else if (typeof element.webkitMatchesSelector !== 'undefined') {
return element.webkitMatchesSelector(query);
} else if (typeof element.mozMatchesSelector !== 'undefined') {
return element.mozMatchesSelector(query);
} else if (typeof element.msMatchesSelector !== 'undefined') {
return element.msMatchesSelector(query);
}
}
};
DOM.remove = function (element) {
if (typeof element.remove !== 'undefined') {
element.remove();
} else {
if (element.parentNode) {
element.parentNode.removeChild(element);
}
}
};
DOM.queryChildren = function (element, selector) {
return Array.prototype.filter.call(element.childNodes, function (child) {
return DOM.matches(child, selector);
});
};
module.exports = DOM;

View File

@@ -0,0 +1,74 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var EventElement = function (element) {
this.element = element;
this.events = {};
};
EventElement.prototype.bind = function (eventName, handler) {
if (typeof this.events[eventName] === 'undefined') {
this.events[eventName] = [];
}
this.events[eventName].push(handler);
this.element.addEventListener(eventName, handler, false);
};
EventElement.prototype.unbind = function (eventName, handler) {
var isHandlerProvided = (typeof handler !== 'undefined');
this.events[eventName] = this.events[eventName].filter(function (hdlr) {
if (isHandlerProvided && hdlr !== handler) {
return true;
}
this.element.removeEventListener(eventName, hdlr, false);
return false;
}, this);
};
EventElement.prototype.unbindAll = function () {
for (var name in this.events) {
this.unbind(name);
}
};
var EventManager = function () {
this.eventElements = [];
};
EventManager.prototype.eventElement = function (element) {
var ee = this.eventElements.filter(function (eventElement) {
return eventElement.element === element;
})[0];
if (typeof ee === 'undefined') {
ee = new EventElement(element);
this.eventElements.push(ee);
}
return ee;
};
EventManager.prototype.bind = function (element, eventName, handler) {
this.eventElement(element).bind(eventName, handler);
};
EventManager.prototype.unbind = function (element, eventName, handler) {
this.eventElement(element).unbind(eventName, handler);
};
EventManager.prototype.unbindAll = function () {
for (var i = 0; i < this.eventElements.length; i++) {
this.eventElements[i].unbindAll();
}
};
EventManager.prototype.once = function (element, eventName, handler) {
var ee = this.eventElement(element);
var onceHandler = function (e) {
ee.unbind(eventName, onceHandler);
handler(e);
};
ee.bind(eventName, onceHandler);
};
module.exports = EventManager;

16
src/js/lib/guid.js Normal file
View File

@@ -0,0 +1,16 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
module.exports = (function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return function () {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
})();

84
src/js/lib/helper.js Normal file
View File

@@ -0,0 +1,84 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var cls = require('./class')
, d = require('./dom');
exports.toInt = function (x) {
return parseInt(x, 10) || 0;
};
exports.clone = function (obj) {
if (obj === null) {
return null;
} else if (typeof obj === 'object') {
var result = {};
for (var key in obj) {
result[key] = this.clone(obj[key]);
}
return result;
} else {
return obj;
}
};
exports.extend = function (original, source) {
var result = this.clone(original);
for (var key in source) {
result[key] = this.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]");
};
exports.removePsClasses = function (element) {
var clsList = cls.list(element);
for (var i = 0; i < clsList.length; i++) {
var className = clsList[i];
if (className.indexOf('ps-') === 0) {
cls.remove(element, className);
}
}
};
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'));
};
exports.startScrolling = function (element, axis) {
cls.add(element, 'ps-in-scrolling');
if (typeof axis !== 'undefined') {
cls.add(element, 'ps-' + axis);
} else {
cls.add(element, 'ps-x');
cls.add(element, 'ps-y');
}
};
exports.stopScrolling = function (element, axis) {
cls.remove(element, 'ps-in-scrolling');
if (typeof axis !== 'undefined') {
cls.remove(element, 'ps-' + axis);
} else {
cls.remove(element, 'ps-x');
cls.remove(element, 'ps-y');
}
};
exports.env = {
isWebKit: 'WebkitAppearance' in document.documentElement.style,
supportsTouch: (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch),
supportsIePointer: window.navigator.msMaxTouchPoints !== null
};

14
src/js/main.js Normal file
View File

@@ -0,0 +1,14 @@
/* 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');
module.exports = {
initialize: initialize,
update: update,
destroy: destroy
};

View File

@@ -0,0 +1,20 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
module.exports = {
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
};

25
src/js/plugin/destroy.js Normal file
View File

@@ -0,0 +1,25 @@
/* 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');
module.exports = function (element) {
var i = instances.get(element);
if (!i) {
return;
}
i.event.unbindAll();
d.remove(i.scrollbarX);
d.remove(i.scrollbarY);
d.remove(i.scrollbarXRail);
d.remove(i.scrollbarYRail);
h.removePsClasses(element);
instances.remove(element);
};

View File

@@ -0,0 +1,63 @@
/* 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');
function bindClickRailHandler(element, i) {
function pageOffset(el) {
return el.getBoundingClientRect();
}
var stopPropagation = window.Event.prototype.stopPropagation.bind;
if (i.settings.stopPropagationOnClick) {
i.event.bind(i.scrollbarY, 'click', stopPropagation);
}
i.event.bind(i.scrollbarYRail, 'click', function (e) {
var halfOfScrollbarLength = h.toInt(i.scrollbarYHeight / 2);
var positionTop = i.railYRatio * (e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength);
var maxPositionTop = i.railYRatio * (i.railYHeight - i.scrollbarYHeight);
var positionRatio = positionTop / maxPositionTop;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
updateScroll(element, 'top', (i.contentHeight - i.containerHeight) * positionRatio);
updateGeometry(element);
e.stopPropagation();
});
if (i.settings.stopPropagationOnClick) {
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.pageXOffset - pageOffset(i.scrollbarXRail).left - halfOfScrollbarLength);
var maxPositionLeft = i.railXRatio * (i.railXWidth - i.scrollbarXWidth);
var positionRatio = positionLeft / maxPositionLeft;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
updateScroll(element, 'left', ((i.contentWidth - i.containerWidth) * positionRatio) - i.negativeScrollAdjustment);
updateGeometry(element);
e.stopPropagation();
});
}
module.exports = function (element) {
var i = instances.get(element);
bindClickRailHandler(element, i);
};

View File

@@ -0,0 +1,106 @@
/* 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');
function bindMouseScrollXHandler(element, i) {
var currentLeft = null;
var currentPageX = null;
function updateScrollLeft(deltaX) {
var newLeft = currentLeft + (deltaX * i.railXRatio);
var maxLeft = Math.max(0, i.scrollbarXRail.getBoundingClientRect().left) + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth));
if (newLeft < 0) {
i.scrollbarXLeft = 0;
} else if (newLeft > maxLeft) {
i.scrollbarXLeft = maxLeft;
} else {
i.scrollbarXLeft = newLeft;
}
var scrollLeft = h.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - (i.railXRatio * i.scrollbarXWidth))) - i.negativeScrollAdjustment;
updateScroll(element, 'left', scrollLeft);
}
var mouseMoveHandler = function (e) {
updateScrollLeft(e.pageX - currentPageX);
updateGeometry(element);
e.stopPropagation();
e.preventDefault();
};
var mouseUpHandler = function () {
h.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');
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
e.stopPropagation();
e.preventDefault();
});
}
function bindMouseScrollYHandler(element, i) {
var currentTop = null;
var currentPageY = null;
function updateScrollTop(deltaY) {
var newTop = currentTop + (deltaY * i.railYRatio);
var maxTop = Math.max(0, i.scrollbarYRail.getBoundingClientRect().top) + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight));
if (newTop < 0) {
i.scrollbarYTop = 0;
} else if (newTop > maxTop) {
i.scrollbarYTop = maxTop;
} else {
i.scrollbarYTop = newTop;
}
var scrollTop = h.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - (i.railYRatio * i.scrollbarYHeight)));
updateScroll(element, 'top', scrollTop);
}
var mouseMoveHandler = function (e) {
updateScrollTop(e.pageY - currentPageY);
updateGeometry(element);
e.stopPropagation();
e.preventDefault();
};
var mouseUpHandler = function () {
h.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');
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
e.stopPropagation();
e.preventDefault();
});
}
module.exports = function (element) {
var i = instances.get(element);
bindMouseScrollXHandler(element, i);
bindMouseScrollYHandler(element, i);
};

View File

@@ -0,0 +1,125 @@
/* 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');
function bindKeyboardHandler(element, i) {
var hovered = false;
i.event.bind(element, 'mouseenter', function () {
hovered = true;
});
i.event.bind(element, 'mouseleave', function () {
hovered = false;
});
var shouldPrevent = false;
function shouldPreventDefault(deltaX, deltaY) {
var scrollTop = element.scrollTop;
if (deltaX === 0) {
if (!i.scrollbarYActive) {
return false;
}
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)) {
return !i.settings.wheelPropagation;
}
}
var scrollLeft = element.scrollLeft;
if (deltaY === 0) {
if (!i.scrollbarXActive) {
return false;
}
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)) {
return !i.settings.wheelPropagation;
}
}
return true;
}
i.event.bind(i.ownerDocument, 'keydown', function (e) {
if (e.isDefaultPrevented && e.isDefaultPrevented()) {
return;
}
if (!hovered) {
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 (h.isEditable(activeElement)) {
return;
}
}
var deltaX = 0;
var deltaY = 0;
switch (e.which) {
case 37: // left
deltaX = -30;
break;
case 38: // up
deltaY = 30;
break;
case 39: // right
deltaX = 30;
break;
case 40: // down
deltaY = -30;
break;
case 33: // page up
deltaY = 90;
break;
case 32: // space bar
if (e.shiftKey) {
deltaY = 90;
} else {
deltaY = -90;
}
break;
case 34: // page down
deltaY = -90;
break;
case 35: // end
if (e.ctrlKey) {
deltaY = -i.contentHeight;
} else {
deltaY = -i.containerHeight;
}
break;
case 36: // home
if (e.ctrlKey) {
deltaY = element.scrollTop;
} else {
deltaY = i.containerHeight;
}
break;
default:
return;
}
updateScroll(element, 'top', element.scrollTop - deltaY);
updateScroll(element, 'left', element.scrollLeft + deltaX);
updateGeometry(element);
shouldPrevent = shouldPreventDefault(deltaX, deltaY);
if (shouldPrevent) {
e.preventDefault();
}
});
}
module.exports = function (element) {
var i = instances.get(element);
bindKeyboardHandler(element, i);
};

View File

@@ -0,0 +1,137 @@
/* 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');
function bindMouseWheelHandler(element, i) {
var shouldPrevent = false;
function shouldPreventDefault(deltaX, deltaY) {
var scrollTop = element.scrollTop;
if (deltaX === 0) {
if (!i.scrollbarYActive) {
return false;
}
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)) {
return !i.settings.wheelPropagation;
}
}
var scrollLeft = element.scrollLeft;
if (deltaY === 0) {
if (!i.scrollbarXActive) {
return false;
}
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)) {
return !i.settings.wheelPropagation;
}
}
return true;
}
function getDeltaFromEvent(e) {
var deltaX = e.deltaX;
var deltaY = -1 * e.deltaY;
if (typeof deltaX === "undefined" || typeof deltaY === "undefined") {
// OS X Safari
deltaX = -1 * e.wheelDeltaX / 6;
deltaY = e.wheelDeltaY / 6;
}
if (e.deltaMode && e.deltaMode === 1) {
// Firefox in deltaMode 1: Line scrolling
deltaX *= 10;
deltaY *= 10;
}
if (deltaX !== deltaX && deltaY !== deltaY/* NaN checks */) {
// IE in some mouse drivers
deltaX = 0;
deltaY = e.wheelDelta;
}
return [deltaX, deltaY];
}
function shouldBeConsumedByTextarea(deltaX, deltaY) {
var hoveredTextarea = element.querySelector('textarea:hover');
if (hoveredTextarea) {
var maxScrollTop = hoveredTextarea.scrollHeight - hoveredTextarea.clientHeight;
if (maxScrollTop > 0) {
if (!(hoveredTextarea.scrollTop === 0 && deltaY > 0) &&
!(hoveredTextarea.scrollTop === maxScrollTop && deltaY < 0)) {
return true;
}
}
var maxScrollLeft = hoveredTextarea.scrollLeft - hoveredTextarea.clientWidth;
if (maxScrollLeft > 0) {
if (!(hoveredTextarea.scrollLeft === 0 && deltaX < 0) &&
!(hoveredTextarea.scrollLeft === maxScrollLeft && deltaX > 0)) {
return true;
}
}
}
return false;
}
function mousewheelHandler(e) {
var delta = getDeltaFromEvent(e);
var deltaX = delta[0];
var deltaY = delta[1];
if (shouldBeConsumedByTextarea(deltaX, deltaY)) {
return;
}
shouldPrevent = false;
if (!i.settings.useBothWheelAxes) {
// deltaX will only be used for horizontal scrolling and deltaY will
// only be used for vertical scrolling - this is the default
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
} else if (i.scrollbarYActive && !i.scrollbarXActive) {
// only vertical scrollbar is active and useBothWheelAxes option is
// active, so let's scroll vertical bar using both mouse wheel axes
if (deltaY) {
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
} else {
updateScroll(element, 'top', element.scrollTop + (deltaX * i.settings.wheelSpeed));
}
shouldPrevent = true;
} else if (i.scrollbarXActive && !i.scrollbarYActive) {
// useBothWheelAxes and only horizontal bar is active, so use both
// wheel axes for horizontal bar
if (deltaX) {
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
} else {
updateScroll(element, 'left', element.scrollLeft - (deltaY * i.settings.wheelSpeed));
}
shouldPrevent = true;
}
updateGeometry(element);
shouldPrevent = (shouldPrevent || shouldPreventDefault(deltaX, deltaY));
if (shouldPrevent) {
e.stopPropagation();
e.preventDefault();
}
}
if (typeof window.onwheel !== "undefined") {
i.event.bind(element, 'wheel', mousewheelHandler);
} else if (typeof window.onmousewheel !== "undefined") {
i.event.bind(element, 'mousewheel', mousewheelHandler);
}
}
module.exports = function (element) {
var i = instances.get(element);
bindMouseWheelHandler(element, i);
};

View File

@@ -0,0 +1,18 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
var instances = require('../instances')
, updateGeometry = require('../update-geometry');
function bindNativeScrollHandler(element, i) {
i.event.bind(element, 'scroll', function () {
updateGeometry(element);
});
}
module.exports = function (element) {
var i = instances.get(element);
bindNativeScrollHandler(element, i);
};

View File

@@ -0,0 +1,112 @@
/* 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');
function bindSelectionHandler(element, i) {
function getRangeNode() {
var selection = window.getSelection ? window.getSelection() :
document.getSelection ? document.getSelection() : '';
if (selection.toString().length === 0) {
return null;
} else {
return selection.getRangeAt(0).commonAncestorContainer;
}
}
var scrollingLoop = null;
var scrollDiff = {top: 0, left: 0};
function startScrolling() {
if (!scrollingLoop) {
scrollingLoop = setInterval(function () {
if (!instances.get(element)) {
clearInterval(scrollingLoop);
return;
}
updateScroll(element, 'top', element.scrollTop + scrollDiff.top);
updateScroll(element, 'left', element.scrollLeft + scrollDiff.left);
updateGeometry(element);
}, 50); // every .1 sec
}
}
function stopScrolling() {
if (scrollingLoop) {
clearInterval(scrollingLoop);
scrollingLoop = null;
}
h.stopScrolling(element);
}
var isSelected = false;
i.event.bind(i.ownerDocument, 'selectionchange', function () {
if (element.contains(getRangeNode())) {
isSelected = true;
} else {
isSelected = false;
stopScrolling();
}
});
i.event.bind(window, 'mouseup', function () {
if (isSelected) {
isSelected = false;
stopScrolling();
}
});
i.event.bind(window, 'mousemove', function (e) {
if (isSelected) {
var mousePosition = {x: e.pageX, y: e.pageY};
var containerGeometry = {
left: element.offsetLeft,
right: element.offsetLeft + element.offsetWidth,
top: element.offsetTop,
bottom: element.offsetTop + element.offsetHeight
};
if (mousePosition.x < containerGeometry.left + 3) {
scrollDiff.left = -5;
h.startScrolling(element, 'x');
} else if (mousePosition.x > containerGeometry.right - 3) {
scrollDiff.left = 5;
h.startScrolling(element, 'x');
} else {
scrollDiff.left = 0;
}
if (mousePosition.y < containerGeometry.top + 3) {
if (containerGeometry.top + 3 - mousePosition.y < 5) {
scrollDiff.top = -5;
} else {
scrollDiff.top = -20;
}
h.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');
} else {
scrollDiff.top = 0;
}
if (scrollDiff.top === 0 && scrollDiff.left === 0) {
stopScrolling();
} else {
startScrolling();
}
}
});
}
module.exports = function (element) {
var i = instances.get(element);
bindSelectionHandler(element, i);
};

View File

@@ -0,0 +1,171 @@
/* 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');
function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
function shouldPreventDefault(deltaX, deltaY) {
var scrollTop = element.scrollTop;
var scrollLeft = element.scrollLeft;
var magnitudeX = Math.abs(deltaX);
var magnitudeY = Math.abs(deltaY);
if (magnitudeY > magnitudeX) {
// user is perhaps trying to swipe up/down the page
if (((deltaY < 0) && (scrollTop === i.contentHeight - i.containerHeight)) ||
((deltaY > 0) && (scrollTop === 0))) {
return !i.settings.swipePropagation;
}
} else if (magnitudeX > magnitudeY) {
// user is perhaps trying to swipe left/right across the page
if (((deltaX < 0) && (scrollLeft === i.contentWidth - i.containerWidth)) ||
((deltaX > 0) && (scrollLeft === 0))) {
return !i.settings.swipePropagation;
}
}
return true;
}
function applyTouchMove(differenceX, differenceY) {
updateScroll(element, 'top', element.scrollTop - differenceY);
updateScroll(element, 'left', element.scrollLeft - differenceX);
updateGeometry(element);
}
var startOffset = {};
var startTime = 0;
var speed = {};
var easingLoop = null;
var inGlobalTouch = false;
var inLocalTouch = false;
function globalTouchStart() {
inGlobalTouch = true;
}
function globalTouchEnd() {
inGlobalTouch = false;
}
function getTouch(e) {
if (e.targetTouches) {
return e.targetTouches[0];
} else {
// Maybe IE pointer
return e;
}
}
function shouldHandle(e) {
if (e.targetTouches && e.targetTouches.length === 1) {
return true;
}
if (e.pointerType && e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
return true;
}
return false;
}
function touchStart(e) {
if (shouldHandle(e)) {
inLocalTouch = true;
var touch = getTouch(e);
startOffset.pageX = touch.pageX;
startOffset.pageY = touch.pageY;
startTime = (new Date()).getTime();
if (easingLoop !== null) {
clearInterval(easingLoop);
}
e.stopPropagation();
}
}
function touchMove(e) {
if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) {
var touch = getTouch(e);
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();
}
}
}
function touchEnd() {
if (!inGlobalTouch && inLocalTouch) {
inLocalTouch = false;
clearInterval(easingLoop);
easingLoop = setInterval(function () {
if (!instances.get(element)) {
clearInterval(easingLoop);
return;
}
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
clearInterval(easingLoop);
return;
}
applyTouchMove(speed.x * 30, speed.y * 30);
speed.x *= 0.8;
speed.y *= 0.8;
}, 10);
}
}
if (supportsTouch) {
i.event.bind(window, 'touchstart', globalTouchStart);
i.event.bind(window, 'touchend', globalTouchEnd);
i.event.bind(element, 'touchstart', touchStart);
i.event.bind(element, 'touchmove', touchMove);
i.event.bind(element, 'touchend', touchEnd);
}
if (supportsIePointer) {
if (window.PointerEvent) {
i.event.bind(window, 'pointerdown', globalTouchStart);
i.event.bind(window, 'pointerup', globalTouchEnd);
i.event.bind(element, 'pointerdown', touchStart);
i.event.bind(element, 'pointermove', touchMove);
i.event.bind(element, 'pointerup', touchEnd);
} else if (window.MSPointerEvent) {
i.event.bind(window, 'MSPointerDown', globalTouchStart);
i.event.bind(window, 'MSPointerUp', globalTouchEnd);
i.event.bind(element, 'MSPointerDown', touchStart);
i.event.bind(element, 'MSPointerMove', touchMove);
i.event.bind(element, 'MSPointerUp', touchEnd);
}
}
}
module.exports = function (element, supportsTouch, supportsIePointer) {
var i = instances.get(element);
bindTouchHandler(element, i, supportsTouch, supportsIePointer);
};

View File

@@ -0,0 +1,47 @@
/* 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');
// 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');
module.exports = function (element, userSettings) {
userSettings = typeof userSettings === 'object' ? userSettings : {};
cls.add(element, 'ps-container');
// Create a plugin instance.
var i = instances.add(element);
i.settings = h.extend(i.settings, userSettings);
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);
};

109
src/js/plugin/instances.js Normal file
View File

@@ -0,0 +1,109 @@
/* 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 instances = {};
function Instance(element) {
var i = this;
i.settings = h.clone(defaultSettings);
i.containerWidth = null;
i.containerHeight = null;
i.contentWidth = null;
i.contentHeight = null;
i.isRtl = d.css(element, 'direction') === "rtl";
i.isNegativeScroll = (function () {
var originalScrollLeft = element.scrollLeft;
var result = null;
element.scrollLeft = -1;
result = element.scrollLeft < 0;
element.scrollLeft = originalScrollLeft;
return result;
})();
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
i.event = new EventManager();
i.ownerDocument = element.ownerDocument || document;
i.scrollbarXRail = d.appendTo(d.e('div', 'ps-scrollbar-x-rail'), element);
i.scrollbarX = d.appendTo(d.e('div', 'ps-scrollbar-x'), i.scrollbarXRail);
i.scrollbarX.setAttribute('tabindex', 0);
i.scrollbarXActive = null;
i.scrollbarXWidth = null;
i.scrollbarXLeft = null;
i.scrollbarXBottom = h.toInt(d.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'));
// 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', '');
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.scrollbarY.setAttribute('tabindex', 0);
i.scrollbarYActive = null;
i.scrollbarYHeight = null;
i.scrollbarYTop = null;
i.scrollbarYRight = h.toInt(d.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.railYHeight = null;
i.railYRatio = null;
}
function getId(element) {
if (typeof element.dataset === 'undefined') {
return element.getAttribute('data-ps-id');
} else {
return element.dataset.psId;
}
}
function setId(element, id) {
if (typeof element.dataset === 'undefined') {
element.setAttribute('data-ps-id', id);
} else {
element.dataset.psId = id;
}
}
function removeId(element) {
if (typeof element.dataset === 'undefined') {
element.removeAttribute('data-ps-id');
} else {
delete element.dataset.psId;
}
}
exports.add = function (element) {
var newId = guid();
setId(element, newId);
instances[newId] = new Instance(element);
return instances[newId];
};
exports.remove = function (element) {
delete instances[getId(element)];
removeId(element);
};
exports.get = function (element) {
return instances[getId(element)];
};

View File

@@ -0,0 +1,129 @@
/* 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');
function getThumbSize(i, thumbSize) {
if (i.settings.minScrollbarLength) {
thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);
}
if (i.settings.maxScrollbarLength) {
thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);
}
return thumbSize;
}
function updateCss(element, i) {
var xRailOffset = {width: i.railXWidth};
if (i.isRtl) {
xRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth - i.contentWidth;
} else {
xRailOffset.left = element.scrollLeft;
}
if (i.isScrollbarXUsingBottom) {
xRailOffset.bottom = i.scrollbarXBottom - element.scrollTop;
} else {
xRailOffset.top = i.scrollbarXTop + element.scrollTop;
}
d.css(i.scrollbarXRail, xRailOffset);
var yRailOffset = {top: element.scrollTop, height: i.railYHeight};
if (i.isScrollbarYUsingRight) {
if (i.isRtl) {
yRailOffset.right = i.contentWidth - (i.negativeScrollAdjustment + element.scrollLeft) - i.scrollbarYRight - i.scrollbarYOuterWidth;
} else {
yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
}
} else {
if (i.isRtl) {
yRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth * 2 - i.contentWidth - i.scrollbarYLeft - i.scrollbarYOuterWidth;
} else {
yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
}
}
d.css(i.scrollbarYRail, yRailOffset);
d.css(i.scrollbarX, {left: i.scrollbarXLeft, width: i.scrollbarXWidth - i.railBorderXWidth});
d.css(i.scrollbarY, {top: i.scrollbarYTop, height: i.scrollbarYHeight - i.railBorderYWidth});
}
module.exports = function (element) {
var i = instances.get(element);
i.containerWidth = element.clientWidth;
i.containerHeight = element.clientHeight;
i.contentWidth = element.scrollWidth;
i.contentHeight = element.scrollHeight;
var existingRails;
if (!element.contains(i.scrollbarXRail)) {
existingRails = d.queryChildren(element, '.ps-scrollbar-x-rail');
if (existingRails.length > 0) {
existingRails.forEach(function (rail) {
d.remove(rail);
});
}
d.appendTo(i.scrollbarXRail, element);
}
if (!element.contains(i.scrollbarYRail)) {
existingRails = d.queryChildren(element, '.ps-scrollbar-y-rail');
if (existingRails.length > 0) {
existingRails.forEach(function (rail) {
d.remove(rail);
});
}
d.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));
} else {
i.scrollbarXActive = false;
}
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));
} else {
i.scrollbarYActive = false;
}
if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;
}
if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {
i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;
}
updateCss(element, i);
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

@@ -0,0 +1,105 @@
/* 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;
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);
module.exports = function (element, axis, value) {
if (typeof element === 'undefined') {
throw 'You must provide an element to the update-scroll function';
}
if (typeof axis === 'undefined') {
throw 'You must provide an axis to the update-scroll function';
}
if (typeof value === 'undefined') {
throw 'You must provide a value to the update-scroll function';
}
if (axis === 'top' && value <= 0) {
element.scrollTop = 0;
element.dispatchEvent(yStartEvent);
return; // don't allow negative scroll
}
if (axis === 'left' && value <= 0) {
element.scrollLeft = 0;
element.dispatchEvent(xStartEvent);
return; // don't allow negative scroll
}
var i = instances.get(element);
if (axis === 'top' && value >= i.contentHeight - i.containerHeight) {
element.scrollTop = i.contentHeight - i.containerHeight;
element.dispatchEvent(yEndEvent);
return; // don't allow scroll past container
}
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 (!lastTop) {
lastTop = element.scrollTop;
}
if (!lastLeft) {
lastLeft = element.scrollLeft;
}
if (axis === 'top' && value < lastTop) {
element.dispatchEvent(upEvent);
}
if (axis === 'top' && value > lastTop) {
element.dispatchEvent(downEvent);
}
if (axis === 'left' && value < lastLeft) {
element.dispatchEvent(leftEvent);
}
if (axis === 'left' && value > lastLeft) {
element.dispatchEvent(rightEvent);
}
if (axis === 'top') {
element.scrollTop = lastTop = value;
element.dispatchEvent(yEvent);
}
if (axis === 'left') {
element.scrollLeft = lastLeft = value;
element.dispatchEvent(xEvent);
}
};

40
src/js/plugin/update.js Normal file
View File

@@ -0,0 +1,40 @@
/* 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');
module.exports = function (element) {
var i = instances.get(element);
if (!i) {
return;
}
// Recalcuate negative scrollLeft adjustment
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'));
// Hide scrollbars not to affect scrollWidth and scrollHeight
d.css(i.scrollbarXRail, 'display', 'none');
d.css(i.scrollbarYRail, 'display', 'none');
updateGeometry(element);
// Update top/left scroll to trigger events
updateScroll(element, 'top', element.scrollTop);
updateScroll(element, 'left', element.scrollLeft);
d.css(i.scrollbarXRail, 'display', '');
d.css(i.scrollbarYRail, 'display', '');
};

View File

@@ -1,75 +0,0 @@
.ps-container .ps-scrollbar-x {
position: absolute; /* please don't change 'position' */
bottom: 3px; /* there must be 'bottom' for ps-scrollbar-x */
height: 8px;
background-color: #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
opacity: 0;
filter: alpha(opacity = 0);
-o-transition: opacity .2s linear;
-webkit-transition: opacity.2s linear;
-moz-transition: opacity .2s linear;
transition: opacity .2s linear;
}
.ps-container.ie6 .ps-scrollbar-x {
font-size: 0; /* fixed scrollbar height in xp sp3 ie6 */
}
.ps-container:hover .ps-scrollbar-x,
.ps-container.hover .ps-scrollbar-x {
opacity: 0.6;
filter: alpha(opacity = 60);
}
.ps-container .ps-scrollbar-x:hover,
.ps-container .ps-scrollbar-x.hover {
opacity: 0.9;
filter: alpha(opacity = 90);
cursor:default;
}
.ps-container .ps-scrollbar-x.in-scrolling {
opacity: 0.9;
filter: alpha(opacity = 90);
}
.ps-container .ps-scrollbar-y {
position: absolute; /* please don't change 'position' */
right: 3px; /* there must be 'right' for ps-scrollbar-y */
width: 8px;
background-color: #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
opacity: 0;
filter: alpha(opacity = 0);
-o-transition: opacity .2s linear;
-webkit-transition: opacity.2s linear;
-moz-transition: opacity .2s linear;
transition: opacity .2s linear;
}
.ps-container.ie .ps-scrollbar-y {
font-size: 0; /* fixed scrollbar height in xp sp3 ie6 */
}
.ps-container:hover .ps-scrollbar-y,
.ps-container.hover .ps-scrollbar-y {
opacity: 0.6;
filter: alpha(opacity = 60);
}
.ps-container .ps-scrollbar-y:hover,
.ps-container .ps-scrollbar-y.hover {
opacity: 0.9;
filter: alpha(opacity = 90);
cursor: default;
}
.ps-container .ps-scrollbar-y.in-scrolling {
opacity: 0.9;
filter: alpha(opacity = 90);
}

View File

@@ -1,384 +0,0 @@
/* Copyright (c) 2012 HyeonJe Jun (http://github.com/noraesae)
* Licensed under the MIT License
*/
((function ($) {
// The default settings for the plugin
var defaultSettings = {
wheelSpeed: 10,
wheelPropagation: false
};
$.fn.perfectScrollbar = function (suppliedSettings, option) {
return this.each(function () {
// Use the default settings
var settings = $.extend(true, {}, defaultSettings);
if (typeof suppliedSettings === "object") {
// But over-ride any supplied
$.extend(true, settings, suppliedSettings);
} else {
// If no settings were supplied, then the first param must be the option
option = suppliedSettings;
}
if (option === 'update') {
if ($(this).data('perfect-scrollbar-update')) {
$(this).data('perfect-scrollbar-update')();
}
return $(this);
}
else if (option === 'destroy') {
if ($(this).data('perfect-scrollbar-destroy')) {
$(this).data('perfect-scrollbar-destroy')();
}
return $(this);
}
if ($(this).data('perfect-scrollbar')) {
// if there's already perfect-scrollbar
return $(this).data('perfect-scrollbar');
}
var $this = $(this).addClass('ps-container'),
$scrollbarX = $("<div class='ps-scrollbar-x'></div>").appendTo($this),
$scrollbarY = $("<div class='ps-scrollbar-y'></div>").appendTo($this),
containerWidth,
containerHeight,
contentWidth,
contentHeight,
scrollbarXWidth,
scrollbarXLeft,
scrollbarXBottom = parseInt($scrollbarX.css('bottom'), 10),
scrollbarYHeight,
scrollbarYTop,
scrollbarYRight = parseInt($scrollbarY.css('right'), 10);
var updateContentScrollTop = function () {
var scrollTop = parseInt(scrollbarYTop * contentHeight / containerHeight, 10);
$this.scrollTop(scrollTop);
$scrollbarX.css({bottom: scrollbarXBottom - scrollTop});
};
var updateContentScrollLeft = function () {
var scrollLeft = parseInt(scrollbarXLeft * contentWidth / containerWidth, 10);
$this.scrollLeft(scrollLeft);
$scrollbarY.css({right: scrollbarYRight - scrollLeft});
};
var updateScrollbarCss = function () {
$scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft(), bottom: scrollbarXBottom - $this.scrollTop(), width: scrollbarXWidth});
$scrollbarY.css({top: scrollbarYTop + $this.scrollTop(), right: scrollbarYRight - $this.scrollLeft(), height: scrollbarYHeight});
};
var updateBarSizeAndPosition = function () {
containerWidth = $this.width();
containerHeight = $this.height();
contentWidth = $this.prop('scrollWidth');
contentHeight = $this.prop('scrollHeight');
if (containerWidth < contentWidth) {
scrollbarXWidth = parseInt(containerWidth * containerWidth / contentWidth, 10);
scrollbarXLeft = parseInt($this.scrollLeft() * containerWidth / contentWidth, 10);
}
else {
scrollbarXWidth = 0;
scrollbarXLeft = 0;
$this.scrollLeft(0);
}
if (containerHeight < contentHeight) {
scrollbarYHeight = parseInt(containerHeight * containerHeight / contentHeight, 10);
scrollbarYTop = parseInt($this.scrollTop() * containerHeight / contentHeight, 10);
}
else {
scrollbarYHeight = 0;
scrollbarYTop = 0;
$this.scrollTop(0);
}
if (scrollbarYTop >= containerHeight - scrollbarYHeight) {
scrollbarYTop = containerHeight - scrollbarYHeight;
}
if (scrollbarXLeft >= containerWidth - scrollbarXWidth) {
scrollbarXLeft = containerWidth - scrollbarXWidth;
}
updateScrollbarCss();
};
var moveBarX = function (currentLeft, deltaX) {
var newLeft = currentLeft + deltaX,
maxLeft = containerWidth - scrollbarXWidth;
if (newLeft < 0) {
scrollbarXLeft = 0;
}
else if (newLeft > maxLeft) {
scrollbarXLeft = maxLeft;
}
else {
scrollbarXLeft = newLeft;
}
$scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft()});
};
var moveBarY = function (currentTop, deltaY) {
var newTop = currentTop + deltaY,
maxTop = containerHeight - scrollbarYHeight;
if (newTop < 0) {
scrollbarYTop = 0;
}
else if (newTop > maxTop) {
scrollbarYTop = maxTop;
}
else {
scrollbarYTop = newTop;
}
$scrollbarY.css({top: scrollbarYTop + $this.scrollTop()});
};
var bindMouseScrollXHandler = function () {
var currentLeft,
currentPageX;
$scrollbarX.bind('mousedown.perfect-scroll', function (e) {
currentPageX = e.pageX;
currentLeft = $scrollbarX.position().left;
$scrollbarX.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove.perfect-scroll', function (e) {
if ($scrollbarX.hasClass('in-scrolling')) {
updateContentScrollLeft();
moveBarX(currentLeft, e.pageX - currentPageX);
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup.perfect-scroll', function (e) {
if ($scrollbarX.hasClass('in-scrolling')) {
$scrollbarX.removeClass('in-scrolling');
}
});
};
var bindMouseScrollYHandler = function () {
var currentTop,
currentPageY;
$scrollbarY.bind('mousedown.perfect-scroll', function (e) {
currentPageY = e.pageY;
currentTop = $scrollbarY.position().top;
$scrollbarY.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove.perfect-scroll', function (e) {
if ($scrollbarY.hasClass('in-scrolling')) {
updateContentScrollTop();
moveBarY(currentTop, e.pageY - currentPageY);
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup.perfect-scroll', function (e) {
if ($scrollbarY.hasClass('in-scrolling')) {
$scrollbarY.removeClass('in-scrolling');
}
});
};
// bind handlers
var bindMouseWheelHandler = function () {
var shouldPreventDefault = function (deltaX, deltaY) {
var scrollTop = $this.scrollTop();
if (scrollTop === 0 && deltaY > 0 && deltaX === 0) {
return !settings.wheelPropagation;
}
else if (scrollTop >= contentHeight - containerHeight && deltaY < 0 && deltaX === 0) {
return !settings.wheelPropagation;
}
var scrollLeft = $this.scrollLeft();
if (scrollLeft === 0 && deltaX < 0 && deltaY === 0) {
return !settings.wheelPropagation;
}
else if (scrollLeft >= contentWidth - containerWidth && deltaX > 0 && deltaY === 0) {
return !settings.wheelPropagation;
}
return true;
};
$this.bind('mousewheel.perfect-scroll', function (e, delta, deltaX, deltaY) {
$this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed));
$this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed));
// update bar position
updateBarSizeAndPosition();
if (shouldPreventDefault(deltaX, deltaY)) {
e.preventDefault();
}
});
};
// bind mobile touch handler
var bindMobileTouchHandler = function () {
var applyTouchMove = function (differenceX, differenceY) {
$this.scrollTop($this.scrollTop() - differenceY);
$this.scrollLeft($this.scrollLeft() - differenceX);
// update bar position
updateBarSizeAndPosition();
};
var startCoords = {},
startTime = 0,
speed = {},
breakingProcess = null,
inGlobalTouch = false;
$(window).bind("touchstart.perfect-scroll", function (e) {
inGlobalTouch = true;
});
$(window).bind("touchend.perfect-scroll", function (e) {
inGlobalTouch = false;
});
$this.bind("touchstart.perfect-scroll", function (e) {
var touch = e.originalEvent.targetTouches[0];
startCoords.pageX = touch.pageX;
startCoords.pageY = touch.pageY;
startTime = (new Date()).getTime();
if (breakingProcess !== null) {
clearInterval(breakingProcess);
}
e.stopPropagation();
});
$this.bind("touchmove.perfect-scroll", function (e) {
if (!inGlobalTouch && e.originalEvent.targetTouches.length === 1) {
var touch = e.originalEvent.targetTouches[0];
var currentCoords = {};
currentCoords.pageX = touch.pageX;
currentCoords.pageY = touch.pageY;
var differenceX = currentCoords.pageX - startCoords.pageX,
differenceY = currentCoords.pageY - startCoords.pageY;
applyTouchMove(differenceX, differenceY);
startCoords = currentCoords;
var currentTime = (new Date()).getTime();
speed.x = differenceX / (currentTime - startTime);
speed.y = differenceY / (currentTime - startTime);
startTime = currentTime;
e.preventDefault();
}
});
$this.bind("touchend.perfect-scroll", function (e) {
breakingProcess = setInterval(function () {
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
clearInterval(breakingProcess);
return;
}
applyTouchMove(speed.x * 30, speed.y * 30);
speed.x *= 0.8;
speed.y *= 0.8;
}, 10);
});
};
var destroy = function () {
$scrollbarX.remove();
$scrollbarY.remove();
$this.unbind('.perfect-scroll');
$(window).unbind('.perfect-scroll');
$this.data('perfect-scrollbar', null);
$this.data('perfect-scrollbar-update', null);
$this.data('perfect-scrollbar-destroy', null);
};
var ieSupport = function (version) {
$this.addClass('ie').addClass('ie' + version);
var bindHoverHandlers = function () {
var mouseenter = function () {
$(this).addClass('hover');
};
var mouseleave = function () {
$(this).removeClass('hover');
};
$this.bind('mouseenter.perfect-scroll', mouseenter).bind('mouseleave.perfect-scroll', mouseleave);
$scrollbarX.bind('mouseenter.perfect-scroll', mouseenter).bind('mouseleave.perfect-scroll', mouseleave);
$scrollbarY.bind('mouseenter.perfect-scroll', mouseenter).bind('mouseleave.perfect-scroll', mouseleave);
};
var fixIe6ScrollbarPosition = function () {
updateScrollbarCss = function () {
$scrollbarX.css({left: scrollbarXLeft + $this.scrollLeft(), bottom: scrollbarXBottom, width: scrollbarXWidth});
$scrollbarY.css({top: scrollbarYTop + $this.scrollTop(), right: scrollbarYRight, height: scrollbarYHeight});
$scrollbarX.hide().show();
$scrollbarY.hide().show();
};
updateContentScrollTop = function () {
var scrollTop = parseInt(scrollbarYTop * contentHeight / containerHeight, 10);
$this.scrollTop(scrollTop);
$scrollbarX.css({bottom: scrollbarXBottom});
$scrollbarX.hide().show();
};
updateContentScrollLeft = function () {
var scrollLeft = parseInt(scrollbarXLeft * contentWidth / containerWidth, 10);
$this.scrollLeft(scrollLeft);
$scrollbarY.hide().show();
};
};
if (version === 6) {
bindHoverHandlers();
fixIe6ScrollbarPosition();
}
};
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var initialize = function () {
var ieMatch = navigator.userAgent.toLowerCase().match(/(msie) ([\w.]+)/);
if (ieMatch && ieMatch[1] === 'msie') {
// must be executed at first, because 'ieSupport' may addClass to the container
ieSupport(parseInt(ieMatch[2], 10));
}
updateBarSizeAndPosition();
bindMouseScrollXHandler();
bindMouseScrollYHandler();
if (isMobile) {
bindMobileTouchHandler();
}
if ($this.mousewheel) {
bindMouseWheelHandler();
}
$this.data('perfect-scrollbar', $this);
$this.data('perfect-scrollbar-update', updateBarSizeAndPosition);
$this.data('perfect-scrollbar-destroy', destroy);
};
// initialize
initialize();
return $this;
});
};
})(jQuery));