Compare commits

...

322 Commits
0.2.1 ... 0.6.3

Author SHA1 Message Date
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
Hyunje Alex Jun
5124a27113 Release 0.4.1.
Patch notes
1. Wrap core functionality in an each function.
2. Use scrollHeight and scrollWidth for content size.
3. IE fixes.
4. Bug fixes.
2013-06-27 11:26:21 +09:00
Hyunje Alex Jun
fa5e6cb38c Add version number in minified sources.
Version number is parsed from package.json.
Before release, the version number have '-dev' postfix.
2013-06-18 18:54:09 +09:00
Hyunje Alex Jun
dd89f14243 Add contrib-clean to Grunt.
We should clean 'min' directory before build.
2013-06-18 18:46:40 +09:00
Hyunje Alex Jun
7e5b225d61 Display an old version requirement.
This reverts commit f7d953d1eb2e3315d6b6b9d1f9ed217eaa22be6d.

And add 'for old versions' mark to the requirement.
2013-06-18 16:19:10 +09:00
Hyunje Alex Jun
e35920f10e Update README.
Add 'IE Support'.
2013-06-16 18:31:29 +09:00
Hyunje Alex Jun
4f6463114c Merge the patches of @maoziliang.
Includes IE fixes.
2013-06-16 17:59:21 +09:00
Hyunje Alex Jun
f02f5e89b7 Fix ie6 scrollbar position problem.
This patch is in fact contributed by the idea of @maoziliang.
2013-06-16 17:56:40 +09:00
Hyunje Alex Jun
21d5d4ab63 Separate the function updating the css of scrollbars. 2013-06-16 17:45:37 +09:00
maoziliang
e833f42d02 Fixed the scrollbar height for xp sp3 ie6
set 'font-size:0' for the scrollbar
2013-06-16 17:22:18 +09:00
maoziliang
a52d55957d Add hover handlers for ie6.
Use scripts to add '.hover' class on the `.ps-container` and both
scrollbars when then mouse is over them because :hover is not supported
except 'a' element.
2013-06-16 17:13:20 +09:00
maoziliang
e93d67e754 Add feature to suport ie.
For ie browser, the `.ps-container` element will add extra class `ie`
and `ie<version>`, like `ie6`, `ie7`, `ie8`, etc.
2013-06-16 17:00:12 +09:00
maoziliang
37210ee453 Add a sample based on text content 2013-06-16 16:49:30 +09:00
Hyunje Alex Jun
6021ec016e Update README.
The link to Contributing wiki page is added.
2013-06-16 00:30:43 +09:00
Hyunje Alex Jun
9be4a1a85f Minify source files with the new build system.
From now, the build can be done with 'grunt build'.
2013-06-16 00:30:43 +09:00
Hyunje Alex Jun
f65c9cb0bb Add files for Grunt. 2013-06-16 00:30:43 +09:00
Hyunje Alex Jun
29a0c13c65 Add csslintrc. 2013-06-15 22:04:50 +09:00
Hyunje Alex Jun
d8c961ee32 Csslint the css file. 2013-06-15 22:04:50 +09:00
Hyunje Alex Jun
a4d8487ee3 Remove build shell script.
We'll use grunt to build the scripts.
The shell script is no more used.
2013-06-15 20:59:26 +09:00
Hyunje Alex Jun
ff55090cd3 Add node_modules in gitignore. 2013-06-15 20:59:07 +09:00
Hyunje Alex Jun
7bc05bbda1 Refactor jshint files.
We'll use grunt, and jshintignore is useless.
Remove comments in jshintrc to be parsed in grunt.
2013-06-15 20:49:22 +09:00
Hyunje Alex Jun
3b1c37440e Inhance the scroll logic with mobile touches.
The scroll works only when the user touch and scroll the wrapper div
with just one touch. By this patch, the zoom function will not be
prevented by scrolling content.
2013-06-14 21:57:24 +09:00
Hyunje Alex Jun
aeab94c7d6 Fix the wrong indents in example pages. 2013-06-14 21:39:53 +09:00
Hyunje Alex Jun
eb8f28cd26 JSHint the code.
Missing space.
2013-06-14 21:38:33 +09:00
Hyunje Alex Jun
d5ef529438 Modify README.md.
The requirement that force just one content element is gone.
2013-06-14 21:36:47 +09:00
Hyunje Alex Jun
34a505d319 Remove $content.
It's not used anymore.
2013-06-14 21:35:32 +09:00
Hyunje Alex Jun
a8db04e41d Merge pull request #36 from zenozeng/master
Use prop('scrollWidth') and prop('scrollHeight') instead of outerWidth() and outerHeight() to get the content size.
2013-06-14 05:32:44 -07:00
Zeno Zeng
d14dfd307e use scrollHeight & scrollWidth to avoid getting the wrong size of the content 2013-06-14 10:13:30 +08:00
Hyunje Alex Jun
de6e4d59b0 Merge pull request #34 from itsdrewmiller/master
pull request for the fix provided in issue 16, for both vertical and horizontal scrolling
2013-06-12 09:29:49 -07:00
itsdrewmiller
351631cfa7 Fixing jumpiness for large scrolls
https://github.com/noraesae/perfect-scrollbar/issues/16
2013-06-12 12:57:43 -03:00
Hyunje Alex Jun
2f6432d263 Merge pull request #30 from maoziliang/master
Update the destroy method. Unbind listeners by event namespace.
2013-06-01 20:40:34 -07:00
maoziliang
3410cf89be update the destroy method. unbind listeners by event namespace.
This will be convenient for adding new event bind in the file. Do not
worry about forgetting to unbind it.
2013-06-02 11:16:33 +08:00
Hyunje Alex Jun
b89660f959 Merge pull request #26 from ahmadsherif/master
Wrap core functionality in an each function.
2013-05-22 18:46:32 -07:00
Ahmad Sherif
d5dd3422cf Wrap core functionality in an each function
If we have many DOM elements that match the PerfectScrollbar selector,
then all elemets get scrolled if one of them is scrolled.
2013-05-22 11:48:51 +02:00
Hyunje Alex Jun
c6c087275c Release 0.3.4.
Patch notes
1. Fix the bug that scrollbars don't stop at the end.
2. Code refactoring.
2013-05-18 12:43:38 +09:00
Hyunje Alex Jun
4613c3daee Code refactoring. 2013-05-18 12:41:15 +09:00
Hyunje Alex Jun
667c61d2c3 Add jshint files. 2013-05-18 12:39:26 +09:00
Hyunje Alex Jun
4012ce9c8c Prevent scrollbar x from moving out of the container. 2013-05-18 12:21:20 +09:00
Hyunje Alex Jun
9734a18d01 Merge pull request #19 from EtnasSoft/master
Fixed bug with the Mouse Wheel and the right scroll bar.
2013-05-17 20:18:19 -07:00
etnassoft
4f49b0fa7f Fix bug with mouse wheel 2013-03-21 11:21:20 +01:00
Hyunje Alex Jun
9d6728e3ff Release 0.3.3.
Patch notes
1. Apply jshint.
2. Fix jQuery plugin site version problem.
2013-03-14 15:47:20 +09:00
Hyunje Alex Jun
69c37268a1 Apply jshint. 2013-03-14 15:46:12 +09:00
Hyunje Alex Jun
960468fc9e Release 0.3.2.
Patch notes
1. Optional parameter support.
 - wheelSpeed
 - wheelPropagation
