( function($) { $.fn.tableHeadFixer = function(param) { return this.each(function() { table.call(this); }); function table() { { var defaults = { head: true, foot: false, left: 0, right: 0, 'z-index': 0, }; var settings = $.extend({}, defaults, param); settings.table = this; settings.parent = $(settings.table).parent(); setParent(); if (settings.head == true) { fixHead(); } if (settings.foot == true) { fixFoot(); } if (settings.left > 0) { fixLeft(); } if (settings.right > 0) { fixRight(); } setCorner(); $(settings.parent).trigger('scroll'); $(window).resize(function() { $(settings.parent).trigger('scroll'); }); /* This function solver z-index problem in corner cell where fix row and column at the same time, set corner cells z-index 1 more then other fixed cells */ function setCorner() { var table = $(settings.table); if (settings.head) { if (settings.left > 0) { var tr = table.find('thead tr'); tr.each(function(k, row) { solverLeftColspan(row, function(cell) { $(cell).css('z-index', settings['z-index'] + 1); }); }); } if (settings.right > 0) { var tr = table.find('thead tr'); tr.each(function(k, row) { solveRightColspan(row, function(cell) { $(cell).css('z-index', settings['z-index'] + 1); }); }); } } if (settings.foot) { if (settings.left > 0) { var tr = table.find('tfoot tr'); tr.each(function(k, row) { solverLeftColspan(row, function(cell) { $(cell).css('z-index', settings['z-index']); }); }); } if (settings.right > 0) { var tr = table.find('tfoot tr'); tr.each(function(k, row) { solveRightColspan(row, function(cell) { $(cell).css('z-index', settings['z-index']); }); }); } } } // Set style of table parent function setParent() { var parent = $(settings.parent); var table = $(settings.table); parent.append(table); parent.css({ 'overflow-x': 'auto', 'overflow-y': 'auto', }); parent.scroll(function() { var scrollWidth = parent[0].scrollWidth; var clientWidth = parent[0].clientWidth; var scrollHeight = parent[0].scrollHeight; var clientHeight = parent[0].clientHeight; var top = parent.scrollTop(); var left = parent.scrollLeft(); if (settings.head) { this.find('thead tr > *').css('top', top); } if (settings.foot) { this.find('tfoot tr > *'). css('bottom', scrollHeight - clientHeight - top); } if (settings.left > 0) { settings.leftColumns.css('left', left); } if (settings.right > 0) { settings.rightColumns.css('right', scrollWidth - clientWidth - left); } }.bind(table)); } // Set table head fixed function fixHead() { var thead = $(settings.table).find('thead'); var tr = thead.find('tr'); var cells = thead.find('tr > *'); setBackground(cells); cells.css({ 'position': 'relative', }); } // Set table foot fixed function fixFoot() { var tfoot = $(settings.table).find('tfoot'); var tr = tfoot.find('tr'); var cells = tfoot.find('tr > *'); setBackground(cells); cells.css({ 'position': 'relative', }); } // Set table left column fixed function fixLeft() { var table = $(settings.table); // var fixColumn = settings.left; settings.leftColumns = $(); var tr = table.find('tr'); tr.each(function(k, row) { solverLeftColspan(row, function(cell) { settings.leftColumns = settings.leftColumns.add(cell); }); // var inc = 1; // for(var i = 1; i <= fixColumn; i = i + inc) { // var nth = inc > 1 ? i - 1 : i; // var cell = $(row).find("*:nth-child(" + nth + ")"); // var colspan = cell.prop("colspan"); // settings.leftColumns = settings.leftColumns.add(cell); // inc = colspan; // } }); var column = settings.leftColumns; column.each(function(k, cell) { var cell = $(cell); setBackground(cell); cell.css({ 'position': 'relative', }); }); } // Set table right column fixed function fixRight() { var table = $(settings.table); var fixColumn = settings.right; settings.rightColumns = $(); var tr = table.find('tr'); tr.each(function(k, row) { solveRightColspan(row, function(cell) { settings.rightColumns = settings.rightColumns.add(cell); }); }); var column = settings.rightColumns; column.each(function(k, cell) { var cell = $(cell); setBackground(cell); cell.css({ 'position': 'relative', }); }); } // Set fixed cells backgrounds function setBackground(elements) { return false; elements.each(function(k, element) { var element = $(element); var parent = $(element).parent(); var elementBackground = element.css('background-color'); elementBackground = ( elementBackground == 'transparent' || elementBackground == 'rgba(0, 0, 0, 0)' ) ? null : elementBackground; var parentBackground = parent.css('background-color'); parentBackground = ( parentBackground == 'transparent' || parentBackground == 'rgba(0, 0, 0, 0)' ) ? null : parentBackground; var background = parentBackground ? parentBackground : 'white'; background = elementBackground ? elementBackground : background; element.css('background-color', background); }); } function solverLeftColspan(row, action) { var fixColumn = settings.left; var inc = 1; for (var i = 1; i <= fixColumn; i = i + inc) { var nth = inc > 1 ? i - 1 : i; var cell = $(row).find('> *:nth-child(' + nth + ')'); var colspan = cell.prop('colspan'); if (cell.cellPos().left < fixColumn) { action(cell); } inc = colspan; } } function solveRightColspan(row, action) { var fixColumn = settings.right; var inc = 1; for (var i = 1; i <= fixColumn; i = i + inc) { var nth = inc > 1 ? i - 1 : i; var cell = $(row).find('> *:nth-last-child(' + nth + ')'); var colspan = cell.prop('colspan'); action(cell); inc = colspan; } } } } }; } )(jQuery); /* cellPos jQuery plugin --------------------- Get visual position of cell in HTML table (or its block like thead). Return value is object with "top" and "left" properties set to row and column index of top-left cell corner. Example of use: $("#myTable tbody td").each(function(){ $(this).text( $(this).cellPos().top +", "+ $(this).cellPos().left ); }); */ ( function($) { /* scan individual table and set "cellPos" data in the form { left: x-coord, top: y-coord } */ function scanTable($table) { var m = []; $table.children('tr').each(function(y, row) { $(row).children('td, th').each(function(x, cell) { var $cell = $(cell), cspan = $cell.attr('colspan') | 0, rspan = $cell.attr('rowspan') | 0, tx, ty; cspan = cspan ? cspan : 1; rspan = rspan ? rspan : 1; for (; m[y] && m[y][x]; ++x) { } //skip already occupied cells in current row for (tx = x; tx < x + cspan; ++tx) { //mark matrix elements occupied by current cell with true for (ty = y; ty < y + rspan; ++ty) { if (!m[ty]) { //fill missing rows m[ty] = []; } m[ty][tx] = true; } } var pos = {top: y, left: x}; $cell.data('cellPos', pos); }); }); } /* plugin */ $.fn.cellPos = function(rescan) { var $cell = this.first(), pos = $cell.data('cellPos'); if (!pos || rescan) { var $table = $cell.closest('table, thead, tbody, tfoot'); scanTable($table); } pos = $cell.data('cellPos'); return pos; }; } )(jQuery);