forked from lorenzofox3/lrStickyHeader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lrStickyHeader.js
158 lines (141 loc) · 5 KB
/
lrStickyHeader.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module unless amdModuleId is set
define([], function () {
return (global['lrStickyHeader'] = factory(global));
});
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(global);
} else {
global['lrStickyHeader'] = factory(global);
}
})(window, function factory (window) {
'use strict';
function getOffset (element, property) {
var offset = element[property];
var parent = element;
while ((parent = parent.offsetParent) !== null) {
offset += parent[property];
}
return offset;
}
var sticky = {
//todo some memoize stuff
setWidth: function setWidth () {
var firstRow = this.tbody.getElementsByTagName('TR')[0];
var trh = this.thead.getElementsByTagName('TR')[0];
var firstTds;
var firstThs;
function setCellWidth (cell) {
cell.style.width = cell.offsetWidth + 'px';
}
if (firstRow && trh) {
firstTds = firstRow.getElementsByTagName('TD');
firstThs = trh.getElementsByTagName('TH');
[].forEach.call(firstTds, setCellWidth);
[].forEach.call(firstThs, setCellWidth);
}
},
eventListener: function eventListener () {
var offsetTop = getOffset(this.thead, 'offsetTop') - Number(this.headerHeight);
var offsetLeft = getOffset(this.thead, 'offsetLeft');
var parentOffsetTop = this.parentIsWindow ? 0 : getOffset(this.parent, 'offsetTop');
var parentScrollTop = this.parentIsWindow ? parent.scrollY : this.parent.scrollTop;
var classes = this.thead.className.split(' ');
if (this.stick !== true && (offsetTop - (parentOffsetTop + parentScrollTop) < 0) &&
(offsetTop + this.tbody.offsetHeight - (parentOffsetTop + parentScrollTop) > 0) &&
(this.tbody.getBoundingClientRect().bottom > 0)) {
this.stick = true;
this.threshold = offsetTop;
this.windowScrollY = this.parentIsWindow ? 0 : window.scrollY;
this.setWidth();
this.thead.style.left = offsetLeft + 'px';
this.thead.style.top = Number(this.headerHeight + parentOffsetTop - this.windowScrollY) + 'px';
setTimeout(function () {
classes.push('lr-sticky-header');
this.thead.style.position = 'fixed';
this.thead.className = classes.join(' ');
this.element.style.marginTop = Number(this.thead.offsetHeight) + 'px';
}.bind(this), 0);
}
if (this.stick === true && !this.parentIsWindow && this.windowScrollY !== window.scrollY) {
this.windowScrollY = window.scrollY;
this.thead.style.top = Number(this.headerHeight + parentOffsetTop - this.windowScrollY) + 'px';
}
if (this.stick === true && (
(this.parentIsWindow && (this.threshold - parentScrollTop > 0)) ||
(parentScrollTop <= 0) ||
(this.tbody.getBoundingClientRect().bottom < 0)
)) {
this.stick = false;
this.thead.style.position = 'initial';
classes.splice(classes.indexOf('lr-sticky-header'), 1);
this.thead.className = (classes).join(' ');
this.element.style.marginTop = '0';
}
}
};
return function lrStickyHeader (tableElement, options) {
var headerHeight = 0;
if (options&&options.headerHeight)
headerHeight=options.headerHeight;
var parent = window;
if (options && options.parent) {
parent = options.parent;
}
var thead;
var tbody;
if (tableElement.tagName !== 'TABLE') {
throw new Error('lrStickyHeader only works on table element');
}
tbody = tableElement.getElementsByTagName('TBODY');
thead = tableElement.getElementsByTagName('THEAD');
if (!thead.length) {
throw new Error('could not find the thead group element');
}
if (!tbody.length) {
throw new Error('could not find the tbody group element');
}
thead = thead[0];
tbody = tbody[0];
var stickyTable = Object.create(sticky, {
element: {value: tableElement},
parent: {
get: function () {
return parent;
}
},
parentIsWindow: {value: parent === window},
headerHeight: {
get: function () {
return headerHeight;
}
},
thead: {
get: function () {
return thead;
}
},
tbody: {
get: function () {
return tbody;
}
}
});
var listener = stickyTable.eventListener.bind(stickyTable);
parent.addEventListener('scroll', listener);
if (parent !== window) {
window.addEventListener('scroll', listener);
}
stickyTable.clean = function clean () {
parent.removeEventListener('scroll', listener);
if (parent !== window) {
window.removeEventListener('scroll', listener);
}
};
return stickyTable;
};
});