2. Example codes added.
2013-03-14 15:14:38 +09:00
Hyunje Alex Jun
42d528a839 Update README.md
Optional parameter support.
2013-03-14 13:44:51 +09:00
Hyunje Alex Jun
26e9ff1cac Example codes added by @GregDThomas. 2013-03-14 11:49:50 +09:00
GregDThomas
38b8b818e8 See issue #10 - provide support for optional settings, including prevention of the mousewheel event and the speed of scrolling 2013-03-14 11:36:57 +09:00
Hyunje Alex Jun
938f3134d7 Release 0.3.1.
Patch notes
1. Mobile touch support.
2. Scrolling logic enhancement.
3. Bug fix.
2013-02-16 00:23:49 +09:00
Hyunje Alex Jun
aa213398f3 Enhance scroll preventDefault logic.
Now scroll preventDefault works more like default browser scroll.
When the scroll leaches top, bottom, left and right end, don't
prevent default scrolling. For sure, when the content size is
smaller than the container size, also don't prevent default scrolling.
2013-02-16 00:17:23 +09:00
Hyunje Alex Jun
1cdbc9509f Fix missed ';'
In JavaScript, it's the convension that ';' is placed
at the end of statement
2013-02-15 23:58:57 +09:00
David
627b6a6b81 Take into account padding and margins on content
Changed the height and widths calculations of the content div to
include any padding and/or margins.

