Compare commits

...

111 Commits
0.5.7 ... 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
59 changed files with 2390 additions and 1554 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" : false,
"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,86 +0,0 @@
'use strict';
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('perfect-scrollbar.jquery.json'),
banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.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'
}
},
cssmin: {
options: {
banner: '<%= banner %>'
},
minify: {
expand: true,
cwd: 'src/',
src: ['perfect-scrollbar.css'],
dest: 'min/',
ext: '.min.css'
}
},
bump: {
options: {
files: ['package.json', 'bower.json', 'perfect-scrollbar.jquery.json'],
updateConfigs: ['pkg'],
commit: false,
createTag: false,
push: false
}
},
sass: {
dist: {
files: {
'src/perfect-scrollbar.css': 'src/perfect-scrollbar.scss'
}
}
}
});
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']);
grunt.registerTask('build', ['clean', 'uglify', 'sass', 'cssmin']);
grunt.registerTask('travis', ['lint']);
grunt.registerTask('release', 'Release a new version', function (arg) {
var bumpType = arg ? ':' + arg : '';
grunt.task.run(['lint', 'bump' + bumpType, 'build']);
});
};

365
README.md
View File

@@ -1,83 +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
-------
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.
```
$ git clone https://github.com/noraesae/perfect-scrollbar.git
$ cd perfect-scrollbar/src
```
You can use [Bower](http://bower.io/) to install the plugin. The plugin is registered as `perfect-scrollbar`.
```
$ bower install perfect-scrollbar
```
## Install
The best way to install and use perfect-scrollbar is with NPM.
It's registered on [npm](https://www.npmjs.org/package/perfect-scrollbar) as `perfect-scrollbar`.
```
$ npm install perfect-scrollbar
```
You can also load it from [cdnjs](http://cdnjs.com/). It is registered as [`jquery.perfect-scrollbar`](http://www.cdnjs.com/libraries/jquery.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).
Requirements
------------
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.
To make this plugin *perfect*, some requirements were not avoidable. But they're all very trivial and there's nothing to worry about.
```
$ git clone https://github.com/noraesae/perfect-scrollbar.git
$ cd perfect-scrollbar/src
$ npm install
$ gulp # will lint and build the source code.
```
There is a Bower package for perfect-scrollbar as well. It is managed
under the [perfect-scrollbar-bower](https://github.com/noraesae/perfect-scrollbar-bower)
repository. The plugin is registered as `perfect-scrollbar`.
```
$ bower install perfect-scrollbar
```
You can also load it from [cdnjs](http://cdnjs.com/).
It is registered as [`jquery.perfect-scrollbar`](http://www.cdnjs.com/libraries/jquery.perfect-scrollbar).
## Requirements
To make this plugin *perfect*, some requirements were unavoidable.
But, they're all very trivial and there is nothing to worry about.
The following requirements should meet.
* the container must have a 'position' css style.
The following requirements are included in the basic CSS, but please
keep in mind when you'd like to change the CSS files.
* the container must have an 'overflow:hidden' css style.
* the scrollbar's position must be 'absolute'.
* the scrollbar-x must have a 'bottom' css style, and the scrollbar-y must have a 'right' css style.
* the scrollbar-x must have a 'bottom' css style, and the scrollbar-y
must have a 'right' css style.
The requirement below is for perfect-scrollbar &lt;= 0.3.4
## How to use
* there must be the *one* content element(like div) for the container.
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.
@@ -86,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.
@@ -123,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...
@@ -187,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
The plugin would work in IEs >= IE9(not well, though).
The plugin would work in IEs >= IE9 (not well, though).
**The patches to fix problems in IE<=8 won't be accepted.**
When old IEs should be supported, please fork the project and make patches personally.
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 the problems frequently asked, there's a [FAQ](https://github.com/noraesae/perfect-scrollbar/wiki/FAQ) wiki page. Please check the page before uploading an issue.
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 Hyunje 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.5.7",
"homepage": "http://noraesae.github.io/perfect-scrollbar/",
"authors": [
"Hyunje 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

@@ -1,11 +1,11 @@
<!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">
<link href="../dist/css/perfect-scrollbar.css" rel="stylesheet">
<style>
.contentHolder { position:relative; margin:0px auto; padding:0px; width: 600px; height: 400px; overflow: hidden; }
.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>

View File

@@ -1,27 +1,22 @@
<!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>
#iframe { width: 100%; min-height: 450px; border: 0; }
html { direction: rtl; }
</style>
<script>
jQuery(document).ready(function ($) {
"use strict";
$('#iframe').load(function() {
var contentIframe = $(this).contents();
var documentIframe = contentIframe.get(0);
$('#Default', documentIframe).perfectScrollbar();
});
});
</script>
<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

@@ -1,18 +1,16 @@
<!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>
#test {
border: 1px solid gray;
max-height: 300px;
width: 400px;
overflow: hidden;
overflow: auto;
position: relative;
}
#test .element {
@@ -22,16 +20,6 @@
line-height: 44px;
}
</style>
<script type="text/javascript">
$(document).ready(function ($) {
var test = $('#test');
test.perfectScrollbar();
test.find('a').click(function () {
$(this).parent().remove();
test.perfectScrollbar('update');
});
});
</script>
</head>
<body>
<div id="test" class="wrapper">
@@ -48,5 +36,18 @@
<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.7
* http://noraesae.github.com/perfect-scrollbar/
* Copyright (c) 2014 Hyunje Alex Jun; Licensed MIT */
.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;opacity:0;-ms-filter:"alpha(Opacity=0)";filter:alpha(opacity=0);-webkit-transition:background-color .2s linear,opacity .2s linear;-moz-transition:background-color .2s linear,opacity .2s linear;-o-transition:background-color .2s linear,opacity .2s linear;transition:background-color .2s linear,opacity .2s linear;bottom:3px;height:8px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;-webkit-transition:background-color .2s linear;-moz-transition:background-color .2s linear;-o-transition:background-color .2s linear;transition:background-color .2s linear;bottom:0;height:8px}.ps-container>.ps-scrollbar-x-rail.in-scrolling{background-color:#eee;opacity:.9;-ms-filter:"alpha(Opacity=90)";filter:alpha(opacity=90)}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;opacity:0;-ms-filter:"alpha(Opacity=0)";filter:alpha(opacity=0);-webkit-transition:background-color .2s linear,opacity .2s linear;-moz-transition:background-color .2s linear,opacity .2s linear;-o-transition:background-color .2s linear,opacity .2s linear;transition:background-color .2s linear,opacity .2s linear;right:3px;width:8px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:4px;-moz-border-radius:4px;-ms-border-radius:4px;border-radius:4px;-webkit-transition:background-color .2s linear;-moz-transition:background-color .2s linear;-o-transition:background-color .2s linear;transition:background-color .2s linear;right:0;width:8px}.ps-container>.ps-scrollbar-y-rail.in-scrolling{background-color:#eee;opacity:.9;-ms-filter:"alpha(Opacity=90)";filter:alpha(opacity=90)}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:.6;-ms-filter:"alpha(Opacity=60)";filter:alpha(opacity=60)}.ps-container:hover>.ps-scrollbar-x-rail.in-scrolling,.ps-container:hover>.ps-scrollbar-y-rail.in-scrolling{background-color:#eee;opacity:.9;-ms-filter:"alpha(Opacity=90)";filter:alpha(opacity=90)}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:.9;-ms-filter:"alpha(Opacity=90)";filter:alpha(opacity=90)}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:.9;-ms-filter:"alpha(Opacity=90)";filter:alpha(opacity=90)}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999}

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
{
"name": "perfect-scrollbar",
"version": "0.5.7",
"description": "Tiny but perfect jquery scrollbar plugin.",
"version": "0.6.3",
"description": "Minimalistic but perfect custom scrollbar plugin",
"author": "Hyunje Alex Jun <me@noraesae.net>",
"contributors": [
{
@@ -9,7 +9,7 @@
"email": "me@noraesae.net"
}
],
"main": "src/perfect-scrollbar.js",
"main": "./index.js",
"repository": {
"type": "git",
"url": "https://github.com/noraesae/perfect-scrollbar"
@@ -19,6 +19,7 @@
},
"keywords": [
"jquery-plugin",
"frontend",
"scroll",
"scrollbar"
],
@@ -26,18 +27,21 @@
"node": ">= 0.8.0"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-bump": "0.0.16",
"grunt-contrib-clean": "~0.4.1",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-cssmin": "~0.6.1",
"grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-uglify": "~0.1.1",
"grunt-sass": "^0.16.1",
"load-grunt-tasks": "^1.0.0"
"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.7",
"author": {
"name": "Hyunje 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": "Hyunje Alex Jun",
"email": "me@noraesae.net",
"url": "https://github.com/noraesae/"
}
]
}

View File

@@ -1,11 +1,9 @@
// Helper mixins
@mixin opacity($o) {
$IEValue: $o * 100;
opacity: $o;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity="+$IEValue+")";
filter: alpha(opacity=$IEValue);
}
// 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;
@@ -25,38 +23,55 @@
display: none;
position: absolute; /* please don't change 'position' */
@include border-radius(4px);
@include opacity(0);
opacity: 0;
@include transition(background-color .2s linear, opacity .2s linear);
}
@mixin scrollbar-rail-hover {
background-color: #eee;
@include opacity(0.9);
background-color: $ps-rail-hover;
opacity: 0.9;
}
@mixin scrollbar-default {
position: absolute; /* please don't change 'position' */
background-color: #aaa;
background-color: $ps-bar-default;
@include border-radius(4px);
@include transition(background-color .2s linear);
}
@mixin scrollbar-hover {
background-color: #999;
background-color: $ps-bar-hover;
}
@mixin in-scrolling {
&.in-scrolling {
@include scrollbar-rail-hover;
&.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 */
@@ -67,8 +82,6 @@
bottom: 0; /* there must be 'bottom' for ps-scrollbar-x */
height: 8px;
}
@include in-scrolling;
}
>.ps-scrollbar-y-rail {
@@ -81,15 +94,14 @@
right: 0; /* there must be 'right' for ps-scrollbar-y */
width: 8px;
}
@include in-scrolling;
}
&:hover {
@include in-scrolling;
>.ps-scrollbar-x-rail,
>.ps-scrollbar-y-rail {
@include opacity(0.6);
@include in-scrolling;
opacity: 0.6;
}
>.ps-scrollbar-x-rail: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,101 +0,0 @@
.ps-container.ps-active-x > .ps-scrollbar-x-rail, .ps-container.ps-active-y > .ps-scrollbar-y-rail {
display: block; }
.ps-container > .ps-scrollbar-x-rail {
display: none;
position: absolute;
/* please don't change 'position' */
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
border-radius: 4px;
opacity: 0;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
-webkit-transition: background-color 0.2s linear, opacity 0.2s linear;
-moz-transition: background-color 0.2s linear, opacity 0.2s linear;
-o-transition: background-color 0.2s linear, opacity 0.2s linear;
transition: background-color 0.2s linear, opacity 0.2s linear;
bottom: 3px;
/* there must be 'bottom' for ps-scrollbar-x-rail */
height: 8px; }
.ps-container > .ps-scrollbar-x-rail > .ps-scrollbar-x {
position: absolute;
/* please don't change 'position' */
background-color: #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
border-radius: 4px;
-webkit-transition: background-color 0.2s linear;
-moz-transition: background-color 0.2s linear;
-o-transition: background-color 0.2s linear;
transition: background-color 0.2s linear;
bottom: 0;
/* there must be 'bottom' for ps-scrollbar-x */
height: 8px; }
.ps-container > .ps-scrollbar-x-rail.in-scrolling {
background-color: #eee;
opacity: 0.9;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
filter: alpha(opacity=90); }
.ps-container > .ps-scrollbar-y-rail {
display: none;
position: absolute;
/* please don't change 'position' */
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
border-radius: 4px;
opacity: 0;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
-webkit-transition: background-color 0.2s linear, opacity 0.2s linear;
-moz-transition: background-color 0.2s linear, opacity 0.2s linear;
-o-transition: background-color 0.2s linear, opacity 0.2s linear;
transition: background-color 0.2s linear, opacity 0.2s linear;
right: 3px;
/* there must be 'right' for ps-scrollbar-y-rail */
width: 8px; }
.ps-container > .ps-scrollbar-y-rail > .ps-scrollbar-y {
position: absolute;
/* please don't change 'position' */
background-color: #aaa;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
border-radius: 4px;
-webkit-transition: background-color 0.2s linear;
-moz-transition: background-color 0.2s linear;
-o-transition: background-color 0.2s linear;
transition: background-color 0.2s linear;
right: 0;
/* there must be 'right' for ps-scrollbar-y */
width: 8px; }
.ps-container > .ps-scrollbar-y-rail.in-scrolling {
background-color: #eee;
opacity: 0.9;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
filter: alpha(opacity=90); }
.ps-container:hover > .ps-scrollbar-x-rail, .ps-container:hover > .ps-scrollbar-y-rail {
opacity: 0.6;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";
filter: alpha(opacity=60); }
.ps-container:hover > .ps-scrollbar-x-rail.in-scrolling, .ps-container:hover > .ps-scrollbar-y-rail.in-scrolling {
background-color: #eee;
opacity: 0.9;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
filter: alpha(opacity=90); }
.ps-container:hover > .ps-scrollbar-x-rail:hover {
background-color: #eee;
opacity: 0.9;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
filter: alpha(opacity=90); }
.ps-container:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x {
background-color: #999; }
.ps-container:hover > .ps-scrollbar-y-rail:hover {
background-color: #eee;
opacity: 0.9;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=90)";
filter: alpha(opacity=90); }
.ps-container:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y {
background-color: #999; }

View File

@@ -1,836 +0,0 @@
/* Copyright (c) 2012, 2014 Hyunje 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';
function int(x) {
if (typeof x === 'string') {
return parseInt(x, 10);
} else {
return ~~x;
}
}
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 incrementingId = 0;
var eventClassFactory = function () {
var id = incrementingId++;
return function (eventName) {
var className = '.perfect-scrollbar-' + id;
if (typeof eventName === 'undefined') {
return className;
} else {
return eventName + className;
}
};
};
$.fn.perfectScrollbar = function (suppliedSettings, option) {
return this.each(function () {
var settings = $.extend(true, {}, defaultSettings);
var $this = $(this);
var isPluginAlive = function () { return !!$this; };
if (typeof suppliedSettings === "object") {
// Override default settings with any supplied
$.extend(true, settings, suppliedSettings);
} else {
// If no setting was 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
$this.addClass('ps-container');
var containerWidth;
var containerHeight;
var contentWidth;
var contentHeight;
var isRtl = $this.css('direction') === "rtl";
var eventClass = eventClassFactory();
var ownerDocument = this.ownerDocument || document;
var $scrollbarXRail = $("<div class='ps-scrollbar-x-rail'>").appendTo($this);
var $scrollbarX = $("<div class='ps-scrollbar-x'>").appendTo($scrollbarXRail);
var scrollbarXActive;
var scrollbarXWidth;
var scrollbarXLeft;
var scrollbarXBottom = int($scrollbarXRail.css('bottom'));
var isScrollbarXUsingBottom = scrollbarXBottom === scrollbarXBottom; // !isNaN
var scrollbarXTop = isScrollbarXUsingBottom ? null : int($scrollbarXRail.css('top'));
var railBorderXWidth = int($scrollbarXRail.css('borderLeftWidth')) + int($scrollbarXRail.css('borderRightWidth'));
var $scrollbarYRail = $("<div class='ps-scrollbar-y-rail'>").appendTo($this);
var $scrollbarY = $("<div class='ps-scrollbar-y'>").appendTo($scrollbarYRail);
var scrollbarYActive;
var scrollbarYHeight;
var scrollbarYTop;
var scrollbarYRight = int($scrollbarYRail.css('right'));
var isScrollbarYUsingRight = scrollbarYRight === scrollbarYRight; // !isNaN
var scrollbarYLeft = isScrollbarYUsingRight ? null : int($scrollbarYRail.css('left'));
var railBorderYWidth = int($scrollbarYRail.css('borderTopWidth')) + int($scrollbarYRail.css('borderBottomWidth'));
function updateScrollTop(currentTop, deltaY) {
var newTop = currentTop + deltaY;
var maxTop = containerHeight - scrollbarYHeight;
if (newTop < 0) {
scrollbarYTop = 0;
} else if (newTop > maxTop) {
scrollbarYTop = maxTop;
} else {
scrollbarYTop = newTop;
}
var scrollTop = int(scrollbarYTop * (contentHeight - containerHeight) / (containerHeight - scrollbarYHeight));
$this.scrollTop(scrollTop);
}
function updateScrollLeft(currentLeft, deltaX) {
var newLeft = currentLeft + deltaX;
var maxLeft = containerWidth - scrollbarXWidth;
if (newLeft < 0) {
scrollbarXLeft = 0;
} else if (newLeft > maxLeft) {
scrollbarXLeft = maxLeft;
} else {
scrollbarXLeft = newLeft;
}
var scrollLeft = int(scrollbarXLeft * (contentWidth - containerWidth) / (containerWidth - scrollbarXWidth));
$this.scrollLeft(scrollLeft);
}
function getThumbSize(thumbSize) {
if (settings.minScrollbarLength) {
thumbSize = Math.max(thumbSize, settings.minScrollbarLength);
}
if (settings.maxScrollbarLength) {
thumbSize = Math.min(thumbSize, settings.maxScrollbarLength);
}
return thumbSize;
}
function updateCss() {
var xRailOffset = {width: containerWidth};
if (isRtl) {
xRailOffset.left = $this.scrollLeft() + containerWidth - contentWidth;
} else {
xRailOffset.left = $this.scrollLeft();
}
if (isScrollbarXUsingBottom) {
xRailOffset.bottom = scrollbarXBottom - $this.scrollTop();
} else {
xRailOffset.top = scrollbarXTop + $this.scrollTop();
}
$scrollbarXRail.css(xRailOffset);
var railYOffset = {top: $this.scrollTop(), height: containerHeight};
if (isScrollbarYUsingRight) {
if (isRtl) {
railYOffset.right = contentWidth - $this.scrollLeft() - scrollbarYRight - $scrollbarY.outerWidth();
} else {
railYOffset.right = scrollbarYRight - $this.scrollLeft();
}
} else {
if (isRtl) {
railYOffset.left = $this.scrollLeft() + containerWidth * 2 - contentWidth - scrollbarYLeft - $scrollbarY.outerWidth();
} else {
railYOffset.left = scrollbarYLeft + $this.scrollLeft();
}
}
$scrollbarYRail.css(railYOffset);
$scrollbarX.css({left: scrollbarXLeft, width: scrollbarXWidth - railBorderXWidth});
$scrollbarY.css({top: scrollbarYTop, height: scrollbarYHeight - railBorderYWidth});
}
function updateGeometry() {
// Hide scrollbars not to affect scrollWidth and scrollHeight
$this.removeClass('ps-active-x');
$this.removeClass('ps-active-y');
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 = getThumbSize(int(containerWidth * containerWidth / contentWidth));
scrollbarXLeft = int($this.scrollLeft() * (containerWidth - scrollbarXWidth) / (contentWidth - containerWidth));
} else {
scrollbarXActive = false;
scrollbarXWidth = 0;
scrollbarXLeft = 0;
$this.scrollLeft(0);
}
if (!settings.suppressScrollY && containerHeight + settings.scrollYMarginOffset < contentHeight) {
scrollbarYActive = true;
scrollbarYHeight = getThumbSize(int(containerHeight * containerHeight / contentHeight));
scrollbarYTop = int($this.scrollTop() * (containerHeight - scrollbarYHeight) / (contentHeight - containerHeight));
} else {
scrollbarYActive = false;
scrollbarYHeight = 0;
scrollbarYTop = 0;
$this.scrollTop(0);
}
if (scrollbarXLeft >= containerWidth - scrollbarXWidth) {
scrollbarXLeft = containerWidth - scrollbarXWidth;
}
if (scrollbarYTop >= containerHeight - scrollbarYHeight) {
scrollbarYTop = containerHeight - scrollbarYHeight;
}
updateCss();
if (scrollbarXActive) {
$this.addClass('ps-active-x');
}
if (scrollbarYActive) {
$this.addClass('ps-active-y');
}
}
function bindMouseScrollXHandler() {
var currentLeft;
var currentPageX;
var inScrolling = false;
$scrollbarX.bind(eventClass('mousedown'), function (e) {
currentPageX = e.pageX;
currentLeft = $scrollbarX.position().left;
$scrollbarXRail.addClass('in-scrolling');
inScrolling = true;
e.stopPropagation();
e.preventDefault();
});
$(ownerDocument).bind(eventClass('mousemove'), function (e) {
if (inScrolling) {
updateScrollLeft(currentLeft, e.pageX - currentPageX);
updateGeometry();
e.stopPropagation();
e.preventDefault();
}
});
$(ownerDocument).bind(eventClass('mouseup'), function (e) {
if (inScrolling) {
inScrolling = false;
$scrollbarXRail.removeClass('in-scrolling');
}
});
currentLeft =
currentPageX = null;
}
function bindMouseScrollYHandler() {
var currentTop;
var currentPageY;
var inScrolling = false;
$scrollbarY.bind(eventClass('mousedown'), function (e) {
currentPageY = e.pageY;
currentTop = $scrollbarY.position().top;
inScrolling = true;
$scrollbarYRail.addClass('in-scrolling');
e.stopPropagation();
e.preventDefault();
});
$(ownerDocument).bind(eventClass('mousemove'), function (e) {
if (inScrolling) {
updateScrollTop(currentTop, e.pageY - currentPageY);
updateGeometry();
e.stopPropagation();
e.preventDefault();
}
});
$(ownerDocument).bind(eventClass('mouseup'), function (e) {
if (inScrolling) {
inScrolling = false;
$scrollbarYRail.removeClass('in-scrolling');
}
});
currentTop =
currentPageY = null;
}
// check if the default scrolling should be prevented.
function shouldPreventDefault(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;
}
function bindMouseWheelHandler() {
var shouldPrevent = false;
function getDeltaFromEvent(e) {
var deltaX = e.originalEvent.deltaX;
var 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];
}
function mousewheelHandler(e) {
var delta = getDeltaFromEvent(e);
var deltaX = delta[0];
var 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;
}
updateGeometry();
shouldPrevent = (shouldPrevent || shouldPreventDefault(deltaX, deltaY));
if (shouldPrevent) {
e.stopPropagation();
e.preventDefault();
}
}
if (typeof window.onwheel !== "undefined") {
$this.bind(eventClass('wheel'), mousewheelHandler);
} else if (typeof window.onmousewheel !== "undefined") {
$this.bind(eventClass('mousewheel'), mousewheelHandler);
}
}
function bindKeyboardHandler() {
var hovered = false;
$this.bind(eventClass('mouseenter'), function (e) {
hovered = true;
});
$this.bind(eventClass('mouseleave'), function (e) {
hovered = false;
});
var shouldPrevent = false;
$(ownerDocument).bind(eventClass('keydown'), function (e) {
if (e.isDefaultPrevented && e.isDefaultPrevented()) {
return;
}
if (!hovered) {
return;
}
var activeElement = document.activeElement ? document.activeElement : ownerDocument.activeElement;
// go deeper if element is a webcomponent
while (activeElement.shadowRoot) {
activeElement = activeElement.shadowRoot.activeElement;
}
if ($(activeElement).is(":input,[contenteditable]")) {
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 = -contentHeight;
} else {
deltaY = -containerHeight;
}
break;
case 36: // home
if (e.ctrlKey) {
deltaY = $this.scrollTop();
} else {
deltaY = containerHeight;
}
break;
default:
return;
}
$this.scrollTop($this.scrollTop() - deltaY);
$this.scrollLeft($this.scrollLeft() + deltaX);
shouldPrevent = shouldPreventDefault(deltaX, deltaY);
if (shouldPrevent) {
e.preventDefault();
}
});
}
function bindRailClickHandler() {
function stopPropagation(e) { e.stopPropagation(); }
$scrollbarY.bind(eventClass('click'), stopPropagation);
$scrollbarYRail.bind(eventClass('click'), function (e) {
var halfOfScrollbarLength = int(scrollbarYHeight / 2);
var positionTop = e.pageY - $scrollbarYRail.offset().top - halfOfScrollbarLength;
var maxPositionTop = containerHeight - scrollbarYHeight;
var positionRatio = positionTop / maxPositionTop;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
$this.scrollTop((contentHeight - containerHeight) * positionRatio);
});
$scrollbarX.bind(eventClass('click'), stopPropagation);
$scrollbarXRail.bind(eventClass('click'), function (e) {
var halfOfScrollbarLength = int(scrollbarXWidth / 2);
var positionLeft = e.pageX - $scrollbarXRail.offset().left - halfOfScrollbarLength;
var maxPositionLeft = containerWidth - scrollbarXWidth;
var positionRatio = positionLeft / maxPositionLeft;
if (positionRatio < 0) {
positionRatio = 0;
} else if (positionRatio > 1) {
positionRatio = 1;
}
$this.scrollLeft((contentWidth - containerWidth) * positionRatio);
});
}
function bindSelectionHandler() {
function getRangeNode() {
var selection = window.getSelection ? window.getSelection() :
document.getSlection ? document.getSlection() : {rangeCount: 0};
if (selection.rangeCount === 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 (!isPluginAlive()) {
clearInterval(scrollingLoop);
return;
}
$this.scrollTop($this.scrollTop() + scrollDiff.top);
$this.scrollLeft($this.scrollLeft() + scrollDiff.left);
updateGeometry();
}, 50); // every .1 sec
}
}
function stopScrolling() {
if (scrollingLoop) {
clearInterval(scrollingLoop);
scrollingLoop = null;
}
$scrollbarXRail.removeClass('in-scrolling');
$scrollbarYRail.removeClass('in-scrolling');
}
var isSelected = false;
$(ownerDocument).bind(eventClass('selectionchange'), function (e) {
if ($.contains($this[0], getRangeNode())) {
isSelected = true;
} else {
isSelected = false;
stopScrolling();
}
});
$(window).bind(eventClass('mouseup'), function (e) {
if (isSelected) {
isSelected = false;
stopScrolling();
}
});
$(window).bind(eventClass('mousemove'), function (e) {
if (isSelected) {
var mousePosition = {x: e.pageX, y: e.pageY};
var containerOffset = $this.offset();
var containerGeometry = {
left: containerOffset.left,
right: containerOffset.left + $this.outerWidth(),
top: containerOffset.top,
bottom: containerOffset.top + $this.outerHeight()
};
if (mousePosition.x < containerGeometry.left + 3) {
scrollDiff.left = -5;
$scrollbarXRail.addClass('in-scrolling');
} else if (mousePosition.x > containerGeometry.right - 3) {
scrollDiff.left = 5;
$scrollbarXRail.addClass('in-scrolling');
} else {
scrollDiff.left = 0;
}
if (mousePosition.y < containerGeometry.top + 3) {
if (containerGeometry.top + 3 - mousePosition.y < 5) {
scrollDiff.top = -5;
} else {
scrollDiff.top = -20;
}
$scrollbarYRail.addClass('in-scrolling');
} else if (mousePosition.y > containerGeometry.bottom - 3) {
if (mousePosition.y - containerGeometry.bottom + 3 < 5) {
scrollDiff.top = 5;
} else {
scrollDiff.top = 20;
}
$scrollbarYRail.addClass('in-scrolling');
} else {
scrollDiff.top = 0;
}
if (scrollDiff.top === 0 && scrollDiff.left === 0) {
stopScrolling();
} else {
startScrolling();
}
}
});
}
function bindTouchHandler(supportsTouch, supportsIePointer) {
function applyTouchMove(differenceX, differenceY) {
$this.scrollTop($this.scrollTop() - differenceY);
$this.scrollLeft($this.scrollLeft() - differenceX);
updateGeometry();
}
var startOffset = {};
var startTime = 0;
var speed = {};
var easingLoop = null;
var inGlobalTouch = false;
var inLocalTouch = false;
function globalTouchStart(e) {
inGlobalTouch = true;
}
function globalTouchEnd(e) {
inGlobalTouch = false;
}
function getTouch(e) {
if (e.originalEvent.targetTouches) {
return e.originalEvent.targetTouches[0];
} else {
// Maybe IE pointer
return e.originalEvent;
}
}
function shouldHandle(e) {
var event = e.originalEvent;
if (event.targetTouches && event.targetTouches.length === 1) {
return true;
}
if (event.pointerType && event.pointerType !== 'mouse' && event.pointerType !== event.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;
}
e.stopPropagation();
e.preventDefault();
}
}
function touchEnd(e) {
if (!inGlobalTouch && inLocalTouch) {
inLocalTouch = false;
clearInterval(easingLoop);
easingLoop = setInterval(function () {
if (!isPluginAlive()) {
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) {
$(window).bind(eventClass("touchstart"), globalTouchStart);
$(window).bind(eventClass("touchend"), globalTouchEnd);
$this.bind(eventClass("touchstart"), touchStart);
$this.bind(eventClass("touchmove"), touchMove);
$this.bind(eventClass("touchend"), touchEnd);
}
if (supportsIePointer) {
if (window.PointerEvent) {
$(window).bind(eventClass("pointerdown"), globalTouchStart);
$(window).bind(eventClass("pointerup"), globalTouchEnd);
$this.bind(eventClass("pointerdown"), touchStart);
$this.bind(eventClass("pointermove"), touchMove);
$this.bind(eventClass("pointerup"), touchEnd);
} else if (window.MSPointerEvent) {
$(window).bind(eventClass("MSPointerDown"), globalTouchStart);
$(window).bind(eventClass("MSPointerUp"), globalTouchEnd);
$this.bind(eventClass("MSPointerDown"), touchStart);
$this.bind(eventClass("MSPointerMove"), touchMove);
$this.bind(eventClass("MSPointerUp"), touchEnd);
}
}
}
function bindScrollHandler() {
$this.bind(eventClass('scroll'), function (e) {
updateGeometry();
});
}
function destroy() {
$this.unbind(eventClass());
$(window).unbind(eventClass());
$(ownerDocument).unbind(eventClass());
$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
$this =
$scrollbarXRail =
$scrollbarYRail =
$scrollbarX =
$scrollbarY =
scrollbarXActive =
scrollbarYActive =
containerWidth =
containerHeight =
contentWidth =
contentHeight =
scrollbarXWidth =
scrollbarXLeft =
scrollbarXBottom =
isScrollbarXUsingBottom =
scrollbarXTop =
scrollbarYHeight =
scrollbarYTop =
scrollbarYRight =
isScrollbarYUsingRight =
scrollbarYLeft =
isRtl =
eventClass = null;
}
var supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
var supportsIePointer = window.navigator.msMaxTouchPoints !== null;
function initialize() {
updateGeometry();
bindScrollHandler();
bindMouseScrollXHandler();
bindMouseScrollYHandler();
bindRailClickHandler();
bindSelectionHandler();
bindMouseWheelHandler();
if (supportsTouch || supportsIePointer) {
bindTouchHandler(supportsTouch, supportsIePointer);
}
if (settings.useKeyboard) {
bindKeyboardHandler();
}
$this.data('perfect-scrollbar', $this);
$this.data('perfect-scrollbar-update', updateGeometry);
$this.data('perfect-scrollbar-destroy', destroy);
}
initialize();
return $this;
});
};
});