From 74fc0daf4935e792ec8e03f5fa08f02b92aa3f67 Mon Sep 17 00:00:00 2001 From: Hyunje Alex Jun Date: Thu, 15 Jan 2015 22:44:17 +0000 Subject: [PATCH] Use browserify. --- bower.json | 4 +- gulpfile.js | 53 +- out/{ => css}/perfect-scrollbar.css | 0 out/{ => css}/perfect-scrollbar.min.css | 0 {src => out/js}/perfect-scrollbar.js | 30 +- out/js/perfect-scrollbar.min.js | 1 + out/perfect-scrollbar.min.js | 1 - package.json | 6 +- src/{perfect-scrollbar.scss => css/main.scss} | 0 src/js/main.js | 867 ++++++++++++++++++ 10 files changed, 922 insertions(+), 40 deletions(-) rename out/{ => css}/perfect-scrollbar.css (100%) rename out/{ => css}/perfect-scrollbar.min.css (100%) rename {src => out/js}/perfect-scrollbar.js (97%) create mode 100644 out/js/perfect-scrollbar.min.js delete mode 100644 out/perfect-scrollbar.min.js rename src/{perfect-scrollbar.scss => css/main.scss} (100%) create mode 100644 src/js/main.js diff --git a/bower.json b/bower.json index 69a9c0d..e7a1c1e 100644 --- a/bower.json +++ b/bower.json @@ -7,8 +7,8 @@ ], "description": "Tiny but perfect jQuery scrollbar plugin", "main": [ - "out/perfect-scrollbar.css", - "src/perfect-scrollbar.js" + "out/css/perfect-scrollbar.css", + "out/js/perfect-scrollbar.js" ], "license": "MIT", "ignore": [ diff --git a/gulpfile.js b/gulpfile.js index 5cd5452..ff466da 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,11 +1,13 @@ 'use strict'; var gulp = require('gulp') + , browserify = require('browserify') , bump = require('gulp-bump') , jshint = require('gulp-jshint') , rename = require('gulp-rename') , rimraf = require('gulp-rimraf') , sass = require('gulp-sass') + , transform = require('vinyl-transform') , uglify = require('gulp-uglify'); gulp.task('lint', function () { @@ -15,38 +17,59 @@ gulp.task('lint', function () { }); gulp.task('clean:js', function () { - return gulp.src('./out/perfect-scrollbar.js', {read: false}) + return gulp.src('./out/js/perfect-scrollbar.js', {read: false}) .pipe(rimraf()); }); -gulp.task('uglify', ['clean:js'], function () { - return gulp.src('./src/perfect-scrollbar.js') +gulp.task('clean:js:min', function () { + return gulp.src('./out/js/perfect-scrollbar.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/main.js') + .pipe(browserified()) + .pipe(rename('perfect-scrollbar.js')) + .pipe(gulp.dest('./out/js')); +}); + +gulp.task('js:min', ['clean:js:min'], function () { + return gulp.src('./src/js/main.js') + .pipe(browserified()) .pipe(uglify()) .pipe(rename('perfect-scrollbar.min.js')) - .pipe(gulp.dest('./out')); + .pipe(gulp.dest('./out/js')); }); gulp.task('clean:css', function () { - return gulp.src('./out/perfect-scrollbar.css', {read: false}) + return gulp.src('./out/css/perfect-scrollbar.css', {read: false}) + .pipe(rimraf()); +}); + +gulp.task('clean:css:min', function () { + return gulp.src('./out/css/perfect-scrollbar.min.css', {read: false}) .pipe(rimraf()); }); gulp.task('sass', ['clean:css'], function () { - return gulp.src('./src/perfect-scrollbar.scss') + return gulp.src('./src/css/main.scss') .pipe(sass()) - .pipe(gulp.dest('./out')); -}); - -gulp.task('clean:css:min', function () { - return gulp.src('./out/perfect-scrollbar.css', {read: false}) - .pipe(rimraf()); + .pipe(rename('perfect-scrollbar.css')) + .pipe(gulp.dest('./out/css')); }); gulp.task('sass:min', ['clean:css:min'], function () { - return gulp.src('./src/perfect-scrollbar.scss') + return gulp.src('./src/css/main.scss') .pipe(sass({outputStyle: 'compressed'})) .pipe(rename('perfect-scrollbar.min.css')) - .pipe(gulp.dest('./out')); + .pipe(gulp.dest('./out/css')); }); function bumpType() { @@ -67,5 +90,5 @@ gulp.task('bump', function () { gulp.task('release', ['bump', 'build']); -gulp.task('build', ['uglify', 'sass', 'sass:min']); +gulp.task('build', ['js', 'js:min', 'sass', 'sass:min']); gulp.task('default', ['lint', 'build']); diff --git a/out/perfect-scrollbar.css b/out/css/perfect-scrollbar.css similarity index 100% rename from out/perfect-scrollbar.css rename to out/css/perfect-scrollbar.css diff --git a/out/perfect-scrollbar.min.css b/out/css/perfect-scrollbar.min.css similarity index 100% rename from out/perfect-scrollbar.min.css rename to out/css/perfect-scrollbar.min.css diff --git a/src/perfect-scrollbar.js b/out/js/perfect-scrollbar.js similarity index 97% rename from src/perfect-scrollbar.js rename to out/js/perfect-scrollbar.js index a6861ae..342a0df 100644 --- a/src/perfect-scrollbar.js +++ b/out/js/perfect-scrollbar.js @@ -1,19 +1,10 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oo?0:o>r?r:o;var l=t(A*(Y-D)/(D-R));x.scrollTop(l)}function s(e,n){var o=e+n,r=M-k;W=0>o?0:o>r?r:o;var l=t(W*(C-M)/(M-k));x.scrollLeft(l)}function c(e){return P.minScrollbarLength&&(e=Math.max(e,P.minScrollbarLength)),P.maxScrollbarLength&&(e=Math.min(e,P.maxScrollbarLength)),e}function u(){var e={width:I};e.left=q?x.scrollLeft()+M-C:x.scrollLeft(),j?e.bottom=N-x.scrollTop():e.top=F+x.scrollTop(),_.css(e);var t={top:x.scrollTop(),height:U};Z?t.right=q?C-x.scrollLeft()-V-J.outerWidth():V-x.scrollLeft():t.left=q?x.scrollLeft()+2*M-C-$-J.outerWidth():$+x.scrollLeft(),G.css(t),H.css({left:W,width:k-Q}),J.css({top:A,height:R-et})}function p(){x.removeClass("ps-active-x"),x.removeClass("ps-active-y"),M=P.includePadding?x.innerWidth():x.width(),D=P.includePadding?x.innerHeight():x.height(),C=x.prop("scrollWidth"),Y=x.prop("scrollHeight"),!P.suppressScrollX&&M+P.scrollXMarginOffset=I-k&&(W=I-k),A>=U-R&&(A=U-R),u(),X&&x.addClass("ps-active-x"),O&&x.addClass("ps-active-y")}function d(){var t,n,o=function(e){s(t,e.pageX-n),p(),e.stopPropagation(),e.preventDefault()},r=function(){x.removeClass("ps-in-scrolling"),e(K).unbind(B("mousemove"),o)};H.bind(B("mousedown"),function(l){n=l.pageX,t=H.position().left,x.addClass("ps-in-scrolling"),e(K).bind(B("mousemove"),o),e(K).one(B("mouseup"),r),l.stopPropagation(),l.preventDefault()}),t=n=null}function f(){var t,n,o=function(e){a(t,e.pageY-n),p(),e.stopPropagation(),e.preventDefault()},r=function(){x.removeClass("ps-in-scrolling"),e(K).unbind(B("mousemove"),o)};J.bind(B("mousedown"),function(l){n=l.pageY,t=J.position().top,x.addClass("ps-in-scrolling"),e(K).bind(B("mousemove"),o),e(K).one(B("mouseup"),r),l.stopPropagation(),l.preventDefault()}),t=n=null}function v(e,t){var n=x.scrollTop();if(0===e){if(!O)return!1;if(0===n&&t>0||n>=Y-D&&0>t)return!P.wheelPropagation}var o=x.scrollLeft();if(0===t){if(!X)return!1;if(0===o&&0>e||o>=C-M&&e>0)return!P.wheelPropagation}return!0}function g(e,t){var n=x.scrollTop(),o=x.scrollLeft(),r=Math.abs(e),l=Math.abs(t);if(l>r){if(0>t&&n===Y-D||t>0&&0===n)return!P.swipePropagation}else if(r>l&&(0>e&&o===C-M||e>0&&0===o))return!P.swipePropagation;return!0}function b(){function e(e){var t=e.originalEvent.deltaX,n=-1*e.originalEvent.deltaY;return("undefined"==typeof t||"undefined"==typeof n)&&(t=-1*e.originalEvent.wheelDeltaX/6,n=e.originalEvent.wheelDeltaY/6),e.originalEvent.deltaMode&&1===e.originalEvent.deltaMode&&(t*=10,n*=10),t!==t&&n!==n&&(t=0,n=e.originalEvent.wheelDelta),[t,n]}function t(t){if(l||!(x.find("select:focus").length>0)){var o=e(t),r=o[0],i=o[1];n=!1,P.useBothWheelAxes?O&&!X?(x.scrollTop(i?x.scrollTop()-i*P.wheelSpeed:x.scrollTop()+r*P.wheelSpeed),n=!0):X&&!O&&(x.scrollLeft(r?x.scrollLeft()+r*P.wheelSpeed:x.scrollLeft()-i*P.wheelSpeed),n=!0):(x.scrollTop(x.scrollTop()-i*P.wheelSpeed),x.scrollLeft(x.scrollLeft()+r*P.wheelSpeed)),p(),n=n||v(r,i),n&&(t.stopPropagation(),t.preventDefault())}}var n=!1;"undefined"!=typeof window.onwheel?x.bind(B("wheel"),t):"undefined"!=typeof window.onmousewheel&&x.bind(B("mousewheel"),t)}function h(){var t=!1;x.bind(B("mouseenter"),function(){t=!0}),x.bind(B("mouseleave"),function(){t=!1});var n=!1;e(K).bind(B("keydown"),function(o){if((!o.isDefaultPrevented||!o.isDefaultPrevented())&&t){for(var r=document.activeElement?document.activeElement:K.activeElement;r.shadowRoot;)r=r.shadowRoot.activeElement;if(!e(r).is(":input,[contenteditable]")){var l=0,i=0;switch(o.which){case 37:l=-30;break;case 38:i=30;break;case 39:l=30;break;case 40:i=-30;break;case 33:i=90;break;case 32:case 34:i=-90;break;case 35:i=o.ctrlKey?-Y:-D;break;case 36:i=o.ctrlKey?x.scrollTop():D;break;default:return}x.scrollTop(x.scrollTop()-i),x.scrollLeft(x.scrollLeft()+l),n=v(l,i),n&&o.preventDefault()}}})}function w(){function e(e){e.stopPropagation()}J.bind(B("click"),e),G.bind(B("click"),function(e){var n=t(R/2),o=e.pageY-G.offset().top-n,r=D-R,l=o/r;0>l?l=0:l>1&&(l=1),x.scrollTop((Y-D)*l)}),H.bind(B("click"),e),_.bind(B("click"),function(e){var n=t(k/2),o=e.pageX-_.offset().left-n,r=M-k,l=o/r;0>l?l=0:l>1&&(l=1),x.scrollLeft((C-M)*l)})}function m(){function t(){var e=window.getSelection?window.getSelection():document.getSlection?document.getSlection():{rangeCount:0};return 0===e.rangeCount?null:e.getRangeAt(0).commonAncestorContainer}function n(){r||(r=setInterval(function(){return E()?(x.scrollTop(x.scrollTop()+l.top),x.scrollLeft(x.scrollLeft()+l.left),void p()):void clearInterval(r)},50))}function o(){r&&(clearInterval(r),r=null),x.removeClass("ps-in-scrolling"),x.removeClass("ps-in-scrolling")}var r=null,l={top:0,left:0},i=!1;e(K).bind(B("selectionchange"),function(){e.contains(x[0],t())?i=!0:(i=!1,o())}),e(window).bind(B("mouseup"),function(){i&&(i=!1,o())}),e(window).bind(B("mousemove"),function(e){if(i){var t={x:e.pageX,y:e.pageY},r=x.offset(),a={left:r.left,right:r.left+x.outerWidth(),top:r.top,bottom:r.top+x.outerHeight()};t.xa.right-3?(l.left=5,x.addClass("ps-in-scrolling")):l.left=0,t.ya.bottom-3?(l.top=t.y-a.bottom+3<5?5:20,x.addClass("ps-in-scrolling")):l.top=0,0===l.top&&0===l.left?o():n()}})}function T(t,n){function o(e,t){x.scrollTop(x.scrollTop()-t),x.scrollLeft(x.scrollLeft()-e),p()}function r(){h=!0}function l(){h=!1}function i(e){return e.originalEvent.targetTouches?e.originalEvent.targetTouches[0]:e.originalEvent}function a(e){var t=e.originalEvent;return t.targetTouches&&1===t.targetTouches.length?!0:t.pointerType&&"mouse"!==t.pointerType&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE?!0:!1}function s(e){if(a(e)){w=!0;var t=i(e);d.pageX=t.pageX,d.pageY=t.pageY,f=(new Date).getTime(),null!==b&&clearInterval(b),e.stopPropagation()}}function c(e){if(!h&&w&&a(e)){var t=i(e),n={pageX:t.pageX,pageY:t.pageY},r=n.pageX-d.pageX,l=n.pageY-d.pageY;o(r,l),d=n;var s=(new Date).getTime(),c=s-f;c>0&&(v.x=r/c,v.y=l/c,f=s),g(r,l)&&(e.stopPropagation(),e.preventDefault())}}function u(){!h&&w&&(w=!1,clearInterval(b),b=setInterval(function(){return E()?Math.abs(v.x)<.01&&Math.abs(v.y)<.01?void clearInterval(b):(o(30*v.x,30*v.y),v.x*=.8,void(v.y*=.8)):void clearInterval(b)},10))}var d={},f=0,v={},b=null,h=!1,w=!1;t&&(e(window).bind(B("touchstart"),r),e(window).bind(B("touchend"),l),x.bind(B("touchstart"),s),x.bind(B("touchmove"),c),x.bind(B("touchend"),u)),n&&(window.PointerEvent?(e(window).bind(B("pointerdown"),r),e(window).bind(B("pointerup"),l),x.bind(B("pointerdown"),s),x.bind(B("pointermove"),c),x.bind(B("pointerup"),u)):window.MSPointerEvent&&(e(window).bind(B("MSPointerDown"),r),e(window).bind(B("MSPointerUp"),l),x.bind(B("MSPointerDown"),s),x.bind(B("MSPointerMove"),c),x.bind(B("MSPointerUp"),u)))}function y(){x.bind(B("scroll"),function(){p()})}function L(){x.unbind(B()),e(window).unbind(B()),e(K).unbind(B()),x.data("perfect-scrollbar",null),x.data("perfect-scrollbar-update",null),x.data("perfect-scrollbar-destroy",null),H.remove(),J.remove(),_.remove(),G.remove(),x=_=G=H=J=X=O=M=D=C=Y=k=W=N=j=F=R=A=V=Z=$=q=B=null}function S(){p(),y(),d(),f(),w(),m(),b(),(nt||ot)&&T(nt,ot),P.useKeyboard&&h(),x.data("perfect-scrollbar",x),x.data("perfect-scrollbar-update",p),x.data("perfect-scrollbar-destroy",L)}var P=e.extend(!0,{},n),x=e(this),E=function(){return!!x};if("object"==typeof o?e.extend(!0,P,o):i=o,"update"===i)return x.data("perfect-scrollbar-update")&&x.data("perfect-scrollbar-update")(),x;if("destroy"===i)return x.data("perfect-scrollbar-destroy")&&x.data("perfect-scrollbar-destroy")(),x;if(x.data("perfect-scrollbar"))return x.data("perfect-scrollbar");x.addClass("ps-container");var M,D,C,Y,X,k,W,I,O,R,A,U,q="rtl"===x.css("direction"),B=r(),K=this.ownerDocument||document,_=e("
").appendTo(x),H=e("
").appendTo(_),N=t(_.css("bottom")),j=N===N,F=j?null:t(_.css("top")),Q=t(_.css("borderLeftWidth"))+t(_.css("borderRightWidth")),z=t(_.css("marginLeft"))+t(_.css("marginRight")),G=e("
").appendTo(x),J=e("
").appendTo(G),V=t(G.css("right")),Z=V===V,$=Z?null:t(G.css("left")),et=t(G.css("borderTopWidth"))+t(G.css("borderBottomWidth")),tt=t(G.css("marginTop"))+t(G.css("marginBottom")),nt="ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch,ot=null!==window.navigator.msMaxTouchPoints;return S(),x})}})},{}]},{},[1]); \ No newline at end of file diff --git a/out/perfect-scrollbar.min.js b/out/perfect-scrollbar.min.js deleted file mode 100644 index 53a5939..0000000 --- a/out/perfect-scrollbar.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):jQuery)}(function(e){"use strict";function t(e){return"string"==typeof e?parseInt(e,10):~~e}var o={wheelSpeed:1,wheelPropagation:!1,swipePropagation:!0,minScrollbarLength:null,maxScrollbarLength:null,useBothWheelAxes:!1,useKeyboard:!0,suppressScrollX:!1,suppressScrollY:!1,scrollXMarginOffset:0,scrollYMarginOffset:0,includePadding:!1},n=0,r=function(){var e=n++;return function(t){var o=".perfect-scrollbar-"+e;return"undefined"==typeof t?o:t+o}},l="WebkitAppearance"in document.documentElement.style;e.fn.perfectScrollbar=function(n,i){return this.each(function(){function a(e,o){var n=e+o,r=D-R;j=0>n?0:n>r?r:n;var l=t(j*(Y-D)/(D-R));M.scrollTop(l)}function s(e,o){var n=e+o,r=E-k;W=0>n?0:n>r?r:n;var l=t(W*(C-E)/(E-k));M.scrollLeft(l)}function c(e){return P.minScrollbarLength&&(e=Math.max(e,P.minScrollbarLength)),P.maxScrollbarLength&&(e=Math.min(e,P.maxScrollbarLength)),e}function u(){var e={width:I};e.left=B?M.scrollLeft()+E-C:M.scrollLeft(),N?e.bottom=_-M.scrollTop():e.top=Q+M.scrollTop(),H.css(e);var t={top:M.scrollTop(),height:A};Z?t.right=B?C-M.scrollLeft()-V-J.outerWidth():V-M.scrollLeft():t.left=B?M.scrollLeft()+2*E-C-$-J.outerWidth():$+M.scrollLeft(),G.css(t),U.css({left:W,width:k-z}),J.css({top:j,height:R-et})}function p(){M.removeClass("ps-active-x"),M.removeClass("ps-active-y"),E=P.includePadding?M.innerWidth():M.width(),D=P.includePadding?M.innerHeight():M.height(),C=M.prop("scrollWidth"),Y=M.prop("scrollHeight"),!P.suppressScrollX&&E+P.scrollXMarginOffset=I-k&&(W=I-k),j>=A-R&&(j=A-R),u(),X&&M.addClass("ps-active-x"),O&&M.addClass("ps-active-y")}function d(){var t,o,n=function(e){s(t,e.pageX-o),p(),e.stopPropagation(),e.preventDefault()},r=function(){M.removeClass("ps-in-scrolling"),e(q).unbind(K("mousemove"),n)};U.bind(K("mousedown"),function(l){o=l.pageX,t=U.position().left,M.addClass("ps-in-scrolling"),e(q).bind(K("mousemove"),n),e(q).one(K("mouseup"),r),l.stopPropagation(),l.preventDefault()}),t=o=null}function f(){var t,o,n=function(e){a(t,e.pageY-o),p(),e.stopPropagation(),e.preventDefault()},r=function(){M.removeClass("ps-in-scrolling"),e(q).unbind(K("mousemove"),n)};J.bind(K("mousedown"),function(l){o=l.pageY,t=J.position().top,M.addClass("ps-in-scrolling"),e(q).bind(K("mousemove"),n),e(q).one(K("mouseup"),r),l.stopPropagation(),l.preventDefault()}),t=o=null}function g(e,t){var o=M.scrollTop();if(0===e){if(!O)return!1;if(0===o&&t>0||o>=Y-D&&0>t)return!P.wheelPropagation}var n=M.scrollLeft();if(0===t){if(!X)return!1;if(0===n&&0>e||n>=C-E&&e>0)return!P.wheelPropagation}return!0}function v(e,t){var o=M.scrollTop(),n=M.scrollLeft(),r=Math.abs(e),l=Math.abs(t);if(l>r){if(0>t&&o===Y-D||t>0&&0===o)return!P.swipePropagation}else if(r>l&&(0>e&&n===C-E||e>0&&0===n))return!P.swipePropagation;return!0}function b(){function e(e){var t=e.originalEvent.deltaX,o=-1*e.originalEvent.deltaY;return("undefined"==typeof t||"undefined"==typeof o)&&(t=-1*e.originalEvent.wheelDeltaX/6,o=e.originalEvent.wheelDeltaY/6),e.originalEvent.deltaMode&&1===e.originalEvent.deltaMode&&(t*=10,o*=10),t!==t&&o!==o&&(t=0,o=e.originalEvent.wheelDelta),[t,o]}function t(t){if(l||!(M.find("select:focus").length>0)){var n=e(t),r=n[0],i=n[1];o=!1,P.useBothWheelAxes?O&&!X?(M.scrollTop(i?M.scrollTop()-i*P.wheelSpeed:M.scrollTop()+r*P.wheelSpeed),o=!0):X&&!O&&(M.scrollLeft(r?M.scrollLeft()+r*P.wheelSpeed:M.scrollLeft()-i*P.wheelSpeed),o=!0):(M.scrollTop(M.scrollTop()-i*P.wheelSpeed),M.scrollLeft(M.scrollLeft()+r*P.wheelSpeed)),p(),o=o||g(r,i),o&&(t.stopPropagation(),t.preventDefault())}}var o=!1;"undefined"!=typeof window.onwheel?M.bind(K("wheel"),t):"undefined"!=typeof window.onmousewheel&&M.bind(K("mousewheel"),t)}function h(){var t=!1;M.bind(K("mouseenter"),function(){t=!0}),M.bind(K("mouseleave"),function(){t=!1});var o=!1;e(q).bind(K("keydown"),function(n){if((!n.isDefaultPrevented||!n.isDefaultPrevented())&&t){for(var r=document.activeElement?document.activeElement:q.activeElement;r.shadowRoot;)r=r.shadowRoot.activeElement;if(!e(r).is(":input,[contenteditable]")){var l=0,i=0;switch(n.which){case 37:l=-30;break;case 38:i=30;break;case 39:l=30;break;case 40:i=-30;break;case 33:i=90;break;case 32:case 34:i=-90;break;case 35:i=n.ctrlKey?-Y:-D;break;case 36:i=n.ctrlKey?M.scrollTop():D;break;default:return}M.scrollTop(M.scrollTop()-i),M.scrollLeft(M.scrollLeft()+l),o=g(l,i),o&&n.preventDefault()}}})}function w(){function e(e){e.stopPropagation()}J.bind(K("click"),e),G.bind(K("click"),function(e){var o=t(R/2),n=e.pageY-G.offset().top-o,r=D-R,l=n/r;0>l?l=0:l>1&&(l=1),M.scrollTop((Y-D)*l)}),U.bind(K("click"),e),H.bind(K("click"),function(e){var o=t(k/2),n=e.pageX-H.offset().left-o,r=E-k,l=n/r;0>l?l=0:l>1&&(l=1),M.scrollLeft((C-E)*l)})}function m(){function t(){var e=window.getSelection?window.getSelection():document.getSlection?document.getSlection():{rangeCount:0};return 0===e.rangeCount?null:e.getRangeAt(0).commonAncestorContainer}function o(){r||(r=setInterval(function(){return x()?(M.scrollTop(M.scrollTop()+l.top),M.scrollLeft(M.scrollLeft()+l.left),void p()):void clearInterval(r)},50))}function n(){r&&(clearInterval(r),r=null),M.removeClass("ps-in-scrolling"),M.removeClass("ps-in-scrolling")}var r=null,l={top:0,left:0},i=!1;e(q).bind(K("selectionchange"),function(){e.contains(M[0],t())?i=!0:(i=!1,n())}),e(window).bind(K("mouseup"),function(){i&&(i=!1,n())}),e(window).bind(K("mousemove"),function(e){if(i){var t={x:e.pageX,y:e.pageY},r=M.offset(),a={left:r.left,right:r.left+M.outerWidth(),top:r.top,bottom:r.top+M.outerHeight()};t.xa.right-3?(l.left=5,M.addClass("ps-in-scrolling")):l.left=0,t.ya.bottom-3?(l.top=t.y-a.bottom+3<5?5:20,M.addClass("ps-in-scrolling")):l.top=0,0===l.top&&0===l.left?n():o()}})}function T(t,o){function n(e,t){M.scrollTop(M.scrollTop()-t),M.scrollLeft(M.scrollLeft()-e),p()}function r(){h=!0}function l(){h=!1}function i(e){return e.originalEvent.targetTouches?e.originalEvent.targetTouches[0]:e.originalEvent}function a(e){var t=e.originalEvent;return t.targetTouches&&1===t.targetTouches.length?!0:t.pointerType&&"mouse"!==t.pointerType&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE?!0:!1}function s(e){if(a(e)){w=!0;var t=i(e);d.pageX=t.pageX,d.pageY=t.pageY,f=(new Date).getTime(),null!==b&&clearInterval(b),e.stopPropagation()}}function c(e){if(!h&&w&&a(e)){var t=i(e),o={pageX:t.pageX,pageY:t.pageY},r=o.pageX-d.pageX,l=o.pageY-d.pageY;n(r,l),d=o;var s=(new Date).getTime(),c=s-f;c>0&&(g.x=r/c,g.y=l/c,f=s),v(r,l)&&(e.stopPropagation(),e.preventDefault())}}function u(){!h&&w&&(w=!1,clearInterval(b),b=setInterval(function(){return x()?Math.abs(g.x)<.01&&Math.abs(g.y)<.01?void clearInterval(b):(n(30*g.x,30*g.y),g.x*=.8,void(g.y*=.8)):void clearInterval(b)},10))}var d={},f=0,g={},b=null,h=!1,w=!1;t&&(e(window).bind(K("touchstart"),r),e(window).bind(K("touchend"),l),M.bind(K("touchstart"),s),M.bind(K("touchmove"),c),M.bind(K("touchend"),u)),o&&(window.PointerEvent?(e(window).bind(K("pointerdown"),r),e(window).bind(K("pointerup"),l),M.bind(K("pointerdown"),s),M.bind(K("pointermove"),c),M.bind(K("pointerup"),u)):window.MSPointerEvent&&(e(window).bind(K("MSPointerDown"),r),e(window).bind(K("MSPointerUp"),l),M.bind(K("MSPointerDown"),s),M.bind(K("MSPointerMove"),c),M.bind(K("MSPointerUp"),u)))}function y(){M.bind(K("scroll"),function(){p()})}function L(){M.unbind(K()),e(window).unbind(K()),e(q).unbind(K()),M.data("perfect-scrollbar",null),M.data("perfect-scrollbar-update",null),M.data("perfect-scrollbar-destroy",null),U.remove(),J.remove(),H.remove(),G.remove(),M=H=G=U=J=X=O=E=D=C=Y=k=W=_=N=Q=R=j=V=Z=$=B=K=null}function S(){p(),y(),d(),f(),w(),m(),b(),(ot||nt)&&T(ot,nt),P.useKeyboard&&h(),M.data("perfect-scrollbar",M),M.data("perfect-scrollbar-update",p),M.data("perfect-scrollbar-destroy",L)}var P=e.extend(!0,{},o),M=e(this),x=function(){return!!M};if("object"==typeof n?e.extend(!0,P,n):i=n,"update"===i)return M.data("perfect-scrollbar-update")&&M.data("perfect-scrollbar-update")(),M;if("destroy"===i)return M.data("perfect-scrollbar-destroy")&&M.data("perfect-scrollbar-destroy")(),M;if(M.data("perfect-scrollbar"))return M.data("perfect-scrollbar");M.addClass("ps-container");var E,D,C,Y,X,k,W,I,O,R,j,A,B="rtl"===M.css("direction"),K=r(),q=this.ownerDocument||document,H=e("
").appendTo(M),U=e("
").appendTo(H),_=t(H.css("bottom")),N=_===_,Q=N?null:t(H.css("top")),z=t(H.css("borderLeftWidth"))+t(H.css("borderRightWidth")),F=t(H.css("marginLeft"))+t(H.css("marginRight")),G=e("
").appendTo(M),J=e("
").appendTo(G),V=t(G.css("right")),Z=V===V,$=Z?null:t(G.css("left")),et=t(G.css("borderTopWidth"))+t(G.css("borderBottomWidth")),tt=t(G.css("marginTop"))+t(G.css("marginBottom")),ot="ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch,nt=null!==window.navigator.msMaxTouchPoints;return S(),M})}}); \ No newline at end of file diff --git a/package.json b/package.json index b4f3934..f5f64f4 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "email": "me@noraesae.net" } ], - "main": "src/perfect-scrollbar.js", + "main": "out/js/perfect-scrollbar.js", "repository": { "type": "git", "url": "https://github.com/noraesae/perfect-scrollbar" @@ -26,13 +26,15 @@ "node": ">= 0.8.0" }, "devDependencies": { + "browserify": "^8.1.1", "gulp": "^3.8.10", "gulp-bump": "^0.1.11", "gulp-jshint": "^1.9.0", "gulp-rename": "^1.2.0", "gulp-rimraf": "^0.1.1", "gulp-sass": "^1.3.1", - "gulp-uglify": "^1.0.2" + "gulp-uglify": "^1.0.2", + "vinyl-transform": "^1.0.0" }, "scripts": { "test": "gulp" diff --git a/src/perfect-scrollbar.scss b/src/css/main.scss similarity index 100% rename from src/perfect-scrollbar.scss rename to src/css/main.scss diff --git a/src/js/main.js b/src/js/main.js new file mode 100644 index 0000000..98e5f03 --- /dev/null +++ b/src/js/main.js @@ -0,0 +1,867 @@ +/* Copyright (c) 2015 Hyunje Alex Jun and other contributors + * Licensed under the MIT License + */ +(function (factory) { + 'use strict'; + factory(jQuery); +})(function ($) { + 'use strict'; + + function getInt(x) { + if (typeof x === 'string') { + return parseInt(x, 10); + } else { + return ~~x; + } + } + + var defaultSettings = { + wheelSpeed: 1, + wheelPropagation: false, + swipePropagation: true, + 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; + } + }; + }; + + var isWebkit = 'WebkitAppearance' in document.documentElement.style; + + $.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 = $("
").appendTo($this); + var $scrollbarX = $("
").appendTo($scrollbarXRail); + var scrollbarXActive; + var scrollbarXWidth; + var scrollbarXLeft; + var scrollbarXBottom = getInt($scrollbarXRail.css('bottom')); + var isScrollbarXUsingBottom = scrollbarXBottom === scrollbarXBottom; // !isNaN + var scrollbarXTop = isScrollbarXUsingBottom ? null : getInt($scrollbarXRail.css('top')); + var railBorderXWidth = getInt($scrollbarXRail.css('borderLeftWidth')) + getInt($scrollbarXRail.css('borderRightWidth')); + var railXMarginWidth = getInt($scrollbarXRail.css('marginLeft')) + getInt($scrollbarXRail.css('marginRight')); + var railXWidth; + + var $scrollbarYRail = $("
").appendTo($this); + var $scrollbarY = $("
").appendTo($scrollbarYRail); + var scrollbarYActive; + var scrollbarYHeight; + var scrollbarYTop; + var scrollbarYRight = getInt($scrollbarYRail.css('right')); + var isScrollbarYUsingRight = scrollbarYRight === scrollbarYRight; // !isNaN + var scrollbarYLeft = isScrollbarYUsingRight ? null : getInt($scrollbarYRail.css('left')); + var railBorderYWidth = getInt($scrollbarYRail.css('borderTopWidth')) + getInt($scrollbarYRail.css('borderBottomWidth')); + var railYMarginHeight = getInt($scrollbarYRail.css('marginTop')) + getInt($scrollbarYRail.css('marginBottom')); + var railYHeight; + + 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 = getInt(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 = getInt(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: railXWidth}; + 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: railYHeight}; + + 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; + railXWidth = containerWidth - railXMarginWidth; + scrollbarXWidth = getThumbSize(getInt(railXWidth * containerWidth / contentWidth)); + scrollbarXLeft = getInt($this.scrollLeft() * (railXWidth - scrollbarXWidth) / (contentWidth - containerWidth)); + } else { + scrollbarXActive = false; + scrollbarXWidth = 0; + scrollbarXLeft = 0; + $this.scrollLeft(0); + } + + if (!settings.suppressScrollY && containerHeight + settings.scrollYMarginOffset < contentHeight) { + scrollbarYActive = true; + railYHeight = containerHeight - railYMarginHeight; + scrollbarYHeight = getThumbSize(getInt(railYHeight * containerHeight / contentHeight)); + scrollbarYTop = getInt($this.scrollTop() * (railYHeight - scrollbarYHeight) / (contentHeight - containerHeight)); + } else { + scrollbarYActive = false; + scrollbarYHeight = 0; + scrollbarYTop = 0; + $this.scrollTop(0); + } + + if (scrollbarXLeft >= railXWidth - scrollbarXWidth) { + scrollbarXLeft = railXWidth - scrollbarXWidth; + } + if (scrollbarYTop >= railYHeight - scrollbarYHeight) { + scrollbarYTop = railYHeight - scrollbarYHeight; + } + + updateCss(); + + if (scrollbarXActive) { + $this.addClass('ps-active-x'); + } + if (scrollbarYActive) { + $this.addClass('ps-active-y'); + } + } + + function bindMouseScrollXHandler() { + var currentLeft; + var currentPageX; + + var mouseMoveHandler = function (e) { + updateScrollLeft(currentLeft, e.pageX - currentPageX); + updateGeometry(); + e.stopPropagation(); + e.preventDefault(); + }; + + var mouseUpHandler = function (e) { + $this.removeClass('ps-in-scrolling'); + $(ownerDocument).unbind(eventClass('mousemove'), mouseMoveHandler); + }; + + $scrollbarX.bind(eventClass('mousedown'), function (e) { + currentPageX = e.pageX; + currentLeft = $scrollbarX.position().left; + $this.addClass('ps-in-scrolling'); + + $(ownerDocument).bind(eventClass('mousemove'), mouseMoveHandler); + $(ownerDocument).one(eventClass('mouseup'), mouseUpHandler); + + e.stopPropagation(); + e.preventDefault(); + }); + + currentLeft = + currentPageX = null; + } + + function bindMouseScrollYHandler() { + var currentTop; + var currentPageY; + + var mouseMoveHandler = function (e) { + updateScrollTop(currentTop, e.pageY - currentPageY); + updateGeometry(); + e.stopPropagation(); + e.preventDefault(); + }; + + var mouseUpHandler = function (e) { + $this.removeClass('ps-in-scrolling'); + $(ownerDocument).unbind(eventClass('mousemove'), mouseMoveHandler); + }; + + $scrollbarY.bind(eventClass('mousedown'), function (e) { + currentPageY = e.pageY; + currentTop = $scrollbarY.position().top; + $this.addClass('ps-in-scrolling'); + + $(ownerDocument).bind(eventClass('mousemove'), mouseMoveHandler); + $(ownerDocument).one(eventClass('mouseup'), mouseUpHandler); + + e.stopPropagation(); + e.preventDefault(); + }); + + currentTop = + currentPageY = null; + } + + function shouldPreventWheel(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 shouldPreventSwipe(deltaX, deltaY) { + var scrollTop = $this.scrollTop(); + var scrollLeft = $this.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 === contentHeight - containerHeight)) || + ((deltaY > 0) && (scrollTop === 0))) { + return !settings.swipePropagation; + } + } else if (magnitudeX > magnitudeY) { + // user is perhaps trying to swipe left/right across the page + + if (((deltaX < 0) && (scrollLeft === contentWidth - containerWidth)) || + ((deltaX > 0) && (scrollLeft === 0))) { + return !settings.swipePropagation; + } + } + + 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) { + // 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 (!isWebkit && $this.find('select:focus').length > 0) { + return; + } + + 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 || shouldPreventWheel(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; + + if (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 = shouldPreventWheel(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 = getInt(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 = getInt(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; + } + $this.removeClass('ps-in-scrolling'); + $this.removeClass('ps-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; + $this.addClass('ps-in-scrolling'); + } else if (mousePosition.x > containerGeometry.right - 3) { + scrollDiff.left = 5; + $this.addClass('ps-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; + } + $this.addClass('ps-in-scrolling'); + } else if (mousePosition.y > containerGeometry.bottom - 3) { + if (mousePosition.y - containerGeometry.bottom + 3 < 5) { + scrollDiff.top = 5; + } else { + scrollDiff.top = 20; + } + $this.addClass('ps-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; + } + + if (shouldPreventSwipe(differenceX, differenceY)) { + 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; + }); + }; +});