outerHeight(true) is changed to outerHeight(false).
outerWidth is changed as same.
Fixed by noraesae.
2013-02-15 23:44:20 +09:00
Hyunje Alex Jun
0099bb556c Supports the mobile touch scrolling.
Using touch events, support mobile scrolling with touch.
2013-02-12 22:37:45 +09:00
Hyunje Alex Jun
2e1e9f2f75 Release 0.2.5.
Patch notes
1. Bug fix.
2. Include min version with jquery-mousewheel.
2013-02-08 10:38:43 +09:00
Hyunje Alex Jun
f3b6fd520c Modify build script to uglifyjs2.
Upgrade to uglifyjs2 and add shell script to create
a min version source that includes jquery-mousewheel.
2013-02-08 10:36:01 +09:00
Hyunje Alex Jun
a6bb9d02a3 Include jquery-mousewheel in src. 2013-02-08 10:35:34 +09:00
Hyunje Alex Jun
639f369d33 Merge pull request #2 from davidkethel/patch-2
Ensure div is at top/left when scroll bars removed
2013-02-07 17:07:19 -08:00
David
dacb601f9f Update src/perfect_scrollbar.js
Ensure the panel is at the top after an update where the scroll bars
are removed. Other wise it is possible to get stuck midway down a panel
with no way of scrolling.
2013-02-07 14:29:44 +10:00
Hyunje Alex Jun
0c9dc8dbb4 Merge pull request #1 from davidkethel/patch-1
Just a couple of small grammar changes
2013-02-06 05:44:16 -08:00
David
f32e32485b Just a couple of small grammar changes 2013-02-06 20:02:02 +10:00
Hyunje Alex Jun
a4bee31597 Update README.md
Add the way how to scroll to somewhere.
2013-01-28 14:00:49 +09:00
Hyunje Alex Jun
bd9e96be12 Release 0.2.4.
Release to jquery plugins.
2013-01-28 13:52:25 +09:00
Hyunje Alex Jun
1bd0c102db IE support. 2012-11-10 17:30:09 +09:00
Hyunje Alex Jun
36ae8c4059 Add .gitignore. 2012-11-10 13:44:08 +09:00
Hyunje Alex Jun
db020f1d29 bug fix.
if handler functions are null, don't do anything.
2012-11-10 13:41:31 +09:00
Hyunje Alex Jun
8a7a471522 Update README.md
Update README for release!
2012-11-10 04:37:54 +09:00
55 changed files with 2867 additions and 275 deletions

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

20
.eslintrc Normal file
View File

@@ -0,0 +1,20 @@
{
"env" : {
"node": true,
"browser": true
},
"globals": {
"$": true,
"define": true
},
"rules" : {
"quotes": false,
"space-after-keywords": [2, "always", {"checkFunctionKeyword": true}],
"space-before-blocks": [2, "always"],
"brace-style": [2, "1tbs", { "allowSingleLine": false}],
"spaced-line-comment": [2, "always"],
"radix": [2, "always"],
"key-spacing": [2, "always", {"beforeColon": false, "afterColon": true}],
"no-multiple-empty-lines": [2, {max: 1}],
}
}

4
.gitignore vendored Normal file
View File

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

9
.npmignore Normal file
View File

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

17
.travis.yml Normal file
View File

@@ -0,0 +1,17 @@
language: node_js
node_js:
- '0.10'
before_script:
- npm install -g gulp
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:
- gulp
- gulp compress

353
README.md
View File

@@ -1,9 +1,350 @@
perfect-scrollbar
=================
# `perfect-scrollbar`
Tiny but perfect jQuery scrollbar plugin
Minimalistic but perfect custom scrollbar plugin
Under Development!
------------------
[![Travis CI](https://travis-ci.org/noraesae/perfect-scrollbar.svg?branch=master)](https://travis-ci.org/noraesae/perfect-scrollbar)
I'm working on... :D
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).
## Why 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.
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.
* *New!* It should work with vanilla JavaScript and major tools like
NPM or Browserify.
## Then perfect-scrollbar is really *perfect*?
* 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?
## Install
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.
## How to use
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: 1**
### wheelPropagation
If this option is true, when the scroll reaches the end of the side, mousewheel event will be propagated to parent element.
**Default: false**
### 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**
### minScrollbarLength
When set to an integer value, the thumb part of the scrollbar will not shrink below that number of pixels.
**Default: null**
### maxScrollbarLength
When set to an integer value, the thumb part of the scrollbar will not expand over that number of pixels.
**Default: null**
### 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**
## Contribution
#### 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...
* You have a very nice idea to improve this plugin!
* You found a bug!
* You're good at English and can help my bad English!
For IE problems, please refer to [IE Support](https://github.com/noraesae/perfect-scrollbar#ie-support).
## IE Support
The plugin would work in IEs >= IE9 (not well, though).
**The patches to fix problems in IE<=8 won't be accepted.**
When old IEs should be supported, please fork the project and
make patches personally.
## Helpdesk
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).
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.

3
build
View File

@@ -1,3 +0,0 @@
#!/bin/sh
uglifyjs src/perfect-scrollbar.js > min/perfect-scrollbar.min.js
cleancss src/perfect-scrollbar.css -o min/perfect-scrollbar.min.css

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>

BIN
examples/azusa.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

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

@@ -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 }
</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

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../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>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<h1 style="text-align:center">wheelPropagation:true</h1>
<div id="WheelPropagation" class="contentHolder">
<div class="content">
</div>
</div>
<div class="spacer">
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

