-
Notifications
You must be signed in to change notification settings - Fork 0
/
stickystuff.js
executable file
·185 lines (148 loc) · 6.24 KB
/
stickystuff.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*!
stickystuff
A jQuery plug-in for persistent table header
https://github.com/lancevo/Sticky-Stuff/
Copyright (C) 2012 Lance Vo
Licensed under MIT
*/
(function ($) {
// By Remy Sharp http://remysharp.com/2010/07/21/throttling-function-calls/
function throttle(fn, delay) {
var timer = null;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
};
}
$.fn.stickystuff = function (opts) {
return this.each(function () {
// get existing stickytableheader instance
var _instance = $.data(this, "stickystuff") || undefined;
if (!_instance) {
console.log('new');
_instance = new stickyheader(this);
$.data(this, "stickystuff", _instance);
//return this;
}
if (typeof opts === "string") {
switch(opts) {
case 'enable' : _instance.enable(); break;
case 'disable' : _instance.disable(); break;
case 'destroy' : _instance.destroy(); break;
default: throw 'stickystuff: invalid parameter';
}
}
return this;
});
function stickyheader(el) {
// default parameters
var o = {
// add classnames to cloned header
classnames : '',
// add attributes cloned header
attributes: '',
// throttle browser scrolling execution
throttle: 50
},
self = this,
// original table
table = $(el),
cloneId = "stickystuff" + Math.floor(Math.random() * 1000),
// cloned table
clone,
isStarted = false,
$window = $(window)
;
if (!table.find("thead").length) {
throw 'stickystuff: <thead> is required';
return;
}
if (typeof opts === "object") {
$.extend(o, opts);
}
clone = $('<table id="' + cloneId + '" class="stickystuff-cloned ' + o.classnames + '"' + o.attributes + ' ></table>')
table.thead = table.find("thead");
clone.thead = table.thead.clone();
// insert header into clone table
clone.prepend(clone.thead);
table.headerHeight = table.thead.height();
calculateOffset();
measureHeader();
// fix issue with columns don't align
clone.width( table.outerWidth());
table.attr('data-stickystuff', cloneId);
// insert clone table into DOM before the original table
clone.hide().insertBefore(table);
enable();
// measure the column widths and apply it to the cloned header
function measureHeader() {
var clonedThs = clone.thead.find("th");
table.thead.find("th").each(function(i){
//set width to clone header columns
$(clonedThs[i]).width($(this).width());
$(clonedThs[i]).outerWidth($(this).outerWidth());
console.log('c vs o : ' + $(clonedThs[i]).width() + ' ' + $(this).width());
console.log('outer c vs o : ' + $(clonedThs[i]).outerWidth() + ' ' + $(this).outerWidth());
$(clonedThs[i]).height($(this).height());
});
clone.width(table.width());
}
// calculate offset of table on the page
// to determine when to show the sticky header
function calculateOffset() {
table.startPos = table.offset().top + table.headerHeight;
// sometimes weird thing happen, unable to calculate the offset
if (isNaN(table.startPos)) {
table.startPos = parseFloat(table.css("marginTop")) + table.headerHeight;
}
table.stopPos = table.offset().top + table.height();
}
// clone table show/hide manager
function toggle() {
var currentPos = $window.scrollTop() + table.headerHeight;
if (currentPos > table.startPos && currentPos < table.stopPos) {
// desktop
if (!isStarted) {
isStarted = true;
table.thead.css('visibility','hidden');
clone.show();
}
} else {
if (isStarted) {
isStarted = false;
clone.hide();
table.thead.css('visibility','');
}
}
}
// enable and bind event listener to window scroll
function enable() {
// no need for throttle with modern browser like Chrome
$window.bind("scroll", throttle(toggle, o.throttle));
// re-trigger the toggle if it hasn't, ie: page is preloaded in the middle of the table, and it hasn't been activated
$window.scroll();
}
// disable sticky header
function disable(){
$window.unbind("scroll", toggle);
table.thead.css('visibility','');
isStarted = false;
clone.hide();
}
// stop and remove sticky header
function destroy() {
disable();
$.data(self, "stickystuff", undefined);
clone.remove();
}
return {
enable: enable,
disable: disable,
destroy : destroy
};
} // stickyheader
} // fn
}(jQuery));