├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── rollup.config.js
└── src
├── index.js
└── slimscroll.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Directories
2 | node_modules/
3 | dist/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # svelte-slimscroll
2 | svelte-slimscroll is a action for Svelte.js, which can transforms any div into a scrollable area with a nice scrollbar.
3 |
4 | **Demo**: https://svelte.dev/repl/e8dcf07c3f3c4573a62ec289b1958005?version=3.29.4.
5 |
6 |
7 | [](https://github.com/MelihAltintas/svelte-slimscroll/stargazers)
8 | ## Install
9 | - Install it by using npm.
10 |
11 | ```
12 | npm i svelte-slimscroll
13 | ```
14 |
15 | - Import it at `svelte` project.
16 |
17 | ``` js
18 | import {slimscroll} from "svelte-slimscroll"
19 | ```
20 |
21 | ## Usage
22 |
23 | Using the `slimscroll` action
24 | ``` html
25 |
26 | ...
27 |
28 | ```
29 |
30 | Using action with options
31 |
32 | ``` html
33 |
34 | ...
35 |
36 |
39 | ```
40 | > The `options` is same as jQuery version. See their [documentation](http://rocha.la/jQuery-slimScroll)
41 |
42 | Options
43 | -------
44 | * **width** - width in pixels of the visible scroll area Default: auto
45 | * **height** - Height in pixels of the visible scroll area. Default: 250px
46 | * **size** - Width in pixels of the scrollbar. Default: 7px
47 | * **color** - Color in hex of the scrollbar. Default: #000
48 | * **position** - left or right. Sets the position of the scrollbar. Default: right
49 | * **distance** - distance in pixels between the side edge and the scrollbar It is used together with position property. Default:1px
50 | * **start** - default scroll position on load - top / bottom / $('selector'). Default: top.
51 | * **opacity** - sets scrollbar opacity. Default: 0.4.
52 | * **alwaysVisible** - Disables scrollbar hide. Default: false
53 | * **disableFadeOut** - Disables scrollbar auto fade. When set to true scrollbar doesn't disappear after some time when mouse is over the slimscroll div.Default: false
54 | * **railVisible** - Enables scrollbar rail. Default: false
55 | * **railColor** - Sets scrollbar rail color, Default: #333
56 | * **railOpacity** - Sets scrollbar rail opacity. Default: 0.2
57 | * **railClass** - defautlt CSS class of the slimscroll rail. Default: 'slimScrollRail'
58 | * **barClass** - defautlt CSS class of the slimscroll bar. Default: 'slimScrollBar'
59 | * **wrapperClass** - defautlt CSS class of the slimscroll wrapper. Default: 'slimScrollDiv'
60 | * **allowPageScroll** - Checks if mouse wheel should scroll page when bar reaches top or bottom of the container. When set to true is scrolls the page.Default: false
61 | * **wheelStep** - Integer value for mouse wheel delta. Default: 20
62 | * **touchScrollStep** - Allows to set different sensitivity for touch scroll events. Negative number inverts scroll direction.Default: 200
63 | * **borderRadius** - sets border radius.Default: 7px
64 | * **railBorderRadius** - sets border radius of the rail.Default: 7px
65 |
66 | ## License
67 | [MIT](http://opensource.org/licenses/MIT)
68 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-slimscroll",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@types/node": {
8 | "version": "14.14.6",
9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz",
10 | "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==",
11 | "dev": true
12 | },
13 | "@types/resolve": {
14 | "version": "0.0.8",
15 | "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
16 | "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
17 | "dev": true,
18 | "requires": {
19 | "@types/node": "*"
20 | }
21 | },
22 | "builtin-modules": {
23 | "version": "3.1.0",
24 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
25 | "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
26 | "dev": true
27 | },
28 | "estree-walker": {
29 | "version": "0.6.1",
30 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
31 | "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
32 | "dev": true
33 | },
34 | "fsevents": {
35 | "version": "2.1.3",
36 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
37 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
38 | "dev": true,
39 | "optional": true
40 | },
41 | "function-bind": {
42 | "version": "1.1.1",
43 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
44 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
45 | "dev": true
46 | },
47 | "has": {
48 | "version": "1.0.3",
49 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
50 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
51 | "dev": true,
52 | "requires": {
53 | "function-bind": "^1.1.1"
54 | }
55 | },
56 | "is-core-module": {
57 | "version": "2.1.0",
58 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
59 | "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==",
60 | "dev": true,
61 | "requires": {
62 | "has": "^1.0.3"
63 | }
64 | },
65 | "is-module": {
66 | "version": "1.0.0",
67 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
68 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
69 | "dev": true
70 | },
71 | "path-parse": {
72 | "version": "1.0.6",
73 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
74 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
75 | "dev": true
76 | },
77 | "require-relative": {
78 | "version": "0.8.7",
79 | "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
80 | "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
81 | "dev": true
82 | },
83 | "resolve": {
84 | "version": "1.18.1",
85 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
86 | "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==",
87 | "dev": true,
88 | "requires": {
89 | "is-core-module": "^2.0.0",
90 | "path-parse": "^1.0.6"
91 | }
92 | },
93 | "rollup": {
94 | "version": "2.33.1",
95 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.1.tgz",
96 | "integrity": "sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==",
97 | "dev": true,
98 | "requires": {
99 | "fsevents": "~2.1.2"
100 | }
101 | },
102 | "rollup-plugin-node-resolve": {
103 | "version": "5.2.0",
104 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
105 | "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
106 | "dev": true,
107 | "requires": {
108 | "@types/resolve": "0.0.8",
109 | "builtin-modules": "^3.1.0",
110 | "is-module": "^1.0.0",
111 | "resolve": "^1.11.1",
112 | "rollup-pluginutils": "^2.8.1"
113 | }
114 | },
115 | "rollup-plugin-svelte": {
116 | "version": "6.1.0",
117 | "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-6.1.0.tgz",
118 | "integrity": "sha512-TX1nIZSD6ePiSdYIEfpkvR7lLnP1nsSycCVz+vXbm5d5kIe5WMldo6fwcL/T8KPjc42XDgLaRcS74BorpQvpiA==",
119 | "dev": true,
120 | "requires": {
121 | "require-relative": "^0.8.7",
122 | "rollup-pluginutils": "^2.8.2",
123 | "sourcemap-codec": "^1.4.8"
124 | }
125 | },
126 | "rollup-pluginutils": {
127 | "version": "2.8.2",
128 | "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
129 | "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
130 | "dev": true,
131 | "requires": {
132 | "estree-walker": "^0.6.1"
133 | }
134 | },
135 | "sourcemap-codec": {
136 | "version": "1.4.8",
137 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
138 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
139 | "dev": true
140 | },
141 | "svelte": {
142 | "version": "3.29.4",
143 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.29.4.tgz",
144 | "integrity": "sha512-oW0fGHlyFFMvzRtIvOs84b0fOc0gmZNQcL5Is3hxuTpvaYX3pfd8oHy4KnOvbq4Ca6SG6AHdRMk7OhApTo0NqA==",
145 | "dev": true
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-slimscroll",
3 | "version": "1.0.6",
4 | "description": "svelte-slimscroll is a action for Svelte.js, which can transforms any div into a scrollable area with a nice scrollbar.",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/MelihAltintas/svelte-slimscroll"
8 | },
9 | "homepage": "",
10 | "bugs": {
11 | "url": "https://github.com/MelihAltintas/svelte-slimscroll/issues"
12 | },
13 | "main": "dist/index.js",
14 | "module": "dist/index.mjs",
15 | "svelte": "src/index.js",
16 | "scripts": {
17 | "build": "rollup -c",
18 | "dev": "rollup -c -w"
19 | },
20 | "keywords": [
21 | "svelte-slimscroll",
22 | "svelte",
23 | "svelte-scroll"
24 | ],
25 | "author": "Melih Altıntaş",
26 | "license": "MIT",
27 | "devDependencies": {
28 | "rollup": "^2.33.1",
29 | "rollup-plugin-node-resolve": "^5.2.0",
30 | "rollup-plugin-svelte": "^6.1.0",
31 | "svelte": "^3.29.4"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import resolve from 'rollup-plugin-node-resolve';
2 |
3 | const pkg = require('./package.json');
4 |
5 | export default {
6 | input: "src/index.js",
7 | output: [
8 | { file: pkg.module, 'format': 'en' },
9 | { file: pkg.main, 'format': 'umd', name: 'Name' }
10 | ],
11 | plugins: [
12 | resolve()
13 | ],
14 | };
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export {slimscroll} from "./slimscroll.js";
--------------------------------------------------------------------------------
/src/slimscroll.js:
--------------------------------------------------------------------------------
1 | var SlimScroll = (function () {
2 | function $(el) {
3 | if (!(this instanceof $)) {
4 | return new $(el)
5 | }
6 | if (typeof el === 'string') {
7 | var r = /<(\w+)><\/\1>$/.exec(el)
8 | if (r) {
9 | el = document.createElement(r[1])
10 | } else {
11 | el = document.querySelector(el)
12 | }
13 | }
14 | this.el = (el && el.nodeType === 1) ? el : document.documentElement
15 | return this
16 | }
17 |
18 | $.prototype = {
19 | parent: function () {
20 | return $(this.el.parentNode || this.el.parentElement)
21 | },
22 | closest: function (selector) {
23 | if (!selector) return $(document)
24 | var parent = this.parent()
25 |
26 | while (parent.el.className != $(selector).el.className) {
27 |
28 | parent = parent.parent()
29 | }
30 | return parent
31 | },
32 | is: function (obj) {
33 | if (this.el === obj.el) {
34 | return true
35 | }
36 | return false
37 | },
38 | hasClass: function (className) {
39 | if (this.el.className.indexOf(className) >= 0) {
40 | return true
41 | }
42 | return false
43 | },
44 | addClass: function (className) {
45 | if (!className || typeof className === 'undefined') return
46 | if (this.hasClass(className)) return
47 | var cls = this.el.className.split(' ')
48 | cls.push(className)
49 | this.el.className = cls.join(' ').trim()
50 | return this
51 | },
52 | css: function (styleObj) {
53 | if (typeof styleObj === 'string') {
54 | return this.el.style[styleObj].replace('px', '')
55 | }
56 | for (var key in styleObj) {
57 | if (typeof styleObj[key] === 'number' && parseInt(styleObj[key])) styleObj[key] = parseInt(styleObj[key]) + 'px'
58 | if (key === 'zIndex') styleObj[key] = parseInt(styleObj[key])
59 | this.el.style[key] = styleObj[key]
60 | }
61 | return this
62 | },
63 | show: function () {
64 | this.el.style.display = 'block'
65 | },
66 | hide: function () {
67 | this.el.style.display = 'none'
68 | },
69 | wrap: function (obj) {
70 | this.parent().el.insertBefore(obj.el, this.el)
71 | obj.append(this)
72 | return this
73 | },
74 | append: function (obj) {
75 | this.el.appendChild(obj.el)
76 | return this
77 | },
78 | scrollTop: function (y) {
79 | if (typeof y !== 'undefined') {
80 | this.el.scrollTop = parseInt(y)
81 | return this
82 | }
83 | return this.el.scrollTop
84 | },
85 | outerHeight: function () {
86 | return this.el.offsetHeight || this.el.clientHeight
87 | },
88 | hover: function (hoverIn, hoverOut) {
89 | this.bind('mouseenter', hoverIn)
90 | this.bind('mouseleave', hoverOut)
91 | },
92 | bind: function (type, fn, capture) {
93 | var el = this.el;
94 |
95 | if (window.addEventListener) {
96 | el.addEventListener(type, fn, capture);
97 |
98 | var ev = document.createEvent('HTMLEvents');
99 | ev.initEvent(type, capture || false, false);
100 | // 在元素上存储创建的事件,方便自定义触发
101 | if (!el['ev' + type]) {
102 | el['ev' + type] = ev;
103 | }
104 |
105 | } else if (window.attachEvent) {
106 | el.attachEvent('on' + type, fn);
107 | if (isNaN(el['cu' + type])) {
108 | // 自定义属性,触发事件用
109 | el['cu' + type] = 0;
110 | }
111 |
112 | var fnEv = function (event) {
113 | if (event.propertyName === 'cu' + type) {
114 | fn.call(el);
115 | }
116 | };
117 |
118 | el.attachEvent('onpropertychange', fnEv);
119 |
120 | // 在元素上存储绑定的propertychange事件,方便删除
121 | if (!el['ev' + type]) {
122 | el['ev' + type] = [fnEv];
123 | } else {
124 | el['ev' + type].push(fnEv);
125 | }
126 | }
127 |
128 | return this;
129 | },
130 | trigger: function (type) {
131 | var el = this.el;
132 | if (typeof type === 'string') {
133 | if (document.dispatchEvent) {
134 | if (el['ev' + type]) {
135 | el.dispatchEvent(el['ev' + type]);
136 | }
137 | } else if (document.attachEvent) {
138 | // 改变对应自定义属性,触发自定义事件
139 | el['cu' + type]++;
140 | }
141 | }
142 | return this;
143 | },
144 | unbind: function (type, fn, capture) {
145 | var el = this.el;
146 | if (window.removeEventListener) {
147 | el.removeEventListener(type, fn, capture || false);
148 | } else if (document.attachEvent) {
149 | el.detachEvent('on' + type, fn);
150 | var arrEv = el['ev' + type];
151 | if (arrEv instanceof Array) {
152 | for (var i = 0; i < arrEv.length; i += 1) {
153 | // 删除该方法名下所有绑定的propertychange事件
154 | el.detachEvent('onpropertychange', arrEv[i]);
155 | }
156 | }
157 | }
158 | return this;
159 | }
160 | }
161 |
162 | $.extend = function (deep) {
163 | var start = 1
164 | if (typeof deep === 'object') {
165 | start = 0
166 | }
167 | var objs = Array.prototype.slice.call(arguments, start),
168 | newObj = {}
169 |
170 | for (var i = 0; i < objs.length; i++) {
171 | if (typeof objs !== 'object') return
172 | for (var key in objs[i]) {
173 | newObj[key] = typeof objs[i][key] === 'object' && deep === true ? $.extend(true, objs[i][key]) : objs[i][key]
174 | }
175 | }
176 | return newObj
177 | }
178 |
179 | $.isPlainObject = function (obj) {
180 | return typeof obj === 'object' && !(obj instanceof Array)
181 | }
182 |
183 | function SlimScroll(el, options) {
184 | var defaults = {
185 |
186 | // width in pixels of the visible scroll area
187 | width: 'auto',
188 |
189 | // height in pixels of the visible scroll area
190 | height: '250px',
191 |
192 | // width in pixels of the scrollbar and rail
193 | size: '7px',
194 |
195 | // scrollbar color, accepts any hex/color value
196 | color: '#000',
197 |
198 | // scrollbar position - left/right
199 | position: 'right',
200 |
201 | // distance in pixels between the side edge and the scrollbar
202 | distance: '1px',
203 |
204 | // default scroll position on load - top / bottom / $('selector')
205 | start: 'top',
206 |
207 | // sets scrollbar opacity
208 | opacity: 0.4,
209 |
210 | // enables always-on mode for the scrollbar
211 | alwaysVisible: false,
212 |
213 | // check if we should hide the scrollbar when user is hovering over
214 | disableFadeOut: false,
215 |
216 | // sets visibility of the rail
217 | railVisible: false,
218 |
219 | // sets rail color
220 | railColor: '#333',
221 |
222 | // sets rail opacity
223 | railOpacity: 0.2,
224 |
225 | // whether we should use jQuery UI Draggable to enable bar dragging
226 | railDraggable: true,
227 |
228 | // defautlt CSS class of the slimscroll rail
229 | railClass: 'slimScrollRail',
230 |
231 | // defautlt CSS class of the slimscroll bar
232 | barClass: 'slimScrollBar',
233 |
234 | // defautlt CSS class of the slimscroll wrapper
235 | wrapperClass: 'slimScrollDiv',
236 |
237 | // check if mousewheel should scroll the window if we reach top/bottom
238 | allowPageScroll: false,
239 |
240 | // scroll amount applied to each mouse wheel step
241 | wheelStep: 20,
242 |
243 | // scroll amount applied when user is using gestures
244 | touchScrollStep: 200,
245 |
246 | // sets border radius
247 | borderRadius: '7px',
248 |
249 | // sets border radius of the rail
250 | railBorderRadius: '7px'
251 | };
252 |
253 |
254 |
255 | var o = $.extend(defaults, options)
256 |
257 | // do it for every element that matches selector
258 | // this.each(function () {
259 |
260 | var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
261 | barHeight, percentScroll, lastScroll,
262 | divS = '',
263 | minBarHeight = 30,
264 | releaseScroll = false;
265 |
266 | // used in event handlers and for better minification
267 | // var me = $(this);
268 | var me = $(el);
269 |
270 |
271 | // ensure we are not binding it again
272 | if (me.parent().hasClass(o.wrapperClass)) {
273 | // start from last bar position
274 | var offset = me.scrollTop();
275 |
276 | // find bar and rail
277 | bar = me.siblings('.' + o.barClass);
278 | rail = me.siblings('.' + o.railClass);
279 |
280 | getBarHeight();
281 |
282 | // check if we should scroll existing instance
283 | if ($.isPlainObject(options)) {
284 | // Pass height: auto to an existing slimscroll object to force a resize after contents have changed
285 | if ('height' in options && options.height === 'auto') {
286 | me.parent().css({ height: 'auto' });
287 | me.css({ height: 'auto' });
288 | var height = me.parent().parent().outerHeight();
289 | me.parent().css({ height: height });
290 | me.css({ height: height });
291 | } else if ('height' in options) {
292 | var h = options.height;
293 | me.parent().css({ height: h });
294 | me.css({ height: h });
295 | }
296 |
297 | if ('scrollTo' in options) {
298 | // jump to a static point
299 | offset = parseInt(o.scrollTo);
300 | }
301 | else if ('scrollBy' in options) {
302 | // jump by value pixels
303 | offset += parseInt(o.scrollBy);
304 | }
305 | else if ('destroy' in options) {
306 | // remove slimscroll elements
307 | bar.remove();
308 | rail.remove();
309 | me.unwrap();
310 | return;
311 | }
312 |
313 | // scroll content by the given offset
314 | scrollContent(offset, false, true);
315 | }
316 |
317 | return;
318 | } else if ($.isPlainObject(options)) {
319 | if ('destroy' in options) {
320 | return;
321 | }
322 | }
323 |
324 | // optionally set height to the parent's height
325 | o.height = (o.height === 'auto') ? me.parent().outerHeight() : o.height;
326 |
327 | // wrap content
328 | var wrapper = $(divS)
329 | .addClass(o.wrapperClass)
330 | .css({
331 | position: 'relative',
332 | overflow: 'hidden',
333 | width: o.width,
334 | height: o.height
335 | });
336 |
337 | // update style for the div
338 | me.css({
339 | overflow: 'hidden',
340 | width: o.width,
341 | height: o.height
342 | });
343 |
344 | // create scrollbar rail
345 | var rail = $(divS)
346 | .addClass(o.railClass)
347 | .css({
348 | width: o.size,
349 | height: '100%',
350 | position: 'absolute',
351 | top: 0,
352 | display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
353 | 'border-radius': o.railBorderRadius,
354 | background: o.railColor,
355 | opacity: o.railOpacity,
356 | zIndex: 998
357 | });
358 |
359 | // create scrollbar
360 | var bar = $(divS)
361 | .addClass(o.barClass)
362 | .css({
363 | background: o.color,
364 | width: o.size,
365 | position: 'absolute',
366 | top: 0,
367 | opacity: o.opacity,
368 | display: o.alwaysVisible ? 'block' : 'none',
369 | 'border-radius': o.borderRadius,
370 | BorderRadius: o.borderRadius,
371 | MozBorderRadius: o.borderRadius,
372 | WebkitBorderRadius: o.borderRadius,
373 | zIndex: 999
374 | });
375 |
376 | // set position
377 | var posCss = (o.position === 'right') ? { right: o.distance } : { left: o.distance };
378 | rail.css(posCss);
379 | bar.css(posCss);
380 |
381 | // wrap it
382 | me.wrap(wrapper);
383 |
384 | // append to parent div
385 | me.parent().append(bar);
386 | me.parent().append(rail);
387 |
388 |
389 | //all binding events callback
390 | var events = {
391 | touchStart: function (e, b) {
392 |
393 | if (e.touches.length) {
394 | // record where touch started
395 | touchDif = e.touches[0].pageY;
396 | }
397 | },
398 | touchMove: function (e) {
399 | // prevent scrolling the page if necessary
400 | if (!releaseScroll) {
401 | e.preventDefault();
402 | }
403 | if (e.touches.length) {
404 | // see how far user swiped
405 | var diff = (touchDif - e.touches[0].pageY) / o.touchScrollStep;
406 | // scroll content
407 | scrollContent(diff, true);
408 | touchDif = e.touches[0].pageY;
409 | }
410 | },
411 | hoverIn: function () {
412 | isOverPanel = true;
413 | showBar();
414 | hideBar();
415 | },
416 | hoverOut: function () {
417 | isOverPanel = false;
418 | hideBar();
419 | },
420 | barHoverIn: function () {
421 | isOverBar = true;
422 | },
423 | barHoverOut: function () {
424 | isOverBar = false;
425 | },
426 | railHoverIn: function () {
427 | showBar();
428 | },
429 | railHoverOut: function () {
430 | hideBar();
431 | },
432 | barMouseDown: function (e) {
433 | var $doc = $(document);
434 | var t = parseFloat(bar.css('top'));
435 | var pageY = e.pageY;
436 | isDragg = true;
437 |
438 | function mousemove(e) {
439 | var currTop = t + e.pageY - pageY;
440 | bar.css({ top: currTop });
441 | scrollContent(0, currTop, false);// scroll content
442 | }
443 |
444 | function mouseup(e) {
445 | isDragg = false; hideBar();
446 | $doc.unbind('mousemove', mousemove);
447 | $doc.unbind('mouseup', mouseup);
448 | }
449 |
450 | $doc.bind('mousemove', mousemove);
451 |
452 | $doc.bind('mouseup', mouseup);
453 | return false;
454 | },
455 | barSelectedStart: function (e) {
456 | e.stopPropagation();
457 | e.preventDefault();
458 | return false;
459 | }
460 | }
461 |
462 | // make it draggable and no longer dependent on the jqueryUI
463 | if (o.railDraggable) {
464 | bar.bind('mousedown', events.barMouseDown).bind('selectstart', events.barSelectedStart);
465 | }
466 |
467 | // on rail over
468 | rail.hover(events.railHoverIn, events.railHoverOut);
469 |
470 | // on bar over
471 | bar.hover(events.barHoverIn, events.barHoverOut);
472 |
473 | // show on parent mouseover
474 | me.hover(events.hoverIn, events.hoverOut);
475 |
476 | // support for mobile
477 | me.bind('touchstart', events.touchStart);
478 |
479 | me.bind('touchmove', events.touchMove);
480 |
481 | // set up initial height
482 | getBarHeight();
483 |
484 | // check start position
485 | if (o.start === 'bottom') {
486 | // scroll content to bottom
487 | bar.css({ top: me.outerHeight() - bar.outerHeight() });
488 | scrollContent(0, true);
489 | }
490 | else if (o.start !== 'top') {
491 | // assume jQuery selector
492 | scrollContent($(o.start).position().top, null, true);
493 |
494 | // make sure bar stays hidden
495 | if (!o.alwaysVisible) { bar.hide(); }
496 | }
497 |
498 | // attach scroll events
499 | attachWheel(el);
500 |
501 | function _onWheel(e) {
502 | // use mouse wheel only when mouse is over
503 | if (!isOverPanel) { return; }
504 |
505 | e = e || window.event;
506 |
507 | var delta = 0;
508 | if (e.wheelDelta) { delta = -e.wheelDelta / 120; }
509 | if (e.detail) { delta = e.detail / 3; }
510 |
511 | var target = e.target || e.srcTarget || e.srcElement;
512 | if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
513 | // scroll content
514 | scrollContent(delta, true);
515 | }
516 |
517 | // stop window scroll
518 | if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
519 | if (!releaseScroll) { e.returnValue = false; }
520 | }
521 |
522 | function scrollContent(y, isWheel, isJump) {
523 | releaseScroll = false;
524 | var delta = y;
525 | var maxTop = me.outerHeight() - bar.outerHeight();
526 |
527 | if (isWheel) {
528 | // move bar with mouse wheel
529 | delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();
530 |
531 | // move bar, make sure it doesn't go out
532 | delta = Math.min(Math.max(delta, 0), maxTop);
533 |
534 | // if scrolling down, make sure a fractional change to the
535 | // scroll position isn't rounded away when the scrollbar's CSS is set
536 | // this flooring of delta would happened automatically when
537 | // bar.css is set below, but we floor here for clarity
538 | delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);
539 |
540 | // scroll the scrollbar
541 | bar.css({ top: delta + 'px' });
542 | }
543 |
544 | // calculate actual scroll amount
545 | percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());
546 | // delta = percentScroll * (me[0].scrollHeight - me.outerHeight());
547 | delta = percentScroll * (me.el.scrollHeight - me.outerHeight());
548 |
549 | if (isJump) {
550 | delta = y;
551 | // var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
552 | var offsetTop = delta / me.el.scrollHeight * me.outerHeight();
553 | offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
554 | bar.css({ top: offsetTop + 'px' });
555 | }
556 |
557 | // scroll content
558 | me.scrollTop(delta);
559 |
560 | // fire scrolling event
561 | me.trigger('slimscrolling', ~~delta);
562 |
563 | // ensure bar is visible
564 | showBar();
565 |
566 | // trigger hide when scroll is stopped
567 | hideBar();
568 | }
569 |
570 | function attachWheel(target) {
571 | if (window.addEventListener) {
572 | target.addEventListener('DOMMouseScroll', _onWheel, false);
573 | target.addEventListener('mousewheel', _onWheel, false);
574 | }
575 | else {
576 | document.attachEvent('onmousewheel', _onWheel)
577 | }
578 | }
579 |
580 | function getBarHeight() {
581 | // calculate scrollbar height and make sure it is not too small
582 | barHeight = Math.max((me.outerHeight() / me.el.scrollHeight) * me.outerHeight(), minBarHeight);
583 | bar.css({ height: barHeight + 'px' });
584 |
585 | // hide scrollbar if content is not long enough
586 | var display = barHeight == me.outerHeight() ? 'none' : 'block';
587 | bar.css({ display: display });
588 | }
589 |
590 | function showBar() {
591 | // recalculate bar height
592 | getBarHeight();
593 | clearTimeout(queueHide);
594 |
595 | // when bar reached top or bottom
596 | if (percentScroll == ~~percentScroll) {
597 | //release wheel
598 | releaseScroll = o.allowPageScroll;
599 |
600 | // publish approporiate event
601 | if (lastScroll != percentScroll) {
602 | var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
603 | me.trigger('slimscroll', msg);
604 | }
605 | }
606 | else {
607 | releaseScroll = false;
608 | }
609 | lastScroll = percentScroll;
610 |
611 | // show only when required
612 | if (barHeight >= me.outerHeight()) {
613 | //allow window scroll
614 | releaseScroll = true;
615 | return;
616 | }
617 | // bar.stop(true, true).fadeIn('fast');
618 | bar.show()
619 | // if (o.railVisible) { rail.stop(true, true).fadeIn('fast'); }
620 | if (o.railVisible) { rail.show(); }
621 | }
622 |
623 | function hideBar() {
624 | // only hide when options allow it
625 | if (!o.alwaysVisible) {
626 | queueHide = setTimeout(function () {
627 | if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg) {
628 | // bar.fadeOut('slow');
629 | // rail.fadeOut('slow');
630 | bar.hide()
631 | rail.hide()
632 | }
633 | }, 1000);
634 | }
635 | }
636 |
637 | // });
638 |
639 | function unbind() {
640 | // make it draggable and no longer dependent on the jqueryUI
641 | bar.unbind('mousedown', events.barMouseDown).unbind('selectstart', events.barSelectedStart);
642 | // on rail over
643 | rail.unbind('mouseenter', events.railHoverIn).unbind('mouseleave', events.railHoverOut);
644 |
645 | // on bar over
646 | bar.unbind('mouseenter', events.barHoverIn).unbind('mouseleave', events.barHoverOut);
647 |
648 | // show on parent mouseover
649 | me.unbind('mouseenter', events.hoverIn).unbind('mouseleave', events.hoverOut);
650 |
651 | // support for mobile
652 | me.unbind('touchstart', events.touchStart);
653 |
654 | me.unbind('touchmove', events.touchMove);
655 | }
656 | return {
657 |
658 | unbind: function () {
659 |
660 |
661 | bar.unbind('mousedown', events.barMouseDown)
662 | .unbind('mouseenter', events.barHoverIn)
663 | .unbind('mouseleave', events.barHoverOut)
664 | .unbind('selectstart', events.barSelectedStart);
665 | rail.unbind('mouseenter', events.railHoverIn)
666 | .unbind('mouseleave', events.railHoverOut);
667 | bar.unbind('mouseenter', events.barHoverIn)
668 | .unbind('mouseleave', events.barHoverOut);
669 | me.unbind('mouseenter', events.hoverIn)
670 | .unbind('mouseleave', events.hoverOut)
671 | .unbind('touchstart', events.touchStart)
672 | .unbind('touchmove', events.touchMove);
673 | bar.el.remove();
674 | rail.el.remove();
675 |
676 | },
677 |
678 | }
679 | }
680 |
681 | return SlimScroll
682 | })()
683 |
684 |
685 |
686 |
687 | function unwrap(node) {
688 | if(node != undefined && node != null)
689 | node.replaceWith(...node.childNodes);
690 | }
691 |
692 | export function slimscroll(node, options) {
693 | // the node has been mounted in the DOM
694 |
695 | let slim = SlimScroll(node,options)
696 | return {
697 | update(options) {
698 |
699 | slim.unbind()
700 | unwrap(node.parentNode);
701 | slim = SlimScroll(node,options)
702 |
703 | },
704 |
705 | destroy() {
706 | // the node has been removed from the DOM
707 | slim.unbind();
708 | unwrap(node.parentNode);
709 | }
710 | };
711 | }
712 |
713 |
--------------------------------------------------------------------------------