@@ -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 }
</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>
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>
#description {
border: 1px solid gray;
height:150px;
width: 400px;
overflow: auto;
position: relative;
}
#status { color: red; }
</style>
</head>
<body>
<div id="description" class="wrapper">
<p>Hello, world! 0</p>
<p>Hello, world! 1</p>
<p>Hello, world! 2</p>
<p>Hello, world! 3</p>
<p>Hello, world! 4</p>
<p>Hello, world! 5</p>
<p>Hello, world! 6</p>
<p>Hello, world! 7</p>
<p>Hello, world! 8</p>
<p>Hello, world! 9</p>
</div>
<div id="status">
</div>
<script type="text/javascript">
var $ = document.querySelector.bind(document);
window.onload = function () {
var container = $('#description');
var stat = $('#status');
Ps.initialize(container);
container.addEventListener('scroll', function (e) {
if(container.scrollTop === 0) {
stat.innerHTML = 'it reaches the top!';
}
else if (container.scrollTop === container.scrollHeight - container.clientHeight) {
stat.innerHTML = 'it reaches the end!';
} else {
stat.innerHTML = '';
}
});
};
</script>
</body>
</html>

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

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
#description {
border: 1px solid gray;
height:150px;
width: 400px;
overflow: auto;
position: relative;
}
</style>
</head>
<body>
<div id="description" class="wrapper">
<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'));
};
$('#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>

139
gulpfile.js Normal file
View File

@@ -0,0 +1,139 @@
'use strict';
var gulp = require('gulp')
, browserify = require('browserify')
, bump = require('gulp-bump')
, connect = require('gulp-connect')
, eslint = require('gulp-eslint')
, insert = require('gulp-insert')
, rename = require('gulp-rename')
, rimraf = require('gulp-rimraf')
, sass = require('gulp-sass')
, transform = require('vinyl-transform')
, uglify = require('gulp-uglify')
, zip = require('gulp-zip');
var 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 gulp.src('./dist/js/*.js', {read: false})
.pipe(rimraf());
});
gulp.task('clean:js:min', function () {
return gulp.src('./dist/js/min/*.js', {read: false})
.pipe(rimraf());
});
function browserified() {
return transform(function (filename) {
var b = browserify(filename);
return b.bundle();
});
}
gulp.task('js', ['clean:js'], function () {
return gulp.src('./src/js/adaptor/*.js')
.pipe(browserified())
.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());
});
gulp.task('js:min', ['clean:js:min'], function () {
return gulp.src('./src/js/adaptor/*.js')
.pipe(browserified())
.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'));
});
gulp.task('clean:css', function () {
return gulp.src('./dist/css/perfect-scrollbar.css', {read: false})
.pipe(rimraf());
});
gulp.task('clean:css:min', function () {
return gulp.src('./dist/css/perfect-scrollbar.min.css', {read: false})
.pipe(rimraf());
});
gulp.task('sass', ['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('sass: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'));
});
function bumpType() {
if (gulp.env.major) {
return 'major';
} else if (gulp.env.minor) {
return 'minor';
} else {
return 'patch';
}
}
gulp.task('bump', function () {
gulp.src('./*.json')
.pipe(bump({type: bumpType()}))
.pipe(gulp.dest('./'));
});
gulp.task('release', ['bump', 'build']);
gulp.task('build', ['js', 'js:min', 'sass', 'sass:min']);
gulp.task('connect', ['build'], function () {
connect.server({
root: __dirname,
livereload: true
});
});
gulp.task('watch', function () {
gulp.watch(['src/js/**/*'], ['js']);
gulp.watch(['src/css/**/*'], ['sass']);
});
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 +0,0 @@
.ps-container .ps-scrollbar-x{position:absolute;bottom:3px;height:8px;background-color:#aaa;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;opacity:0;filter:alpha(opacity=0);-webkit-transition:opacity.2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.ps-container:hover .ps-scrollbar-x{opacity:.6;filter:alpha(opacity=60)}.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;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px;opacity:0;-webkit-transition:opacity.2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.ps-container:hover .ps-scrollbar-y{opacity:.6;filter:alpha(opacity=60)}.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,3 +0,0 @@
/* Copyright (c) 2012 HyeonJe Jun (http://github.com/noraesae)
* Licensed under the MIT License
*/(function(e){e.fn.perfectScrollbar=function(t){if(t==="update"){e(this).data("perfect_scrollbar_update")();return}if(t==="destroy"){e(this).data("perfect_scrollbar_destroy")();return}if(e(this).data("perfect_scrollbar"))return;var n=e(this).addClass("ps-container"),r=e(this).children(),i=e("<div class='ps-scrollbar-x'></div>").appendTo(n),s=e("<div class='ps-scrollbar-y'></div>").appendTo(n),o,u,a,f,l,c,h=parseInt(i.css("bottom")),p,d,v=parseInt(s.css("right")),m=function(){var e=parseInt(d*f/u);n.scrollTop(e),i.css({bottom:h-e})},g=function(){var e=parseInt(c*a/o);n.scrollLeft(e),s.css({right:v-e})},y=function(){o=n.width(),u=n.height(),a=r.width(),f=r.height(),o<a?(l=parseInt(o*o/a),c=parseInt(n.scrollLeft()*o/a)):(l=0,c=0),u<f?(p=parseInt(u*u/f),d=parseInt(n.scrollTop()*u/f)):(p=0,scrollbar_y_left=0),i.css({left:c+n.scrollLeft(),bottom:h-n.scrollTop(),width:l}),s.css({top:d+n.scrollTop(),right:v-n.scrollLeft(),height:p})},b=function(e,t){var r=e+t,s=o-l;r<0?c=0:r>s?c=s:c=r,i.css({left:c+n.scrollLeft()})},w=function(e,t){var r=e+t,i=u-p;r<0?d=0:r>i?d=i:d=r,s.css({top:d+n.scrollTop()})},E=function(){var t,n;i.bind("mousedown.perfect-scroll",function(e){n=e.pageX,t=i.position().left,i.addClass("in-scrolling"),e.stopPropagation(),e.preventDefault()}),e(window).bind("mousemove.perfect-scroll",function(e){i.hasClass("in-scrolling")&&(b(t,e.pageX-n),g(),e.stopPropagation(),e.preventDefault())}),e(window).bind("mouseup.perfect-scroll",function(e){i.hasClass("in-scrolling")&&i.removeClass("in-scrolling")})},S=function(){var t,n;s.bind("mousedown.perfect-scroll",function(e){n=e.pageY,t=s.position().top,s.addClass("in-scrolling"),e.stopPropagation(),e.preventDefault()}),e(window).bind("mousemove.perfect-scroll",function(e){s.hasClass("in-scrolling")&&(w(t,e.pageY-n),m(),e.stopPropagation(),e.preventDefault())}),e(window).bind("mouseup.perfect-scroll",function(e){s.hasClass("in-scrolling")&&s.removeClass("in-scrolling")})},x=function(){n.mousewheel(function(e,t,r,i){n.scrollTop(n.scrollTop()-i*10),n.scrollLeft(n.scrollLeft()+r*10),y(),(f>u||a>o)&&e.preventDefault()})},T=function(){i.remove(),s.remove(),n.unbind("mousewheel"),e(window).unbind("mousemove.perfect-scroll"),e(window).unbind("mouseup.perfect-scroll"),n.data("perfect_scrollbar",null),n.data("perfect_scrollbar_update",null),n.data("perfect_scrollbar_destroy",null)},N=function(){y(),E(),S(),n.mousewheel&&x(),n.data("perfect_scrollbar",!0),n.data("perfect_scrollbar_update",y),n.data("perfect_scrollbar_destroy",T)};return N(),n}})(jQuery);

47
package.json Normal file
View File

@@ -0,0 +1,47 @@
{
"name": "perfect-scrollbar",
"version": "0.6.3",
"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"
},
"devDependencies": {
"browserify": "^8.1.1",
"gulp": "^3.8.10",
"gulp-bump": "^0.1.11",
"gulp-connect": "^2.2.0",
"gulp-eslint": "^0.2.0",
"gulp-insert": "^0.4.0",
"gulp-rename": "^1.2.0",
"gulp-rimraf": "^0.1.1",
"gulp-sass": "^1.3.1",
"gulp-uglify": "^1.0.2",
"gulp-zip": "^2.0.2",
"vinyl-transform": "^1.0.0"
},
"scripts": {
"test": "gulp"
},
"license": "MIT"
}

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

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 element.classList;
} else {
return element.className.split(' ');
}
};

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

