-
Notifications
You must be signed in to change notification settings - Fork 0
/
scroll.js
126 lines (90 loc) · 3.11 KB
/
scroll.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
function Scroll(element) {
var main = element.querySelector('.js-scroll-main');
var bar = element.querySelector('.js-scroll-bar');
var handler = element.querySelector('.js-scroll-bar-handler');
var resizeMain = element.querySelector('.js-scroll-resize-main');
var resizeContent = element.querySelector('.js-scroll-resize-content');
// Create custom events tight to the current instance.
this._calculate = this._bind(this._calculate);
this._scroll = this._bind(this._scroll);
this._mouseDown = this._bind(this._mouseDown);
this._mouseMove = this._bind(this._mouseMove);
this._mouseUp = this._bind(this._mouseUp);
// Cache references.
this._main = main;
this._bar = bar;
this._handler = handler;
// Calculate.
this._calculate();
// Resize events.
if (resizeMain && resizeContent) {
resizeMain.contentWindow['onresize'] = this._calculate;
resizeContent.contentWindow['onresize'] = this._calculate;
}
// Common events.
this._addEvent(handler, 'mousedown', this._mouseDown);
this._addEvent(main, 'scroll', this._scroll);
}
Scroll.prototype = {
_main: null,
_bar: null,
_handler: null,
_diff: 0,
_yStart: 0,
_positionStart: 0,
calculate: function() {
this._calculate();
},
_bind: function(method) {
var that = this;
return function() {
return method.apply(that, arguments);
};
},
_addEvent: function(element, eventName, handler) {
if (element.addEventListener) {
element.addEventListener(eventName, handler);
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, handler);
}
},
_removeEvent: function(element, eventName, handler) {
if (element.removeEventListener) {
element.removeEventListener(eventName, handler);
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, handler);
}
},
_calculate: function() {
var barHeight = this._bar.offsetHeight;
var scrollWidth = this._main.offsetWidth - this._main.clientWidth;
var scrollHeight = this._main.scrollHeight;
var scrollVisibleHeight = this._main.offsetHeight;
var handlerHeight = Math.round(scrollVisibleHeight * barHeight / scrollHeight);
this._main.style.marginRight = -scrollWidth + 'px';
this._handler.style.height = handlerHeight + 'px';
this._diff = (barHeight - handlerHeight) / (scrollHeight - scrollVisibleHeight);
this._scroll();
},
_scroll: function() {
this._handler.style.top = this._main.scrollTop * this._diff + 'px';
},
_mouseDown: function(evt) {
this._addEvent(document, 'mousemove', this._mouseMove);
this._addEvent(document, 'mouseup', this._mouseUp);
this._addEvent(document, 'selectstart', this._preventDefault);
this._yStart = evt.clientY;
this._positionStart = this._main.scrollTop;
},
_mouseMove: function(evt) {
this._main.scrollTop = this._positionStart + (evt.clientY - this._yStart) / this._diff;
},
_mouseUp: function() {
this._removeEvent(document, 'mousemove', this._mouseMove);
this._removeEvent(document, 'mouseup', this._mouseUp);
this._removeEvent(document, 'selectstart', this._preventDefault);
},
_preventDefault: function(evt) {
evt.preventDefault ? evt.preventDefault() : evt.returnValue = false;
}
};