FixedTableHeader Demo Page with vanilla javascript |
Please scroll page for see action and plugin description.
You will see fixed header foreach table when you scroll down the page.
School | Date | Time1 | Time2 | Time 3 | Facility |
---|---|---|---|---|---|
tfoottestrow | |||||
School 1 | 01.01.2009 | 08:00 | 10:00 | 11:00 | Location of Event |
School 2 | 02.01.2009 | 10:00 | 12:00 | 16:00 | Location of Event |
School 3 | 03.01.2009 | 8:00 | 10:00 | 17:00 | Location of Event |
School 4 | 04.01.2009 | 10:00 | 10:43 | 10:00 | Location of Event |
School 5 | 05.01.2009 | 10:00 | 10:00 | 10:00 | Location of Event |
School 6 | 06.01.2009 | 10:00 | 21:00 | 10:00 | Location of Event |
School 7 | 07.01.2009 | 09:00 | 10:00 | 14:00 | Location of Event |
School 8 | 08.01.2009 | 10:00 | 14:00 | 10:00 | Location of Event |
School 9 | 09.01.2009 | 6:00 | 10:00 | 10:00 | Location of Event |
School 10 | 10.01.2009 | 10:00 | 10:00 | 10:00 | Location of Event |
School 11 | 11.01.2009 | 10:00 | 10:00 | 10:00 | Location of Event |
School 12 | 12.01.2009 | 7:00 | 10:00 | 10:00 | Location of Event |
School 13 | 13.01.2009 | 10:00 | 15:00 | 16:00 | Location of Event |
School 14 | 14.01.2009 | 10:00 | 18:00 | 19:00 | Location of Event |
School 15 | 15.01.2009 | 10:00 | 10:00 | 13:00 | Location of Event |
School 16 | 16.01.2009 | 6:00 | 10:00 | 12:00 | Location of Event |
School 17 | 17.01.2009 | 10:00 | 16:00 | 20:00 | Location of Event |
School 18 | 18.01.2009 | 10:00 | 11:00 | 17:00 | Location of Event |
Courses--Autumn2009 | ||||
---|---|---|---|---|
Course Name | CourseTutor | Summary | Code | Fee |
Course Name 1 | Dr.John | The course will....................... | H27 | $32 |
Course Name 2 | Dr.John | The course will....................... | H28 | $18 |
Course Name 3 | Dr.John | The course will....................... | H30 | $43 |
Course Name 4 | Dr.John | The course will....................... | H27 | $32 |
Course Name 5 | Dr.John | The course will....................... | H28 | $18 |
Course Name 6 | Dr.John | The course will....................... | H30 | $18 |
Course Name 7 | Dr.John | The course will....................... | H27 | $32 |
Course Name 8 | Dr.John | The course will....................... | H28 | $18 |
Course Name 9 | Dr.John | The course will....................... | H30 | $18 |
Course Name 10 | Dr.John | The course will....................... | H27 | $32 |
Course Name 11 | Dr.John | The course will....................... | H28 | $18 |
Course Name 12 | Dr.John | The course will....................... | H30 | $18 |
TIMETABLE | |||||
---|---|---|---|---|---|
STATIONA | STATIONB | ||||
WorkDays | Saturday | Sunday | WorkDays | Saturday | Sunday |
05:50 | 06:00 | 06:20 | 06:20 | 06:30 | 07:25 |
06:10 | 06:15 | 06:40 | 06:50 | 07:00 | 07:45 |
06:30 | 06:30 | 07:00 | 07:10 | 07:15 | 08:00 |
06:45 | 06:45 | 07:20 | 07:30 | 07:30 | 08:20 |
¦07:00¦ | 07:00 | 07:35 | 07:50 | 07:45 | 08:35 |
07:10 | 07:15 | 07:50 | 08:10 | 08:00 | 08:50 |
¦07:10¦ | 07:30 | 08:00 | 08:30 | 08:20 | 09:00 |
¦07:20¦ | 07:40 | 08:10 | 08:45 | 08:35 | 09:15 |
07:30 | 07:50 | 08:20 | 08:55 | 08:50 | 09:30 |
¦07:40¦ | 08:00 | 08:30 | 09:05 | 09:05 | 09:45 |
07:50 | 08:10 | 08:50 | 09:15 | 09:15 | 10:00 |
08:00 | 08:20 | 09:10 | 09:30 | 09:30 | 10:15 |
¦08:15¦ | 08:30 | 09:30 | 09:45 | 09:40 | 10:35 |
08:15 | 08:45 | 09:45 | 10:00 | 09:50 | 10:50 |
08:30 | 09:00 | 10:00 | 10:15 | 10:05 | 11:05 |
08:50 | 09:15 | 10:10 | 10:30 | 10:20 | 11:15 |
09:10 | 09:30 | 10:20 | 10:45 | 10:30 | 11:25 |
09:30 | 09:45 | 10:35 | 11:00 | 10:45 | 11:45 |
09:45 | 10:00 | 10:45 | 11:15 | 11:00 | 11:55 |
10:00 | 10:10 | 10:55 | 11:30 | 11:15 | 12:05 |
10:15 | 10:25 | 11:10 | 11:45 | 11:30 | 12:20 |
10:30 | 10:35 | 11:25 | 12:00 | 11:45 | 12:35 |
10:45 | 10:50 | 11:40 | 12:15 | 12:00 | 12:50 |
11:00 | 11:05 | 11:55 | 12:35 | 12:20 | 13:05 |
11:15 | 11:20 | 12:10 | 12:55 | 12:35 | 13:20 |
11:30 | 11:35 | 12:20 | 13:10 | 12:50 | 13:30 |
11:45 | 11:55 | 12:35 | 13:25 | 13:00 | 13:45 |
12:05 | 12:15 | 12:50 | 13:40 | 13:20 | 14:00 |
12:20 | 12:35 | 13:00 | 14:00 | 13:40 | 14:10 |
12:35 | 12:50 | 13:10 | 14:20 | 13:55 | 14:20 |
12:50 | 13:05 | 13:25 | 14:35 | 14:10 | 14:35 |
13:05 | 13:25 | 13:40 | 14:55 | 14:25 | 14:50 |
13:20 | 13:45 | 13:55 | 15:10 | 14:40 | 15:05 |
13:35 | 14:05 | 14:10 | 15:30 | 15:00 | 15:20 |
13:50 | 14:20 | 14:25 | 15:50 | 15:20 | 15:35 |
14:10 | 14:35 | 14:35 | 16:05 | 15:40 | 15:45 |
14:30 | 14:55 | 14:50 | 16:25 | 16:10 | 16:00 |
14:50 | 15:10 | 15:05 | 16:40 | 16:30 | 16:15 |
15:10 | 15:25 | 15:15 | 17:00 | 16:50 | 16:25 |
15:30 | 15:40 | 15:25 | ¦17:10¦ | 17:05 | 16:35 |
15:50 | 15:55 | 15:40 | 17:15 | 17:20 | 16:50 |
16:05 | 16:15 | 15:55 | 17:30 | 17:35 | 17:05 |
16:20 | 16:35 | 16:10 | 17:45 | 17:50 | 17:20 |
16:35 | 16:55 | 16:25 | 17:55 | 18:10 | 17:30 |
16:55 | 17:10 | 16:40 | 18:15 | 18:30 | 17:50 |
17:15 | 17:30 | 16:50 | ¦18:30¦ | 18:45 | 18:00 |
17:30 | 17:45 | 17:05 | 18:45 | 19:00 | 18:20 |
17:45 | 18:00 | 17:25 | 19:05 | 19:15 | 18:30 |
18:00 | 18:15 | 17:40 | 19:20 | 19:30 | 18:45 |
¦18:10¦ | 18:30 | 17:55 | ¦19:35¦ | 19:45 | 19:00 |
18:20 | 18:50 | 18:15 | 19:45 | 20:00 | 19:15 |
18:40 | 19:10 | 18:35 | 20:05 | 20:20 | 19:40 |
19:00 | 19:30 | 18:50 | 20:25 | 20:40 | 19:55 |
19:15 | 19:50 | 19:05 | 20:40 | 21:00 | 20:10 |
19:30 | 20:10 | 19:20 | 20:55 | 21:20 | 20:25 |
19:45 | 20:35 | 19:35 | 21:15 | 21:45 | 20:40 |
20:05 | 21:00 | 19:55 | 21:30 | 22:10 | 21:00 |
20:30 | 21:30 | 20:15 | 21:50 | 22:40 | 21:25 |
21:00 | 22:00 | 20:45 | 22:10 | 23:10 | 21:55 |
21:30 | 21:10 | 22:40 | 22:20 | ||
22:00 | 23:10 |
Just copy the code below and paste it into a file, then call it at the bottom of your page.
Important : for code to work, structure of tables must be as follow :
<div id="content">
<table>
<thead>
<tr>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
</tr>
</tbody>
</table>
</div>
and should be within a unique div tag with an id (one div for all tables).
The script needs two params : the id of the wrapper and marging (number) between top of the page and bottom of an eventualy fixed block (as menu for example). This marging can be equal to zero.
var idContainer = 'DemoContent';
/*
# ------------------ BEGIN LICENSE BLOCK ------------------
#
# This file is part of SIGesTH
#
# Copyright (c) 2009 - 2015 Cyril MAGUIRE,
# Licensed under the CeCILL v2.1 license.
# See http://www.cecill.info/licences.fr.html
#
# ------------------- END LICENSE BLOCK -------------------
*/
// marge est la distance entre le haut de la fenêtre et le haut du tableau
// à partir de laquelle l'entête du tableau est en position fixe
// Utile s'il y a un bloc fixe en haut de page, afin d'éviter que l'entête du tableau ne s'affiche en dessous
if (marge == undefined || marge == null || isNaN(marge) == true) var marge = 0;
if (idContainer == undefined || idContainer == null) {
var idContainer;
alert('Message de fixedTableHeader.js : Vous devez définir un container !');
}
if (document.getElementById(idContainer) == undefined) {
alert('Message de fixedTableHeader.js : Le container '+idContainer+' n\'existe pas !');
}
;(function(idContainer,marge,window,undefined){
'use_strict';
if (idContainer == undefined || idContainer == null) return;
// On convertit en integer en utilisant |0 à la place de parseInt moins fiable
// voir http://www.js-attitude.fr/2012/12/26/convertir-un-nombre-en-texte-en-javascript/
marge = (marge|0);
var isIE = isBrowserIE();
function isBrowserIE() {
//var isMSIE = /*@cc_on!@*/0;
var nav = navigator.userAgent.toLowerCase();
return (nav.indexOf('msie') != -1) ? (nav.split('msie')[1]|0) : false;
}
function Remove(idOfParent,idToRemove) {
if (isIE) {
document.getElementById(idToRemove).removeNode(true);
} else {
var Node1 = document.getElementById(idOfParent);
var len = Node1.childNodes.length;
for(var i = 0; i < len; i++){
if (Node1.childNodes[i] != undefined && Node1.childNodes[i].id != undefined && Node1.childNodes[i].id == idToRemove){
Node1.removeChild(Node1.childNodes[i]);
}
}
}
}
function addElement(DomParent,elemToAdd,htmlToInsert,id) {
var newElement = document.createElement('div');
document.body.appendChild(newElement);
newElement.innerHTML = htmlToInsert;
if (id != '') {
newElement.setAttribute('id',id+'_wrapper');
}
}
function getScrollPosition() {
return Array(
(document.documentElement && document.documentElement.scrollLeft) || window.pageXOffset || self.pageXOffset || document.body.scrollLeft,
(document.documentElement && document.documentElement.scrollTop) || window.pageYOffset || self.pageYOffset || document.body.scrollTop
);
}
function arrayCompare(a1, a2) {
if (a1.length != a2.length) return false;
var length = a2.length;
for (var i = 0; i < length; i++) {
if (a1[i] !== a2[i]) return false;
}
return true;
}
function inArray(needle, haystack) {
var length = haystack.length;
for(var i = 0; i < length; i++) {
if(typeof haystack[i] == 'object') {
if(arrayCompare(haystack[i], needle)) return true;
} else {
if(haystack[i] == needle) return true;
}
}
return false;
}
/*
Récupère la position réelle d'un objet dans la page (en tenant compte de tous ses parents)
IN : Obj => Javascript Object ; Prop => Offset voulu (offsetTop,offsetLeft,offsetBottom,offsetRight)
OUT : Numérique => position réelle d'un objet sur la page.
*/
function GetDomOffset( Obj, Prop ) {
var iVal = 0;
while (Obj && (Obj.tagName != 'body' || Obj.tagName != 'BODY')) {
eval('iVal += Obj.' + Prop + ';');
Obj = Obj.offsetParent;
}
return iVal;
}
var fixedHeaderTable = {
tbl:[],
init: function() {
this.addEventListener(window,"scroll", this);
},
addEventListener: function(el, eventName, handler) {
if (el.addEventListener) {
el.addEventListener(eventName, handler, false);
} else {
el.attachEvent('on' + eventName, fixedHeaderTable.handleEvent);
}
},
handleEvent: function(e) {
var evt = e ? e:event;
if (isIE) {
var obj = null;
obj = fixedHeaderTable;
} else {
var obj = Object.create(null);
obj = this;
}
var pos = getScrollPosition();
var tabPos = [];
var c = obj.tbl.length;
for (var i = 0; i < c; i++) {
if (obj.tbl[i] != undefined) {
tabPos[i] = (obj.tbl[i].posTop - (2*marge)) ;
pos[1] += obj.tbl[i].containerPosTop;
if (obj.tbl[i].posTop > 0 && obj.tbl[i].posBottom > 0) {
if (pos[1] < tabPos[i]) {
obj.action(i,false);
}
if (pos[1] > (tabPos[i]) ) {
obj.action(i,true);
}
if (pos[1] >= obj.tbl[i].posBottom ) {
obj.action(i,false);
}
}
}
};
},
action: function(i,display) {
var clone = document.getElementById('fixedtableheader'+i);
if (clone) {
if (display === true) {
clone.style.display = 'block';
}
if (display === false) {
clone.style.display = 'none';
}
}
},
};
var posBottom = 0;
var posTop = 0;
var mainDiv = document.getElementById(idContainer);
var disp = mainDiv.style.display;
if (disp == '') { disp = 'block'; }
var containerPosTop = 0;
// afin de déterminer la position des tableaux, on affiche le bloc qui les contient, s'il est masqué
if(disp != 'block') {
mainDiv.style.display = 'block';
containerPosTop = GetDomOffset( mainDiv, 'offsetTop' );
}
var tables = mainDiv.getElementsByTagName('table');
// widths est l'ensemble des largeurs de colonnes pour chaque tableau
var widths = [];
if (tables.length > 0){
var c = tables.length;
for (var i = 0; i < c; i++) {
var lastcell = tables[i].getElementsByTagName('tr');
for (var j = 0,clast = lastcell.length; j <= clast; j++) {
if(j == 0) { posTop = GetDomOffset(lastcell[0],'offsetTop');}
if(j == clast) { posBottom = GetDomOffset(lastcell[j-1],'offsetTop');}
}
fixedHeaderTable.tbl[i] = new Object();
fixedHeaderTable.tbl[i].table = tables[i];
fixedHeaderTable.tbl[i].containerPosTop = containerPosTop;
fixedHeaderTable.tbl[i].posTop = posTop;
fixedHeaderTable.tbl[i].posBottom = posBottom;
fixedHeaderTable.tbl[i].posLeft = GetDomOffset( tables[i], 'offsetLeft' );
var size = [];
size[i] = tables[i].getElementsByTagName('thead');
var tableBody = [];
tableBody[i] = tables[i].getElementsByTagName('tbody');
if (size[i][0]) {
var nbOfRowsInHead = size[i][0].getElementsByTagName('tr').length;
}
// TBODY
var tBod = tables[i].getElementsByTagName('tbody');
if (tBod[0]) {
var nbOfRows = tBod[0].getElementsByTagName('tr');
}
var nbOfCols = 0;
var cellsOfThisRow = [];
if (nbOfRows) {
var allRowsOfBody = nbOfRows.length;
for (var thisRow = 0; thisRow < allRowsOfBody; thisRow++) {
cellsOfThisRow[thisRow] = nbOfRows[thisRow].getElementsByTagName('td');
var nbOfTdInThisRow = cellsOfThisRow[thisRow].length;
nbOfCols = (nbOfTdInThisRow >= nbOfCols ? nbOfTdInThisRow : nbOfCols);
}
}
var colWidth = [];
var indexOfCol = 0;
if (allRowsOfBody) {
for (var row = 0; row < allRowsOfBody; row++) {
var nbOfCells= cellsOfThisRow[row].length;
for (var cel = 0; cel < nbOfCells; cel++) {
var widthOfThisCell = cellsOfThisRow[row][cel].offsetWidth;
colWidth[indexOfCol] = (widthOfThisCell > colWidth[indexOfCol] ? colWidth[indexOfCol] : widthOfThisCell);
indexOfCol++;
}
}
}
// THEAD
indexOfCol = 0;
if (size[i][0]) {
// largeurs est l'ensemble des largeurs de colonnes pour un tableau donné
var largeurs = [];
widths[i] = [];
var dec = 0
var decalage = [];
// Pour chaque ligne d'entête
for (var k = 0; k < nbOfRowsInHead; k++) {
if (size[i][k] != undefined) {
if(disp == 'block') {
fixedHeaderTable.tbl[i].posBottom -= ((size[i][k].offsetHeight/2)+marge);
} else {
fixedHeaderTable.tbl[i].containerPosTop -= ((size[i][k].offsetHeight*2)+marge);
}
var cells = size[i][k].getElementsByTagName('th');
var ccells = cells.length;
for (var l = 0; l < ccells; l++) {
largeurs[indexOfCol] = colWidth[indexOfCol];
if (indexOfCol 3) {
var colsp = cells[larg].getAttribute('colspan');
if (colsp == null) {
widths[i].push(largeurs[larg]);
}
} else {
widths[i].push(largeurs[larg]);
}
var rowsp = cells[larg].getAttribute('rowspan');
if (rowsp == null) {
decalage[dec] = largeurs[larg];
dec++;
}
}
}
var clone = size[i][k].cloneNode(true);
var cloneBody = tableBody[i][k].cloneNode(true);
var mainTab = document.createElement('div');
mainDiv.setAttribute('style', 'position:relative;');
cloneBody.setAttribute('style', 'visibility:hidden;border:none;');
var cellsBodyFake = cloneBody.getElementsByTagName('td');
var nbTds = cellsBodyFake.length;
for (var m = 0; m < nbTds; m++) {
cellsBodyFake[m].setAttribute('style','border:none;');
};
mainDiv.appendChild(mainTab);
mainTab.innerHTML = '
';
mainTab.setAttribute('style', 'position:relative;border:none;');
var tabFake = document.getElementById('fixedtableheader'+i);
tabFake.setAttribute('style', 'display:block;position:fixed;top:'+marge+'px;max-width:'+mainTab.offsetWidth+'px;background:transparent;border:none;');
tabFake.style.display = 'none';
tabFake.appendChild(clone);
tabFake.appendChild(cloneBody);
var rowsFake = document.getElementById('fixedtableheader'+i).getElementsByTagName('tr');
var cellsFake = rowsFake[0].getElementsByTagName('th');
var indexOfWidth = 0;
for (var m = 0; m < nbOfCols; m++) {
if (cellsFake[m] != undefined) {
var rowsp = cellsFake[m].getAttribute('rowspan');
if (rowsp == null && decalage[m] != undefined) {
if (cellsFake[m].getAttribute('style') != '') {
cellsFake[m].setAttribute('style','min-width:'+decalage[m]+'px;');
}
}
var colsp = cellsFake[m].getAttribute('colspan');
if (colsp != null && rowsp == null) {
if (cellsFake[m].getAttribute('style') != '') {
var w = 0;
var colspanWidth = 0;
while (w != colsp) {
colspanWidth += widths[i][m+w];
w++;
}
cellsFake[m].setAttribute('style','min-width:'+colspanWidth+'px;');
indexOfWidth = m+w-1;
}
} else {
if (cellsFake[m].innerHTML == '') {
cellsFake[m].innerHTML = ' ';
cellsFake[m].setAttribute('style','min-width:'+widths[i][indexOfWidth]+'px;');
}
if (cellsFake[m].getAttribute('style') != '') {
cellsFake[m].setAttribute('style','width:'+widths[i][indexOfWidth]+'px;');
}
}
indexOfWidth++;
}
};
delete clone;
delete cloneBody;
}
}
} else {
fixedHeaderTable.tbl.splice(i,1);
}
};
fixedHeaderTable.init();
}
mainDiv.style.display = disp;
})(idContainer,marge,window);
Enjoy !
Width of cells of header can be less large than columns. I don't know how to fix it. Help will be great. Thanks (fixed).
Last update 27/02/2015
Copyright © 2021 Ecyseo Compression GZIP activée