@@ -0,0 +1,77 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
exports.e = function (tagName, className) {
var element = document.createElement(tagName);
element.className = className;
return element;
};
exports.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;
}
exports.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);
}
}
};
exports.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);
}
}
};
exports.remove = function (element) {
if (typeof element.remove !== 'undefined') {
element.remove();
} else {
if (element.parentNode) {
element.parentNode.removeChild(element);
}
}
};

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,18 @@
/* Copyright (c) 2015 Hyunje Alex Jun and other contributors
* Licensed under the MIT License
*/
'use strict';
module.exports = {
wheelSpeed: 1,
wheelPropagation: false,
swipePropagation: true,
minScrollbarLength: null,
maxScrollbarLength: null,
useBothWheelAxes: false,
useKeyboard: true,
suppressScrollX: false,
suppressScrollY: false,
scrollXMarginOffset: 0,
scrollYMarginOffset: 0
};

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

@@ -0,0 +1,21 @@
/* 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);
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,58 @@
/* 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');
function bindClickRailHandler(element, i) {
function pageOffset(el) {
return el.getBoundingClientRect();
}
var stopPropagation = window.Event.prototype.stopPropagation.bind;
i.event.bind(i.scrollbarY, 'click', stopPropagation);
i.event.bind(i.scrollbarYRail, 'click', function (e) {
var halfOfScrollbarLength = h.toInt(i.scrollbarYHeight / 2);
var positionTop = i.railYRatio * (e.pageY - window.scrollY - pageOffset(i.scrollbarYRail).top - halfOfScrollbarLength);
var maxPositionTop = i.railYRatio * (i.railYHeight - i.scrollbarYHeight);
var positionRatio = positionTop / maxPositionTop;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
element.scrollTop = (i.contentHeight - i.containerHeight) * positionRatio;
updateGeometry(element);
e.stopPropagation();
});
i.event.bind(i.scrollbarX, 'click', stopPropagation);
i.event.bind(i.scrollbarXRail, 'click', function (e) {
var halfOfScrollbarLength = h.toInt(i.scrollbarXWidth / 2);
var positionLeft = i.railXRatio * (e.pageX - window.scrollX - 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;
}
element.scrollLeft = ((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,105 @@
/* 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');
function bindMouseScrollXHandler(element, i) {
var currentLeft = null;
var currentPageX = null;
function updateScrollLeft(deltaX) {
var newLeft = currentLeft + (deltaX * i.railXRatio);
var maxLeft = 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;
element.scrollLeft = 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 = 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)));
element.scrollTop = 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,118 @@
/* 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');
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
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;
}
element.scrollTop = element.scrollTop - deltaY;
element.scrollLeft = 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,144 @@
/* 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');
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) {
// FIXME: this is a quick fix for the select problem in FF and IE.
// If there comes an effective way to deal with the problem,
// this lines should be removed.
if (!h.env.isWebKit && element.querySelector('select:focus')) {
return;
}
var delta = getDeltaFromEvent(e);
var deltaX = delta[0];
var deltaY = delta[1];
if (shouldBeConsumedByTextarea(deltaX, deltaY)) {
return;
}
shouldPrevent = false;
if (!i.settings.useBothWheelAxes) {
// deltaX will only be used for horizontal scrolling and deltaY will
// only be used for vertical scrolling - this is the default
element.scrollTop = element.scrollTop - (deltaY * i.settings.wheelSpeed);
element.scrollLeft = element.scrollLeft + (deltaX * i.settings.wheelSpeed);
} else if (i.scrollbarYActive && !i.scrollbarXActive) {
// only vertical scrollbar is active and useBothWheelAxes option is
// active, so let's scroll vertical bar using both mouse wheel axes
if (deltaY) {
element.scrollTop = element.scrollTop - (deltaY * i.settings.wheelSpeed);
} else {
element.scrollTop = element.scrollTop + (deltaX * i.settings.wheelSpeed);
}
shouldPrevent = true;
} else if (i.scrollbarXActive && !i.scrollbarYActive) {
// useBothWheelAxes and only horizontal bar is active, so use both
// wheel axes for horizontal bar
if (deltaX) {
element.scrollLeft = element.scrollLeft + (deltaX * i.settings.wheelSpeed);
} else {
element.scrollLeft = 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,111 @@
/* 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');
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;
}
element.scrollTop = element.scrollTop + scrollDiff.top;
element.scrollLeft = 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,170 @@
/* 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 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) {
element.scrollTop = element.scrollTop - differenceY;
element.scrollLeft = 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,44 @@
/* 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);
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);
};

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

@@ -0,0 +1,107 @@
/* 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.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.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,107 @@
/* 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');
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;
if (!element.contains(i.scrollbarXRail)) {
d.appendTo(i.scrollbarXRail, element);
}
if (!element.contains(i.scrollbarYRail)) {
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;
i.scrollbarXWidth = 0;
i.scrollbarXLeft = 0;
element.scrollLeft = 0;
}
if (!i.settings.suppressScrollY && i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight) {
i.scrollbarYActive = true;
i.railYHeight = i.containerHeight - i.railYMarginHeight;
i.railYRatio = i.containerHeight / i.railYHeight;
i.scrollbarYHeight = getThumbSize(i, h.toInt(i.railYHeight * i.containerHeight / i.contentHeight));
i.scrollbarYTop = h.toInt(element.scrollTop * (i.railYHeight - i.scrollbarYHeight) / (i.contentHeight - i.containerHeight));
} else {
i.scrollbarYActive = false;
i.scrollbarYHeight = 0;
i.scrollbarYTop = 0;
element.scrollTop = 0;
}
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);
cls[i.scrollbarXActive ? 'add' : 'remove'](element, 'ps-active-x');
cls[i.scrollbarYActive ? 'add' : 'remove'](element, 'ps-active-y');
};

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

@@ -0,0 +1,31 @@
/* 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');
module.exports = function (element) {
var i = instances.get(element);
// 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);
d.css(i.scrollbarXRail, 'display', '');
d.css(i.scrollbarYRail, 'display', '');
};

View File

@@ -1,60 +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;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
opacity: 0;
filter: alpha(opacity = 0);
-webkit-transition: opacity.2s linear;
-moz-transition: opacity .2s linear;
transition: opacity .2s linear;
}
.ps-container:hover .ps-scrollbar-x {
opacity: 0.6;
filter: alpha(opacity = 60);
}
.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;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
opacity: 0;
-webkit-transition: opacity.2s linear;
-moz-transition: opacity .2s linear;
transition: opacity .2s linear;
}
.ps-container:hover .ps-scrollbar-y {
opacity: 0.6;
filter: alpha(opacity = 60);
}
.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,202 +0,0 @@
/* Copyright (c) 2012 HyeonJe Jun (http://github.com/noraesae)
* Licensed under the MIT License
*/
((function($) {
$.fn.perfectScrollbar = function(option) {
if(option === 'update') {
$(this).data('perfect_scrollbar_update')();
return;
}
else if(option === 'destroy') {
$(this).data('perfect_scrollbar_destroy')();
return;
}
if($(this).data('perfect_scrollbar')) {
// if there's already perfect_scrollbar
return;
}
var $this = $(this).addClass('ps-container'),
$content = $(this).children(),
$scrollbar_x = $("<div class='ps-scrollbar-x'></div>").appendTo($this),
$scrollbar_y = $("<div class='ps-scrollbar-y'></div>").appendTo($this),
container_width,
container_height,
content_width,
content_height,
scrollbar_x_width,
scrollbar_x_left,
scrollbar_x_bottom = parseInt($scrollbar_x.css('bottom')),
scrollbar_y_height,
scrollbar_y_top,
scrollbar_y_right = parseInt($scrollbar_y.css('right'));
var updateContentScrollTop = function() {
var scroll_top = parseInt(scrollbar_y_top * content_height / container_height);
$this.scrollTop(scroll_top);
$scrollbar_x.css({bottom: scrollbar_x_bottom - scroll_top});
};
var updateContentScrollLeft = function() {
var scroll_left = parseInt(scrollbar_x_left * content_width / container_width);
$this.scrollLeft(scroll_left);
$scrollbar_y.css({right: scrollbar_y_right - scroll_left});
};
var updateBarSizeAndPosition = function() {
container_width = $this.width();
container_height = $this.height();
content_width = $content.width();
content_height = $content.height();
if(container_width < content_width) {
scrollbar_x_width = parseInt(container_width * container_width / content_width);
scrollbar_x_left = parseInt($this.scrollLeft() * container_width / content_width);
}
else {
scrollbar_x_width = 0;
scrollbar_x_left = 0;
}
if(container_height < content_height) {
scrollbar_y_height = parseInt(container_height * container_height / content_height);
scrollbar_y_top = parseInt($this.scrollTop() * container_height / content_height);
}
else {
scrollbar_y_height = 0;
scrollbar_y_left = 0;
}
$scrollbar_x.css({left: scrollbar_x_left + $this.scrollLeft(), bottom: scrollbar_x_bottom - $this.scrollTop(), width: scrollbar_x_width});
$scrollbar_y.css({top: scrollbar_y_top + $this.scrollTop(), right: scrollbar_y_right - $this.scrollLeft(), height: scrollbar_y_height});
};
var moveBarX = function(current_left, delta_x) {
var new_left = current_left + delta_x,
max_left = container_width - scrollbar_x_width;
if(new_left < 0) {
scrollbar_x_left = 0;
}
else if(new_left > max_left) {
scrollbar_x_left = max_left;
}
else {
scrollbar_x_left = new_left;
}
$scrollbar_x.css({left: scrollbar_x_left + $this.scrollLeft()});
}
var moveBarY = function(current_top, delta_y) {
var new_top = current_top + delta_y,
max_top = container_height - scrollbar_y_height;
if(new_top < 0) {
scrollbar_y_top = 0;
}
else if(new_top > max_top) {
scrollbar_y_top = max_top;
}
else {
scrollbar_y_top = new_top;
}
$scrollbar_y.css({top: scrollbar_y_top + $this.scrollTop()});
};
var bindMouseScrollXHandler = function() {
var current_left,
current_page_x;
$scrollbar_x.bind('mousedown.perfect-scroll', function(e) {
current_page_x = e.pageX;
current_left = $scrollbar_x.position().left;
$scrollbar_x.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(window).bind('mousemove.perfect-scroll', function(e) {
if($scrollbar_x.hasClass('in-scrolling')) {
moveBarX(current_left, e.pageX - current_page_x);
updateContentScrollLeft();
e.stopPropagation();
e.preventDefault();
}
});
$(window).bind('mouseup.perfect-scroll', function(e) {
if($scrollbar_x.hasClass('in-scrolling')) {
$scrollbar_x.removeClass('in-scrolling');
}
});
};
var bindMouseScrollYHandler = function() {
var current_top,
current_page_y;
$scrollbar_y.bind('mousedown.perfect-scroll', function(e) {
current_page_y = e.pageY;
current_top = $scrollbar_y.position().top;
$scrollbar_y.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(window).bind('mousemove.perfect-scroll', function(e) {
if($scrollbar_y.hasClass('in-scrolling')) {
moveBarY(current_top, e.pageY - current_page_y);
updateContentScrollTop();
e.stopPropagation();
e.preventDefault();
}
});
$(window).bind('mouseup.perfect-scroll', function(e) {
if($scrollbar_y.hasClass('in-scrolling')) {
$scrollbar_y.removeClass('in-scrolling');
}
});
};
// bind handlers
var bindMouseWheelHandler = function() {
$this.mousewheel(function(e, delta, deltaX, deltaY) {
$this.scrollTop($this.scrollTop() - (deltaY * 10));
$this.scrollLeft($this.scrollLeft() + (deltaX * 10));
// update bar position
updateBarSizeAndPosition();
if(content_height > container_height || content_width > container_width) {
e.preventDefault();
}
});
};
var destroy = function() {
$scrollbar_x.remove();
$scrollbar_y.remove();
$this.unbind('mousewheel');
$(window).unbind('mousemove.perfect-scroll');
$(window).unbind('mouseup.perfect-scroll');
$this.data('perfect_scrollbar', null);
$this.data('perfect_scrollbar_update', null);
$this.data('perfect_scrollbar_destroy', null);
};
var initialize = function() {
updateBarSizeAndPosition();
bindMouseScrollXHandler();
bindMouseScrollYHandler();
if($this.mousewheel) bindMouseWheelHandler();
$this.data('perfect_scrollbar', true);
$this.data('perfect_scrollbar_update', updateBarSizeAndPosition);
$this.data('perfect_scrollbar_destroy', destroy);
};
// initialize
initialize();
return $this;
};
})(jQuery));