forked from lorenzofox3/lrStickyHeader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lrStickyHeader.js
126 lines (110 loc) · 4.04 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
(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 = this.offsetTopOverride ? this.offsetTopOverride : getOffset(this.thead, 'offsetTop');
var offsetLeft = getOffset(this.thead, 'offsetLeft');
var classes = this.thead.className.split(' ');
var scrollPosition = this.isWindowScroll ? this.scrollContainer.scrollY : this.scrollContainer.scrollTop;
if (this.stick !== true && (offsetTop - scrollPosition < 0)) {
this.stick = true;
this.treshold = offsetTop;
this.setWidth();
this.thead.style.left = offsetLeft + 'px';
this.thead.style.top = this.isWindowScroll ? 0 : this.scrollContainer.getBoundingClientRect().top + 'px';
setTimeout(function () {
classes.push('lr-sticky-header');
this.thead.style.position = 'fixed';
this.thead.className = classes.join(' ');
}.bind(this), 0);
}
if (this.stick === true && (this.treshold - scrollPosition > 0)) {
this.stick = false;
this.thead.style.position = 'initial';
classes.splice(classes.indexOf('lr-sticky-header'), 1);
this.thead.className = (classes).join(' ');
}
}
};
return function lrStickyHeader (tableElement, options) {
options = options || {};
options.scrollContainer = options.scrollContainer || window;
options.offsetTopOverride = options.offsetTopOverride || null;
var isWindowScroll = options.scrollContainer === window;
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},
scrollContainer: { value: options.scrollContainer },
isWindowScroll: { value: isWindowScroll },
offsetTopOverride: { value: options.offsetTopOverride },
thead: {
get: function () {
return thead;
}
},
tbody: {
get: function () {
return tbody;
}
}
});
var listener = stickyTable.eventListener.bind(stickyTable);
options.scrollContainer.addEventListener('scroll', listener);
stickyTable.clean = function clean () {
options.scrollContainer.removeEventListener('scroll', listener);
};
return stickyTable;
};
});