Compare commits

...

155 Commits
0.5.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
59 changed files with 2562 additions and 1383 deletions

View File

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

14
.editorconfig Normal file
View File

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

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

3
.gitignore vendored
View File

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

View File

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

9
.npmignore Normal file
View File

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

View File

@@ -1,5 +1,17 @@
language: node_js
node_js:
- "0.10"
- '0.10'
before_script:
- npm install -g grunt-cli
- 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

View File

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

357
README.md
View File

@@ -1,75 +1,266 @@
perfect-scrollbar [![Travis CI](https://travis-ci.org/noraesae/perfect-scrollbar.svg?branch=master)](https://travis-ci.org/noraesae/perfect-scrollbar)
=================
# `perfect-scrollbar`
Tiny but perfect jQuery scrollbar plugin
Minimalistic but perfect custom scrollbar plugin
Why perfect-scrollbar?
------------------
[![Travis CI](https://travis-ci.org/noraesae/perfect-scrollbar.svg?branch=master)](https://travis-ci.org/noraesae/perfect-scrollbar)
I worked on a personal project recently, and I was trying to find the jQuery scrollbar plugin that's *perfect*. But there was no *perfect* scrollbar plugin. That's why I decided to make one.
If you want information of old versions&lt;0.6.0, please refer to
[an old documentation](https://github.com/noraesae/perfect-scrollbar/tree/0.5.9).
perfect-scrollbar is very tiny but *perfect* (for me, and maybe for the most of developers) jQuery scrollbar plugin.
I hope you love this!
## Why perfect-scrollbar?
Demo: http://noraesae.github.com/perfect-scrollbar/
I was once working on a personal project, and trying to find the jQuery
scrollbar plugin that's *perfect*. But there was no *perfect* one.
That's why I decided to make one.
What does *perfect* mean?
---------------------
perfect-scrollbar is minimalistic but *perfect* (for me, and maybe for most developers)
scrollbar plugin working with jQuery or vanilla JavaScript as well.
I hope you love it!
## [Demo](http://noraesae.github.com/perfect-scrollbar/)
[It's on the GitHub Pages](http://noraesae.github.com/perfect-scrollbar/).
## What does *perfect* mean?
*perfect* means...
* There should be no css change on any original element.
* The scrollbar should not affect the original design layout.
* The design of the scrollbar should be (nearly) fully customizable.
* If the size of the container or the content changes, the scrollbar size and position should be able to change.
* If the size of the container or the content changes, the scrollbar
size and position should be able to change.
* *New!* It should work with vanilla JavaScript and major tools like
NPM or Browserify.
Then perfect-scrollbar is really *perfect*?
-------------------------------------------
## Then perfect-scrollbar is really *perfect*?
Yes! the only thing that's not *perfect* is my English.
* perfect-scrollbar has some requirements, but doesn't change or add any style on original elements.
* perfect-scrollbar is designed not to have width or height. It's fixed on the right and bottom side of the container.
* You can change nearly all css styles of the scrollbar. The scrollbar design has no dependency on scripts.
* perfect-scrollbar support 'update' function. Whenever you need to update the size or position of the scrollbar, just update.
* Additionally, perfect-scrollbar do use 'scrollTop' and 'scrollLeft', not absolute position or something messy.
* perfect-scrollbar has some requirements, but doesn't change or add
any style on original elements.
* perfect-scrollbar is designed not to have width or height. It's fixed
on the right and bottom side of the container.
* You can change nearly all css styles of the scrollbar. The scrollbar
design has no dependency on scripts.
* perfect-scrollbar supports an 'update' function. Whenever you need
to update the size or position of the scrollbar, just update.
* Additionally, perfect-scrollbar uses 'scrollTop' and 'scrollLeft',
not absolute positioning or something messy.
* perfect-scrollbar supports RTL perfectly on both WebKit and Gecko based browsers.
It's cool, isn't it?
Install
-------
## Install
You can download the latest stable version with download links in [Github Page](http://noraesae.github.io/perfect-scrollbar/). You also can find all releases in [Releases](https://github.com/noraesae/perfect-scrollbar/releases) page.
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 can be fixed.
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`.
```
git clone https://github.com/noraesae/perfect-scrollbar.git
cd perfect-scrollbar/src
$ npm install perfect-scrollbar
```
You can use [Bower](http://bower.io/) to install the plugin. The plugin is registered as `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.
```
bower install perfect-scrollbar
$ git clone https://github.com/noraesae/perfect-scrollbar.git
$ cd perfect-scrollbar/src
$ npm install
$ gulp # will lint and build the source code.
```
Requirements
------------
To make this plugin *perfect*, some requirements were not avoidable. But they're all very trivial and there's nothing to worry about.
There is a Bower package for perfect-scrollbar as well. It is managed
under the [perfect-scrollbar-bower](https://github.com/noraesae/perfect-scrollbar-bower)
repository. The plugin is registered as `perfect-scrollbar`.
```
$ bower install perfect-scrollbar
```
You can also load it from [cdnjs](http://cdnjs.com/).
It is registered as [`jquery.perfect-scrollbar`](http://www.cdnjs.com/libraries/jquery.perfect-scrollbar).
## Requirements
To make this plugin *perfect*, some requirements were unavoidable.
But, they're all very trivial and there is nothing to worry about.
The following requirements should meet.
* the container must have a 'position' css style.
The following requirements are included in the basic CSS, but please
keep in mind when you'd like to change the CSS files.
* the container must have an 'overflow:hidden' css style.
* the scrollbar's position must be 'absolute'.
* the scrollbar-x must have a 'bottom' css style, and the scrollbar-y must have a 'right' css style.
* the scrollbar-x must have a 'bottom' css style, and the scrollbar-y
must have a 'right' css style.
The requirement below is for perfect-scrollbar &lt;= 0.3.4
## How to use
* there must be the *one* content element(like div) for the container.
First of all, please check if the container element meets the
requirements.
Optional parameters
-------------------
```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.
@@ -78,10 +269,12 @@ The scroll speed applied to mousewheel event.
**Default: 1**
### wheelPropagation
If this option is true, when the scroll reach the end of the side, mousewheel event will be propagated to parent element.
*Currently not supported for touch events*
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.
@@ -115,62 +308,9 @@ The number of pixels the content width can surpass the container width without e
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**
### includePadding
When set to true, it uses `innerWidth` and `innerHeight` for the container size instead of `width` and `height`. When your container element has non-zero padding and the scrollbar layout looks weird, this option can be helpful.
**Default: false**
## Contribution
How to Use
----------
```html
<style>
#Demo {
position: 'relative';
height: 100%; // Or whatever you want (eg. 400px)
overflow: hidden;
}
</style>
<div id='Demo'>
<div>
...
</div>
</div>
```
When the html document is like above, just use like this:
```javascript
$('#Demo').perfectScrollbar();
```
With optional parameters:
```javascript
$("#Demo").perfectScrollbar({
wheelSpeed: 20,
wheelPropagation: true,
minScrollbarLength: 20
})
```
If the size of your container or content changes:
```javascript
$('#Demo').perfectScrollbar('update');
```
If you want to destory the scrollbar:
```javascript
$('#Demo').perfectScrollbar('destroy');
```
If you want to scroll to somewhere, just use scroll-top css and update.
```javascript
$("#Demo").scrollTop(0);
$("#Demo").perfectScrollbar('update');
```
Also you can get the informations about how to use the plugin from example codes in the `examples` directory of the source tree.
Contribution
------------
#### Please read [Contributing](https://github.com/noraesae/perfect-scrollbar/wiki/Contributing) in the wiki before making any contibution.
#### Please read [Contributing](https://github.com/noraesae/perfect-scrollbar/wiki/Contributing) in the wiki before making any contribution.
I *really* welcome contributions! Please feel free to fork and issue pull requests when...
@@ -179,28 +319,29 @@ I *really* welcome contributions! Please feel free to fork and issue pull reques
* You found a bug!
* You're good at English and can help my bad English!
For IE problems, please refer to [IE Support](https://github.com/noraesae/perfect-scrollbar#ie-support)
For IE problems, please refer to [IE Support](https://github.com/noraesae/perfect-scrollbar#ie-support).
IE Support
----------
## IE Support
This plugin supports old IE browsers in the **minimum** range. The plugin is tested in IEs >= IE6 and works(not well, but works).
The plugin would work in IEs >= IE9 (not well, though).
**But the project will not accept the patches to fix IE problems in IE 6/7/8.**
**The patches to fix problems in IE<=8 won't be accepted.**
From jQuery 2.0, jQuery also will not support IE 6/7/8. I also think that supporting old browsers really breaks the web development conventions.
When old IEs should be supported, please fork the project and
make patches personally.
When old IEs should be supported, please fork the project and make patches personally.
## Helpdesk
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).
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
-------
## License
The MIT License (MIT) Copyright (c) 2012, 2014 Hyeonje Alex Jun and other contributors.
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:

View File

@@ -1,24 +0,0 @@
{
"name": "perfect-scrollbar",
"version": "0.4.11",
"homepage": "http://noraesae.github.io/perfect-scrollbar/",
"authors": [
"Hyeonje Alex Jun <me@noraesae.net>"
],
"description": "Tiny but perfect jQuery scrollbar plugin",
"main": [
"src/perfect-scrollbar.css",
"src/perfect-scrollbar.js"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"jquery": ">=1.10"
}
}

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
h1 { text-align: center; }
.container { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.container .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
</style>
<style>
/* to make scrollbars always visible */
.always-visible.ps-container > .ps-scrollbar-x-rail,
.always-visible.ps-container > .ps-scrollbar-y-rail {
opacity: 0.6;
}
</style>
</head>
<body>
<h1>Default</h1>
<div class="container">
<div class="content">
</div>
</div>
<h1>Always visible</h1>
<div class="container always-visible">
<div class="content">
</div>
</div>
<script>
window.onload = function () {
[].forEach.call(document.querySelectorAll('.container'), function (el) {
Ps.initialize(el);
});
};
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px;}
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
</head>
<body>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
</body>
</html>

22
examples/iframe.html Normal file
View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
#iframe { width: 100%; min-height: 450px; border: 0; }
html { direction: rtl; }
</style>
</head>
<body>
<iframe src="iframe-content.html" id="iframe"></iframe>
<script>
var iframe = document.querySelector('#iframe');
iframe.onload = function () {
Ps.initialize(iframe.contentDocument.querySelector('#Default'))
};
</script>
</body>
</html>

40
examples/jquery.html Normal file
View File

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

View File

@@ -1,27 +1,15 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
});
var updateSize = function () {
var width = parseInt($('#width').val(), 10);
var height = parseInt($('#height').val(), 10);
$('#Default').width(width).height(height).perfectScrollbar('update');
};
</script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
</head>
<body>
<div id="Default" class="contentHolder">
@@ -33,6 +21,20 @@
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

@@ -1,23 +1,15 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 640px; height: 360px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 12800px; height: 7200px; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#LongThumb').perfectScrollbar({minScrollbarLength:100});
});
</script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 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>
@@ -30,5 +22,12 @@
<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

@@ -1,25 +1,16 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
h2 { text-align: center; }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#SuppressScrollX').perfectScrollbar({suppressScrollX: true});
$('#SuppressScrollY').perfectScrollbar({suppressScrollY: true});
});
</script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
h2 { text-align: center; }
</style>
</head>
<body>
<h2>Default</h2>
@@ -37,6 +28,13 @@
<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

@@ -1,25 +1,16 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 640px; height: 360px; overflow: hidden; }
.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>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#CanScrollWithYAxis').perfectScrollbar({useBothWheelAxes: true});
$('#CanScrollWithXAxis').perfectScrollbar({useBothWheelAxes: true});
});
</script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 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>
@@ -37,5 +28,13 @@
<div class="content-y">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#CanScrollWithYAxis'), {useBothWheelAxes: true});
Ps.initialize($('#CanScrollWithXAxis'), {useBothWheelAxes: true});
};
</script>
</body>
</html>

View File

@@ -1,23 +1,15 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#NoWheelPropagation').perfectScrollbar({wheelPropagation:true});
});
</script>
<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>
@@ -26,7 +18,7 @@
</div>
</div>
<h1 style="text-align:center">wheelPropagation:true</h1>
<div id="NoWheelPropagation" class="contentHolder">
<div id="WheelPropagation" class="contentHolder">
<div class="content">
</div>
</div>
@@ -34,6 +26,13 @@
Note<br>that<br>there<br>is<br>plenty<br>of<br>text<br>after<br>the<br>image<br>to<br>ensure<br>that<br>it<br>is<br>possible<br>to<br>down<br>
after<br>the<br>bottom<br>of<br>the<br>image<br>has<br>been<br>reached<br>to<br>enable<br>the<br>wheel<br>propagation<br>to<br>be<br>tested<br>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
Ps.initialize($('#WheelPropagation'), {wheelPropagation: true});
};
</script>
</body>
</html>

View File

@@ -1,24 +1,15 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
$('#FastWheelSpeed').perfectScrollbar({wheelSpeed:10});
$('#SlowWheelSpeed').perfectScrollbar({wheelSpeed:0.1});
});
</script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
</style>
</head>
<body>
<h1 style="text-align:center">Default; wheelSpeed:1</h1>
@@ -36,6 +27,14 @@
<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

@@ -1,41 +1,20 @@
<!DOCTYPE HTML>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
#description {
border: 1px solid gray;
height:150px;
width: 400px;
overflow: hidden;
overflow: auto;
position: relative;
}
#status {
color: red;
}
#status { color: red; }
</style>
<script type="text/javascript">
$(document).ready(function ($) {
var $container = $('#description');
var $status = $('#status');
$container.perfectScrollbar();
$container.scroll(function(e) {
if($container.scrollTop() === 0) {
$status.text('it reaches the top!');
}
else if ($container.scrollTop() === $container.prop('scrollHeight') - $container.height()) {
$status.text('it reaches the end!');
} else {
$status.text('');
}
});
});
</script>
</head>
<body>
<div id="description" class="wrapper">
@@ -52,5 +31,23 @@
</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>

View File

@@ -1,29 +1,28 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
<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>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
});
</script>
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

@@ -1,38 +1,37 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.contentHolder .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.spacer { text-align:center }
<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>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#Default').perfectScrollbar();
});
</script>
/* Change the alignment of scrollbars */
/* Recommended: You can just modify the CSS file directly. */
.ps-container .ps-scrollbar-x-rail {
top: 3px;
bottom: auto; /* If using `top`, there shouldn't be a `bottom`. */
}
.ps-container .ps-scrollbar-y-rail {
left: 3px;
right: auto; /* If using `left`, there shouldn't be a `right`. */
}
</style>
</head>
<body>
<div id="Default" class="contentHolder">
<div class="content">
</div>
</div>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#Default'));
};
</script>
</body>
</html>

View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
h1 { text-align: center; }
.container { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: auto; }
.container .content { background-image: url('./azusa.jpg'); width: 1280px; height: 720px; }
.large-margin .ps-scrollbar-x-rail {
margin: 0 25%;
opacity: 0.5;
background-color: #eee;
}
.large-margin .ps-scrollbar-y-rail {
margin: 100px 0;
opacity: 0.5;
background-color: #eee;
}
</style>
</head>
<body>
<h1>Default</h1>
<div class="container">
<div class="content">
</div>
</div>
<h1>Margins</h1>
<div class="container large-margin">
<div class="content">
</div>
</div>
<script>
window.onload = function () {
[].forEach.call(document.querySelectorAll('.container'), function (el) {
Ps.initialize(el);
});
};
</script>
</body>
</html>

View File

@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
#table {
font-size: 20px;
}
#table thead, #table tbody, #table tr {
display: block;
width: 600px;
border-spacing: 0;
border-collapse: collapse;
}
#table tbody {
height: 100px;
overflow-y: auto;
overflow-x:hidden;
position: relative;
}
#table tbody td, #table thead th {
display: block;
border: 1px solid black;
width: 200px;
float: left;
box-sizing: border-box;
}
</style>
</head>
<body>
<div id="table" class="wrapper">
<table id='table'>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Occupation</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alex</td>
<td>20</td>
<td>Student</td>
</tr>
<tr>
<td>Paul</td>
<td>23</td>
<td>Engineer</td>
</tr>
<tr>
<td>Chris</td>
<td>19</td>
<td>Human being</td>
</tr>
<tr>
<td>Alex</td>
<td>20</td>
<td>Student</td>
</tr>
<tr>
<td>Paul</td>
<td>23</td>
<td>Engineer</td>
</tr>
<tr>
<td>Chris</td>
<td>19</td>
<td>Human being</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#table tbody'));
};
</script>
</body>
</html>

View File

@@ -1,41 +1,57 @@
<!DOCTYPE HTML>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>perfect-scrollbar example</title>
<link href="../src/perfect-scrollbar.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="../src/perfect-scrollbar.js"></script>
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<script src="../dist/js/perfect-scrollbar.js"></script>
<style>
#description {
border: 1px solid gray;
height:150px;
width: 400px;
overflow: hidden;
position: absolute;
overflow: auto;
position: relative;
}
</style>
<script type="text/javascript">
$(document).ready(function ($) {
$('#description').perfectScrollbar();
});
</script>
</head>
<body>
<div id="description" class="wrapper">
<div>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
</div>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
<p>The command takes options applicable</p>
</div>
<button id='redraw'>Redraw</button>
<script>
var $ = document.querySelector.bind(document);
window.onload = function () {
Ps.initialize($('#description'));
};
$('#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,5 +0,0 @@
/*! perfect-scrollbar - v0.5.1
* http://noraesae.github.com/perfect-scrollbar/
* Copyright (c) 2014 Hyeonje Alex Jun; Licensed MIT */
.ps-container .ps-scrollbar-x-rail{position:absolute;bottom:3px;height:8px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;opacity:0;filter:alpha(opacity=0);-o-transition:background-color .2s linear,opacity .2s linear;-webkit-transition:background-color .2s linear,opacity .2s linear;-moz-transition:background-color .2s linear,opacity .2s linear;transition:background-color .2s linear,opacity .2s linear}.ps-container:hover .ps-scrollbar-x-rail,.ps-container.hover .ps-scrollbar-x-rail{opacity:.6;filter:alpha(opacity=60)}.ps-container .ps-scrollbar-x-rail:hover,.ps-container .ps-scrollbar-x-rail.hover{background-color:#eee;opacity:.9;filter:alpha(opacity=90)}.ps-container .ps-scrollbar-x-rail.in-scrolling{background-color:#eee;opacity:.9;filter:alpha(opacity=90)}.ps-container .ps-scrollbar-y-rail{position:absolute;right:3px;width:8px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;opacity:0;filter:alpha(opacity=0);-o-transition:background-color .2s linear,opacity .2s linear;-webkit-transition:background-color .2s linear,opacity .2s linear;-moz-transition:background-color .2s linear,opacity .2s linear;transition:background-color .2s linear,opacity .2s linear}.ps-container:hover .ps-scrollbar-y-rail,.ps-container.hover .ps-scrollbar-y-rail{opacity:.6;filter:alpha(opacity=60)}.ps-container .ps-scrollbar-y-rail:hover,.ps-container .ps-scrollbar-y-rail.hover{background-color:#eee;opacity:.9;filter:alpha(opacity=90)}.ps-container .ps-scrollbar-y-rail.in-scrolling{background-color:#eee;opacity:.9;filter:alpha(opacity=90)}.ps-container .ps-scrollbar-x{position:absolute;bottom:0;height:8px;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-o-transition:background-color .2s linear;-webkit-transition:background-color.2s linear;-moz-transition:background-color .2s linear;transition:background-color .2s linear}.ps-container.ie6 .ps-scrollbar-x{font-size:0}.ps-container .ps-scrollbar-x-rail:hover .ps-scrollbar-x,.ps-container .ps-scrollbar-x-rail.hover .ps-scrollbar-x{background-color:#999}.ps-container .ps-scrollbar-y{position:absolute;right:0;width:8px;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-o-transition:background-color .2s linear;-webkit-transition:background-color.2s linear;-moz-transition:background-color .2s linear;transition:background-color .2s linear}.ps-container.ie6 .ps-scrollbar-y{font-size:0}.ps-container .ps-scrollbar-y-rail:hover .ps-scrollbar-y,.ps-container .ps-scrollbar-y-rail.hover .ps-scrollbar-y{background-color:#999}.ps-container.ie .ps-scrollbar-x,.ps-container.ie .ps-scrollbar-y{visibility:hidden}.ps-container.ie:hover .ps-scrollbar-x,.ps-container.ie:hover .ps-scrollbar-y,.ps-container.ie.hover .ps-scrollbar-x,.ps-container.ie.hover .ps-scrollbar-y{visibility:visible}

File diff suppressed because one or more lines are too long

View File

@@ -1,19 +1,47 @@
{
"name": "perfect-scrollbar",
"version": "0.5.1",
"main": "src/perfect-scrollbar.js",
"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": {
"grunt": "~0.4.1",
"grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-uglify": "~0.1.1",
"grunt-contrib-cssmin": "~0.6.1",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-clean": "~0.4.1"
"browserify": "^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": "grunt travis --verbose"
}
"test": "gulp"
},
"license": "MIT"
}

View File

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

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

@@ -0,0 +1,123 @@
// Colors
$ps-rail-hover: #eee;
$ps-bar-default: #aaa;
$ps-bar-hover: #999;
// Helper mixins
@mixin border-radius($r) {
-webkit-border-radius: $r;
-moz-border-radius: $r;
-ms-border-radius: $r;
border-radius: $r;
}
@mixin transition($t...) {
-webkit-transition: $t;
-moz-transition: $t;
-o-transition: $t;
transition: $t;
}
// Scrollbar mixins
@mixin scrollbar-rail-default {
display: none;
position: absolute; /* please don't change 'position' */
@include border-radius(4px);
opacity: 0;
@include transition(background-color .2s linear, opacity .2s linear);
}
@mixin scrollbar-rail-hover {
background-color: $ps-rail-hover;
opacity: 0.9;
}
@mixin scrollbar-default {
position: absolute; /* please don't change 'position' */
background-color: $ps-bar-default;
@include border-radius(4px);
@include transition(background-color .2s linear);
}
@mixin scrollbar-hover {
background-color: $ps-bar-hover;
}
@mixin in-scrolling {
&.ps-in-scrolling {
pointer-events: none;
&.ps-x>.ps-scrollbar-x-rail{
@include scrollbar-rail-hover;
>.ps-scrollbar-x {
@include scrollbar-hover;
}
}
&.ps-y>.ps-scrollbar-y-rail {
@include scrollbar-rail-hover;
>.ps-scrollbar-y {
@include scrollbar-hover;
}
}
}
}
.ps-container {
-ms-touch-action: none;
overflow: hidden !important;
&.ps-active-x > .ps-scrollbar-x-rail,
&.ps-active-y > .ps-scrollbar-y-rail {
display: block;
}
@include in-scrolling;
>.ps-scrollbar-x-rail {
@include scrollbar-rail-default;
bottom: 3px; /* there must be 'bottom' for ps-scrollbar-x-rail */
height: 8px;
>.ps-scrollbar-x {
@include scrollbar-default;
bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */
height: 8px;
}
}
>.ps-scrollbar-y-rail {
@include scrollbar-rail-default;
right: 3px; /* there must be 'right' for ps-scrollbar-y-rail */
width: 8px;
>.ps-scrollbar-y {
@include scrollbar-default;
right: 0; /* there must be 'right' for ps-scrollbar-y */
width: 8px;
}
}
&:hover {
@include in-scrolling;
>.ps-scrollbar-x-rail,
>.ps-scrollbar-y-rail {
opacity: 0.6;
}
>.ps-scrollbar-x-rail:hover {
@include scrollbar-rail-hover;
>.ps-scrollbar-x {
@include scrollbar-hover;
}
}
>.ps-scrollbar-y-rail:hover {
@include scrollbar-rail-hover;
>.ps-scrollbar-y {
@include scrollbar-hover;
}
}
}
}

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,125 +0,0 @@
.ps-container .ps-scrollbar-x-rail {
position: absolute; /* please don't change 'position' */
bottom: 3px; /* there must be 'bottom' for ps-scrollbar-x-rail */
height: 8px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
opacity: 0;
filter: alpha(opacity=0);
-o-transition: background-color .2s linear, opacity .2s linear;
-webkit-transition: background-color .2s linear, opacity .2s linear;
-moz-transition: background-color .2s linear, opacity .2s linear;
transition: background-color .2s linear, opacity .2s linear;
}
.ps-container:hover .ps-scrollbar-x-rail,
.ps-container.hover .ps-scrollbar-x-rail {
opacity: 0.6;
filter: alpha(opacity=60);
}
.ps-container .ps-scrollbar-x-rail:hover,
.ps-container .ps-scrollbar-x-rail.hover {
background-color: #eee;
opacity: 0.9;
filter: alpha(opacity=90);
}
.ps-container .ps-scrollbar-x-rail.in-scrolling {
background-color: #eee;
opacity: 0.9;
filter: alpha(opacity=90);
}
.ps-container .ps-scrollbar-y-rail {
position: absolute; /* please don't change 'position' */
right: 3px; /* there must be 'right' for ps-scrollbar-y-rail */
width: 8px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
opacity: 0;
filter: alpha(opacity = 0);
-o-transition: background-color .2s linear, opacity .2s linear;
-webkit-transition: background-color .2s linear, opacity .2s linear;
-moz-transition: background-color .2s linear, opacity .2s linear;
transition: background-color .2s linear, opacity .2s linear;
}
.ps-container:hover .ps-scrollbar-y-rail,
.ps-container.hover .ps-scrollbar-y-rail {
opacity: 0.6;
filter: alpha(opacity=60);
}
.ps-container .ps-scrollbar-y-rail:hover,
.ps-container .ps-scrollbar-y-rail.hover {
background-color: #eee;
opacity: 0.9;
filter: alpha(opacity=90);
}
.ps-container .ps-scrollbar-y-rail.in-scrolling {
background-color: #eee;
opacity: 0.9;
filter: alpha(opacity=90);
}
.ps-container .ps-scrollbar-x {
position: absolute; /* please don't change 'position' */
bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */
height: 8px;
background-color: #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-o-transition: background-color .2s linear;
-webkit-transition: background-color.2s linear;
-moz-transition: background-color .2s linear;
transition: background-color .2s linear;
}
.ps-container.ie6 .ps-scrollbar-x {
font-size: 0; /* fixed scrollbar height in xp sp3 ie6 */
}
.ps-container .ps-scrollbar-x-rail:hover .ps-scrollbar-x,
.ps-container .ps-scrollbar-x-rail.hover .ps-scrollbar-x {
background-color: #999;
}
.ps-container .ps-scrollbar-y {
position: absolute; /* please don't change 'position' */
right: 0; /* there must be 'right' for ps-scrollbar-y */
width: 8px;
background-color: #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
-o-transition: background-color .2s linear;
-webkit-transition: background-color.2s linear;
-moz-transition: background-color .2s linear;
transition: background-color .2s linear;
}
.ps-container.ie6 .ps-scrollbar-y {
font-size: 0; /* fixed scrollbar height in xp sp3 ie6 */
}
.ps-container .ps-scrollbar-y-rail:hover .ps-scrollbar-y,
.ps-container .ps-scrollbar-y-rail.hover .ps-scrollbar-y {
background-color: #999;
}
.ps-container.ie .ps-scrollbar-x,
.ps-container.ie .ps-scrollbar-y {
visibility: hidden;
}
.ps-container.ie:hover .ps-scrollbar-x,
.ps-container.ie:hover .ps-scrollbar-y,
.ps-container.ie.hover .ps-scrollbar-x,
.ps-container.ie.hover .ps-scrollbar-y {
visibility: visible;
}

View File

@@ -1,714 +0,0 @@
/* Copyright (c) 2012, 2014 Hyeonje Alex Jun and other contributors
* Licensed under the MIT License
*/
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
'use strict';
// The default settings for the plugin
var defaultSettings = {
wheelSpeed: 1,
wheelPropagation: false,
minScrollbarLength: null,
maxScrollbarLength: null,
useBothWheelAxes: false,
useKeyboard: true,
suppressScrollX: false,
suppressScrollY: false,
scrollXMarginOffset: 0,
scrollYMarginOffset: 0,
includePadding: false
};
var getEventClassName = (function () {
var incrementingId = 0;
return function () {
var id = incrementingId;
incrementingId += 1;
return '.perfect-scrollbar-' + id;
};
}());
$.fn.perfectScrollbar = function (suppliedSettings, option) {
return this.each(function () {
// Use the default settings
var settings = $.extend(true, {}, defaultSettings),
$this = $(this);
if (typeof suppliedSettings === "object") {
// But over-ride any supplied
$.extend(true, settings, suppliedSettings);
} else {
// If no settings were supplied, then the first param must be the option
option = suppliedSettings;
}
// Catch options
if (option === 'update') {
if ($this.data('perfect-scrollbar-update')) {
$this.data('perfect-scrollbar-update')();
}
return $this;
}
else if (option === 'destroy') {
if ($this.data('perfect-scrollbar-destroy')) {
$this.data('perfect-scrollbar-destroy')();
}
return $this;
}
if ($this.data('perfect-scrollbar')) {
// if there's already perfect-scrollbar
return $this.data('perfect-scrollbar');
}
// Or generate new perfectScrollbar
// Set class to the container
$this.addClass('ps-container');
var $scrollbarXRail = $("<div class='ps-scrollbar-x-rail'></div>").appendTo($this),
$scrollbarYRail = $("<div class='ps-scrollbar-y-rail'></div>").appendTo($this),
$scrollbarX = $("<div class='ps-scrollbar-x'></div>").appendTo($scrollbarXRail),
$scrollbarY = $("<div class='ps-scrollbar-y'></div>").appendTo($scrollbarYRail),
scrollbarXActive,
scrollbarYActive,
containerWidth,
containerHeight,
contentWidth,
contentHeight,
scrollbarXWidth,
scrollbarXLeft,
scrollbarXBottom = parseInt($scrollbarXRail.css('bottom'), 10),
isScrollbarXUsingBottom = scrollbarXBottom === scrollbarXBottom, // !isNaN
scrollbarXTop = isScrollbarXUsingBottom ? null : parseInt($scrollbarXRail.css('top'), 10),
scrollbarYHeight,
scrollbarYTop,
scrollbarYRight = parseInt($scrollbarYRail.css('right'), 10),
isScrollbarYUsingRight = scrollbarYRight === scrollbarYRight, // !isNaN
scrollbarYLeft = isScrollbarYUsingRight ? null: parseInt($scrollbarYRail.css('left'), 10),
isRtl = $this.css('direction') === "rtl",
eventClassName = getEventClassName(),
railBorderXWidth = parseInt($scrollbarXRail.css('borderLeftWidth'), 10) + parseInt($scrollbarXRail.css('borderRightWidth'), 10),
railBorderYWidth = parseInt($scrollbarXRail.css('borderTopWidth'), 10) + parseInt($scrollbarXRail.css('borderBottomWidth'), 10);
var updateContentScrollTop = function (currentTop, deltaY) {
var newTop = currentTop + deltaY,
maxTop = containerHeight - scrollbarYHeight;
if (newTop < 0) {
scrollbarYTop = 0;
}
else if (newTop > maxTop) {
scrollbarYTop = maxTop;
}
else {
scrollbarYTop = newTop;
}
var scrollTop = parseInt(scrollbarYTop * (contentHeight - containerHeight) / (containerHeight - scrollbarYHeight), 10);
$this.scrollTop(scrollTop);
};
var updateContentScrollLeft = function (currentLeft, deltaX) {
var newLeft = currentLeft + deltaX,
maxLeft = containerWidth - scrollbarXWidth;
if (newLeft < 0) {
scrollbarXLeft = 0;
}
else if (newLeft > maxLeft) {
scrollbarXLeft = maxLeft;
}
else {
scrollbarXLeft = newLeft;
}
var scrollLeft = parseInt(scrollbarXLeft * (contentWidth - containerWidth) / (containerWidth - scrollbarXWidth), 10);
$this.scrollLeft(scrollLeft);
};
var getSettingsAdjustedThumbSize = function (thumbSize) {
if (settings.minScrollbarLength) {
thumbSize = Math.max(thumbSize, settings.minScrollbarLength);
}
if (settings.maxScrollbarLength) {
thumbSize = Math.min(thumbSize, settings.maxScrollbarLength);
}
return thumbSize;
};
var updateScrollbarCss = function () {
var scrollbarXStyles = {width: containerWidth, display: scrollbarXActive ? "inherit": "none"};
if (isRtl) {
scrollbarXStyles.left = $this.scrollLeft() + containerWidth - contentWidth;
} else {
scrollbarXStyles.left = $this.scrollLeft();
}
if (isScrollbarXUsingBottom) {
scrollbarXStyles.bottom = scrollbarXBottom - $this.scrollTop();
} else {
scrollbarXStyles.top = scrollbarXTop + $this.scrollTop();
}
$scrollbarXRail.css(scrollbarXStyles);
var scrollbarYStyles = {top: $this.scrollTop(), height: containerHeight, display: scrollbarYActive ? "inherit": "none"};
if (isScrollbarYUsingRight) {
if (isRtl) {
scrollbarYStyles.right = contentWidth - $this.scrollLeft() - scrollbarYRight - $scrollbarY.outerWidth();
} else {
scrollbarYStyles.right = scrollbarYRight - $this.scrollLeft();
}
} else {
if (isRtl) {
scrollbarYStyles.left = $this.scrollLeft() + containerWidth * 2 - contentWidth - scrollbarYLeft - $scrollbarY.outerWidth();
} else {
scrollbarYStyles.left = scrollbarYLeft + $this.scrollLeft();
}
}
$scrollbarYRail.css(scrollbarYStyles);
$scrollbarX.css({left: scrollbarXLeft, width: scrollbarXWidth - railBorderXWidth});
$scrollbarY.css({top: scrollbarYTop, height: scrollbarYHeight - railBorderYWidth});
if (scrollbarXActive) {
$this.addClass('ps-active-x');
} else {
$this.removeClass('ps-active-x');
}
if (scrollbarYActive) {
$this.addClass('ps-active-y');
} else {
$this.removeClass('ps-active-y');
}
};
var updateBarSizeAndPosition = function () {
// Hide scrollbars not to affect scrollWidth and scrollHeight
$scrollbarXRail.hide();
$scrollbarYRail.hide();
containerWidth = settings.includePadding ? $this.innerWidth() : $this.width();
containerHeight = settings.includePadding ? $this.innerHeight() : $this.height();
contentWidth = $this.prop('scrollWidth');
contentHeight = $this.prop('scrollHeight');
if (!settings.suppressScrollX && containerWidth + settings.scrollXMarginOffset < contentWidth) {
scrollbarXActive = true;
scrollbarXWidth = getSettingsAdjustedThumbSize(parseInt(containerWidth * containerWidth / contentWidth, 10));
scrollbarXLeft = parseInt($this.scrollLeft() * (containerWidth - scrollbarXWidth) / (contentWidth - containerWidth), 10);
}
else {
scrollbarXActive = false;
scrollbarXWidth = 0;
scrollbarXLeft = 0;
$this.scrollLeft(0);
}
if (!settings.suppressScrollY && containerHeight + settings.scrollYMarginOffset < contentHeight) {
scrollbarYActive = true;
scrollbarYHeight = getSettingsAdjustedThumbSize(parseInt(containerHeight * containerHeight / contentHeight, 10));
scrollbarYTop = parseInt($this.scrollTop() * (containerHeight - scrollbarYHeight) / (contentHeight - containerHeight), 10);
}
else {
scrollbarYActive = false;
scrollbarYHeight = 0;
scrollbarYTop = 0;
$this.scrollTop(0);
}
if (scrollbarYTop >= containerHeight - scrollbarYHeight) {
scrollbarYTop = containerHeight - scrollbarYHeight;
}
if (scrollbarXLeft >= containerWidth - scrollbarXWidth) {
scrollbarXLeft = containerWidth - scrollbarXWidth;
}
updateScrollbarCss();
// Show scrollbars again after updated
$scrollbarXRail.show();
$scrollbarYRail.show();
};
var bindMouseScrollXHandler = function () {
var currentLeft,
currentPageX;
$scrollbarX.bind('mousedown' + eventClassName, function (e) {
currentPageX = e.pageX;
currentLeft = $scrollbarX.position().left;
$scrollbarXRail.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove' + eventClassName, function (e) {
if ($scrollbarXRail.hasClass('in-scrolling')) {
updateContentScrollLeft(currentLeft, e.pageX - currentPageX);
updateBarSizeAndPosition();
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup' + eventClassName, function (e) {
if ($scrollbarXRail.hasClass('in-scrolling')) {
$scrollbarXRail.removeClass('in-scrolling');
}
});
currentLeft =
currentPageX = null;
};
var bindMouseScrollYHandler = function () {
var currentTop,
currentPageY;
$scrollbarY.bind('mousedown' + eventClassName, function (e) {
currentPageY = e.pageY;
currentTop = $scrollbarY.position().top;
$scrollbarYRail.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(document).bind('mousemove' + eventClassName, function (e) {
if ($scrollbarYRail.hasClass('in-scrolling')) {
updateContentScrollTop(currentTop, e.pageY - currentPageY);
updateBarSizeAndPosition();
e.stopPropagation();
e.preventDefault();
}
});
$(document).bind('mouseup' + eventClassName, function (e) {
if ($scrollbarYRail.hasClass('in-scrolling')) {
$scrollbarYRail.removeClass('in-scrolling');
}
});
currentTop =
currentPageY = null;
};
// check if the default scrolling should be prevented.
var shouldPreventDefault = function (deltaX, deltaY) {
var scrollTop = $this.scrollTop();
if (deltaX === 0) {
if (!scrollbarYActive) {
return false;
}
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= contentHeight - containerHeight && deltaY < 0)) {
return !settings.wheelPropagation;
}
}
var scrollLeft = $this.scrollLeft();
if (deltaY === 0) {
if (!scrollbarXActive) {
return false;
}
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= contentWidth - containerWidth && deltaX > 0)) {
return !settings.wheelPropagation;
}
}
return true;
};
// bind handlers
var bindMouseWheelHandler = function () {
var shouldPrevent = false;
var getDeltaFromEvent = function (e) {
var deltaX = e.originalEvent.deltaX,
deltaY = -1 * e.originalEvent.deltaY;
if (typeof deltaX === "undefined" || typeof deltaY === "undefined") {
// OS X Safari
deltaX = -1 * e.originalEvent.wheelDeltaX / 6;
deltaY = e.originalEvent.wheelDeltaY / 6;
}
if (e.originalEvent.deltaMode && e.originalEvent.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.originalEvent.wheelDelta;
}
return [deltaX, deltaY];
};
var mousewheelHandler = function (e) {
var delta = getDeltaFromEvent(e);
var deltaX = delta[0],
deltaY = delta[1];
shouldPrevent = false;
if (!settings.useBothWheelAxes) {
// deltaX will only be used for horizontal scrolling and deltaY will
// only be used for vertical scrolling - this is the default
$this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed));
$this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed));
} else if (scrollbarYActive && !scrollbarXActive) {
// only vertical scrollbar is active and useBothWheelAxes option is
// active, so let's scroll vertical bar using both mouse wheel axes
if (deltaY) {
$this.scrollTop($this.scrollTop() - (deltaY * settings.wheelSpeed));
} else {
$this.scrollTop($this.scrollTop() + (deltaX * settings.wheelSpeed));
}
shouldPrevent = true;
} else if (scrollbarXActive && !scrollbarYActive) {
// useBothWheelAxes and only horizontal bar is active, so use both
// wheel axes for horizontal bar
if (deltaX) {
$this.scrollLeft($this.scrollLeft() + (deltaX * settings.wheelSpeed));
} else {
$this.scrollLeft($this.scrollLeft() - (deltaY * settings.wheelSpeed));
}
shouldPrevent = true;
}
// update bar position
updateBarSizeAndPosition();
shouldPrevent = (shouldPrevent || shouldPreventDefault(deltaX, deltaY));
if (shouldPrevent) {
e.stopPropagation();
e.preventDefault();
}
};
if (typeof window.onwheel !== "undefined") {
$this.bind('wheel' + eventClassName, mousewheelHandler);
} else if (typeof window.onmousewheel !== "undefined") {
$this.bind('mousewheel' + eventClassName, mousewheelHandler);
}
};
var bindKeyboardHandler = function () {
var hovered = false;
$this.bind('mouseenter' + eventClassName, function (e) {
hovered = true;
});
$this.bind('mouseleave' + eventClassName, function (e) {
hovered = false;
});
var shouldPrevent = false;
$(document).bind('keydown' + eventClassName, function (e) {
if (e.isDefaultPrevented && e.isDefaultPrevented()) {
return;
}
if (!hovered || $(document.activeElement).is(":input,[contenteditable]")) {
return;
}
var deltaX = 0,
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
deltaY = -containerHeight;
break;
case 36: // home
deltaY = containerHeight;
break;
default:
return;
}
$this.scrollTop($this.scrollTop() - deltaY);
$this.scrollLeft($this.scrollLeft() + deltaX);
shouldPrevent = shouldPreventDefault(deltaX, deltaY);
if (shouldPrevent) {
e.preventDefault();
}
});
};
var bindRailClickHandler = function () {
var stopPropagation = function (e) { e.stopPropagation(); };
$scrollbarY.bind('click' + eventClassName, stopPropagation);
$scrollbarYRail.bind('click' + eventClassName, function (e) {
var halfOfScrollbarLength = parseInt(scrollbarYHeight / 2, 10),
positionTop = e.pageY - $scrollbarYRail.offset().top - halfOfScrollbarLength,
maxPositionTop = containerHeight - scrollbarYHeight,
positionRatio = positionTop / maxPositionTop;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
$this.scrollTop((contentHeight - containerHeight) * positionRatio);
});
$scrollbarX.bind('click' + eventClassName, stopPropagation);
$scrollbarXRail.bind('click' + eventClassName, function (e) {
var halfOfScrollbarLength = parseInt(scrollbarXWidth / 2, 10),
positionLeft = e.pageX - $scrollbarXRail.offset().left - halfOfScrollbarLength,
maxPositionLeft = containerWidth - scrollbarXWidth,
positionRatio = positionLeft / maxPositionLeft;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
$this.scrollLeft((contentWidth - containerWidth) * positionRatio);
});
};
// bind mobile touch handler
var bindMobileTouchHandler = function () {
var applyTouchMove = function (differenceX, differenceY) {
$this.scrollTop($this.scrollTop() - differenceY);
$this.scrollLeft($this.scrollLeft() - differenceX);
// update bar position
updateBarSizeAndPosition();
};
var startCoords = {},
startTime = 0,
speed = {},
breakingProcess = null,
inGlobalTouch = false;
$(window).bind("touchstart" + eventClassName, function (e) {
inGlobalTouch = true;
});
$(window).bind("touchend" + eventClassName, function (e) {
inGlobalTouch = false;
});
$this.bind("touchstart" + eventClassName, function (e) {
var touch = e.originalEvent.targetTouches[0];
startCoords.pageX = touch.pageX;
startCoords.pageY = touch.pageY;
startTime = (new Date()).getTime();
if (breakingProcess !== null) {
clearInterval(breakingProcess);
}
e.stopPropagation();
});
$this.bind("touchmove" + eventClassName, function (e) {
if (!inGlobalTouch && e.originalEvent.targetTouches.length === 1) {
var touch = e.originalEvent.targetTouches[0];
var currentCoords = {};
currentCoords.pageX = touch.pageX;
currentCoords.pageY = touch.pageY;
var differenceX = currentCoords.pageX - startCoords.pageX,
differenceY = currentCoords.pageY - startCoords.pageY;
applyTouchMove(differenceX, differenceY);
startCoords = currentCoords;
var currentTime = (new Date()).getTime();
var timeGap = currentTime - startTime;
if (timeGap > 0) {
speed.x = differenceX / timeGap;
speed.y = differenceY / timeGap;
startTime = currentTime;
}
e.preventDefault();
}
});
$this.bind("touchend" + eventClassName, function (e) {
clearInterval(breakingProcess);
breakingProcess = setInterval(function () {
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
clearInterval(breakingProcess);
return;
}
applyTouchMove(speed.x * 30, speed.y * 30);
speed.x *= 0.8;
speed.y *= 0.8;
}, 10);
});
};
var bindScrollHandler = function () {
$this.bind('scroll' + eventClassName, function (e) {
updateBarSizeAndPosition();
});
};
var destroy = function () {
$this.unbind(eventClassName);
$(window).unbind(eventClassName);
$(document).unbind(eventClassName);
$this.data('perfect-scrollbar', null);
$this.data('perfect-scrollbar-update', null);
$this.data('perfect-scrollbar-destroy', null);
$scrollbarX.remove();
$scrollbarY.remove();
$scrollbarXRail.remove();
$scrollbarYRail.remove();
// clean all variables
$scrollbarXRail =
$scrollbarYRail =
$scrollbarX =
$scrollbarY =
scrollbarXActive =
scrollbarYActive =
containerWidth =
containerHeight =
contentWidth =
contentHeight =
scrollbarXWidth =
scrollbarXLeft =
scrollbarXBottom =
isScrollbarXUsingBottom =
scrollbarXTop =
scrollbarYHeight =
scrollbarYTop =
scrollbarYRight =
isScrollbarYUsingRight =
scrollbarYLeft =
isRtl =
eventClassName = null;
};
var ieSupport = function (version) {
$this.addClass('ie').addClass('ie' + version);
var bindHoverHandlers = function () {
var mouseenter = function () {
$(this).addClass('hover');
};
var mouseleave = function () {
$(this).removeClass('hover');
};
$this.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave);
$scrollbarXRail.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave);
$scrollbarYRail.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave);
$scrollbarX.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave);
$scrollbarY.bind('mouseenter' + eventClassName, mouseenter).bind('mouseleave' + eventClassName, mouseleave);
};
var fixIe6ScrollbarPosition = function () {
updateScrollbarCss = function () {
var scrollbarXStyles = {left: scrollbarXLeft + $this.scrollLeft(), width: scrollbarXWidth};
if (isScrollbarXUsingBottom) {
scrollbarXStyles.bottom = scrollbarXBottom;
} else {
scrollbarXStyles.top = scrollbarXTop;
}
$scrollbarX.css(scrollbarXStyles);
var scrollbarYStyles = {top: scrollbarYTop + $this.scrollTop(), height: scrollbarYHeight};
if (isScrollbarYUsingRight) {
scrollbarYStyles.right = scrollbarYRight;
} else {
scrollbarYStyles.left = scrollbarYLeft;
}
$scrollbarY.css(scrollbarYStyles);
$scrollbarX.hide().show();
$scrollbarY.hide().show();
};
};
if (version === 6) {
bindHoverHandlers();
fixIe6ScrollbarPosition();
}
};
var supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
var initialize = function () {
var ieMatch = navigator.userAgent.toLowerCase().match(/(msie) ([\w.]+)/);
if (ieMatch && ieMatch[1] === 'msie') {
// must be executed at first, because 'ieSupport' may addClass to the container
ieSupport(parseInt(ieMatch[2], 10));
}
updateBarSizeAndPosition();
bindScrollHandler();
bindMouseScrollXHandler();
bindMouseScrollYHandler();
bindRailClickHandler();
bindMouseWheelHandler();
if (supportsTouch) {
bindMobileTouchHandler();
}
if (settings.useKeyboard) {
bindKeyboardHandler();
}
$this.data('perfect-scrollbar', $this);
$this.data('perfect-scrollbar-update', updateBarSizeAndPosition);
$this.data('perfect-scrollbar-destroy', destroy);
};
// initialize
initialize();
return $this;
});
};
}));