├── sample ├── bower.json └── index.html ├── bower.json ├── package.json ├── gulpfile.js ├── project.nuspec ├── README.md └── jquery.jTableScroll.js /sample/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jTableScroll-sample", 3 | "version": "1.6.0", 4 | "main": "index.html", 5 | "dependencies": { 6 | "jquery": "~2.1.0" 7 | } 8 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jtablescroll", 3 | "version": "1.6.0", 4 | "authors": [ 5 | "Mike Allison " 6 | ], 7 | "description": "An easy to implement jQuery extension that simplifies adding both horizontal and vertical scrolling with static header and footer to any html table. It will automatically (and reactively) size to it's parent container, or a given set of dimensions.", 8 | "main": "jQuery.jTableScroll.js", 9 | "keywords": [ 10 | "jquery", 11 | "table", 12 | "scroll", 13 | "scrolling", 14 | "static", 15 | "header", 16 | "footer", 17 | "scroller" 18 | ], 19 | "license": "MIT", 20 | "homepage": "https://github.com/mike-allison/jTableScroll", 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "bower_components", 25 | "test", 26 | "tests", 27 | "sample" 28 | ], 29 | "dependencies": { 30 | "jquery": ">=1.10.0" 31 | } 32 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jtablescroll", 3 | "version": "1.6.0", 4 | "description": "An easy to implement jQuery extension that simplifies adding both horizontal and vertical scrolling with static header and footer to any html table. It will automatically (and reactively) size to it's parent container, or a given set of dimensions.", 5 | "main": "jQuery.jTableScroll.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/mike-allison/jTableScroll" 12 | }, 13 | "keywords": [ 14 | "angular", 15 | "table", 16 | "scroll", 17 | "scrolling", 18 | "static", 19 | "header", 20 | "footer", 21 | "scroller" 22 | ], 23 | "author": "Mike Allison ", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/mike-allison/jTableScroll/issues" 27 | }, 28 | "homepage": "https://github.com/mike-allison/jTableScroll", 29 | "devDependencies": { 30 | "gulp": "^3.8.11", 31 | "gulp-clean": "^0.3.1", 32 | "gulp-nuget": "0.0.3", 33 | "run-sequence": "^1.0.2" 34 | } 35 | } -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | nuget = require('gulp-nuget'), 3 | clean = require('gulp-clean'), 4 | runSequence = require('run-sequence'), 5 | project = require('./package.json'), 6 | nugetApi = require('../nugetApi.json'), 7 | nugetPath = '../nuget.exe'; 8 | 9 | gulp.task('nuget-pack', function() { 10 | return gulp.src('./jQuery.jTableScroll.js') 11 | .pipe(nuget.pack({ 12 | nuspec: 'project.nuspec', 13 | nuget: nugetPath, 14 | version: project.version, 15 | workingDirectory: '.tmp/' 16 | })) 17 | .pipe(gulp.dest('nuget/')); 18 | }); 19 | 20 | gulp.task('nuget-push', function() { 21 | return gulp.src('nuget/jTableScroll.' + project.version + '.nupkg') 22 | .pipe(nuget.push({ 23 | feed: 'https://www.nuget.org/', 24 | nuget: nugetPath, 25 | apiKey: nugetApi.key 26 | })); 27 | }); 28 | 29 | gulp.task('clean', function() { 30 | return gulp.src(['./*.nupkg','.tmp/**']).pipe(clean()); 31 | }); 32 | 33 | gulp.task('clean-leftovers', function() { 34 | return gulp.src(['./*.nupkg']).pipe(clean()); 35 | }); 36 | 37 | gulp.task('nuget', function() { 38 | runSequence('clean','nuget-pack','clean-leftovers'); 39 | }); -------------------------------------------------------------------------------- /project.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jTableScroll 5 | 1.6.0 6 | Mike Allison 7 | mikeallison 8 | http://mikeallisononline.com 9 | false 10 | An easy to implement jQuery extension that simplifies adding both horizontal and vertical scrolling with static header and footer to any html table. It will automatically (and reactively) size to it's parent container, or a given set of dimensions. 11 | An easy to implement jQuery extension that simplifies adding both horizontal and vertical scrolling with static header and footer to any html table. 12 | Mike Allison 2013 13 | jquery table scroll scrolling static header footer scroller 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jTableScroll 2 | A powerful jQuery extension that automates scrolling and fixed headers and footers. 3 | 4 | By default it will size a table to it's parent container, fix the position of the header and footer, add horizontal and vertical scrolling as needed, and resize reactively to window resize events. 5 | 6 | ## Homepage & Demo 7 | http://mikeallisononline.com/Projects/jTableScroll 8 | 9 | ## Install 10 | ``` 11 | (bower): bower install jtablescroll 12 | (npm): npm install jTableScroll 13 | (nuget): Install-Package jtablescroll 14 | ``` 15 | 16 | ## License 17 | MIT 18 | 19 | ## Copyright 20 | 2013 Mike Allison 21 | 22 | ## Example Table 23 | ```html 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Column 1Column 2Column 3
Data 1Data 2Data 3
Foot 1Foot 2Foot 3
47 | ``` 48 | 49 | ## Javascript 50 | ```javascript 51 | 52 | 55 | ``` 56 | 57 | ## Options (JSON object) 58 | ```javascript 59 | { 60 | reactive: (bool)(optional)(default: true) enable reactive sizing to parent control 61 | width: (int)(optional) desired max width in pixels 62 | height: (int)(optional) desired height in pixels 63 | backgroundcolor: (string)(optional)(default: #fffff) table header bg color 64 | } 65 | ``` 66 | 67 | 68 | -------------------------------------------------------------------------------- /sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jTableScroll-sample 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 |
Col 1Col 2Col 3Col 4Col 5Col 6
asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
2asdfasdfasdfafsdasdfasdfasdfasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgvasdfasdfasdfasdgv
Footer Content
83 |
84 | 85 | 86 | 92 | 93 | -------------------------------------------------------------------------------- /jquery.jTableScroll.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jTableScroll 3 | * http://mikeallisononline.com/ 4 | * 5 | * Dependent on jquery 6 | * http://jquery.com/ 7 | * 8 | * Copyright 2013 Mike Allison 9 | * Released under the MIT license 10 | * http://opensource.org/licenses/MIT 11 | */ 12 | 13 | (function ($) { 14 | $.fn.jTableScroll = function (o) { 15 | o = $.extend({ 16 | width: null, 17 | height: null, 18 | backgroundcolor: null, 19 | headerCss: null, 20 | reactive: true 21 | }, o || {}); 22 | 23 | //get scrollbar size 24 | var dummy = $('
').css({ visibility: 'hidden', width: '50px', height:'50px', overflow: 'scroll' }).appendTo('body'); 25 | var scrollbarpx = 50 - $('
').height(99).appendTo(dummy).outerWidth(); 26 | dummy.remove(); 27 | 28 | //IE8 browser test (because it's bad) 29 | var rv = -1; 30 | var ua = navigator.userAgent; 31 | var re = new RegExp("Trident\/([0-9]{1,}[\.0-9]{0,})"); 32 | if (re.exec(ua) != null) { 33 | rv = parseFloat(RegExp.$1); 34 | } 35 | var ie8 = (rv == 4); 36 | 37 | this.each(function () { 38 | var self = $(this); 39 | var parent = self.parent(); 40 | var prevParentWidth = parent.width(); 41 | var divWidth = parseInt(o.width ? o.width : parent.width()); 42 | var divHeight = parseInt(o.height ? o.height : parent.height()); 43 | 44 | 45 | //bypass if table size smaller than given dimesions 46 | if (self.width() <= divWidth && self.height() <= divHeight) 47 | return; 48 | 49 | var width = self.width(); 50 | self.width(width); //reinforce table width so it doesn't change dynamically 51 | 52 | //Create outer div 53 | var outerdiv = $(document.createElement('div')); 54 | outerdiv.css({ 'overflow': 'hidden' }).width(divWidth).height(divHeight); 55 | 56 | //Create header div 57 | var headerdiv = $(document.createElement('div')); 58 | headerdiv.css({ 'overflow': 'hidden', 'position': 'relative' }).width(divWidth); 59 | if (o.headerCss) 60 | headerdiv.addClass(o.headerCss); 61 | 62 | //Create header clone 63 | var cloneTable = self.clone(); 64 | cloneTable.find('tbody').remove(); 65 | cloneTable.find('tfoot').remove(); 66 | 67 | //Create footer clone 68 | var cloneFoot = self.clone(); 69 | cloneFoot.find('tbody').remove(); 70 | cloneFoot.find('thead').remove(); 71 | 72 | var headBgColor = null; 73 | //Set header/footer column widths and click events 74 | self.find('thead').find('th').each(function(index, value) { 75 | var val = $(value); 76 | var tdwidth = val.width(); 77 | if (headBgColor == null) { 78 | if (o.backgroundcolor == null) 79 | headBgColor = val.bkgcolor(); 80 | else 81 | headBgColor = o.backgroundcolor; 82 | } 83 | if (headBgColor == "rgba(0, 0, 0, 0)" || headBgColor == "transparent") 84 | headBgColor = "#fff"; 85 | 86 | val.css("width", tdwidth + 'px'); //reinforce width 87 | $(cloneTable.find('th')[index]).click(function() { val.click(); }); 88 | $(cloneTable.find('th')[index]).width(tdwidth); 89 | $(cloneFoot.find('th')[index]).click(function () { val.click(); }); 90 | $(cloneFoot.find('td')[index]).width(tdwidth); 91 | }); 92 | 93 | //Create footer div 94 | var footerdiv = $(document.createElement('div')); 95 | footerdiv.css({ 'overflow': 'hidden', 'position': 'relative', 'background-color': headBgColor }).width(divWidth); 96 | 97 | cloneTable.css({ 'table-layout': 'fixed', 'background-color': headBgColor }); 98 | cloneFoot.css({ 'table-layout': 'fixed', 'background-color': headBgColor }); 99 | self.css({ 'table-layout': 'fixed' }); 100 | 101 | //Create body div 102 | var bodydiv = $(document.createElement('div')); 103 | 104 | //Add horizontal scroll event 105 | bodydiv.scroll(function () { 106 | headerdiv.scrollLeft(bodydiv.scrollLeft()); 107 | footerdiv.scrollLeft(bodydiv.scrollLeft()); 108 | }); 109 | 110 | //Add to DOM 111 | headerdiv.append(cloneTable); 112 | footerdiv.append(cloneFoot); 113 | self.before(outerdiv); 114 | self.appendTo(bodydiv); 115 | outerdiv.append(headerdiv); 116 | outerdiv.append(bodydiv); 117 | outerdiv.append(footerdiv); 118 | 119 | //Adjust header and footer div width if vertical scrollbar present 120 | var combinedHeight = self.height() + headerdiv.height() + footerdiv.height(); 121 | if (combinedHeight >= divHeight) { 122 | headerdiv.width(headerdiv.width() - scrollbarpx); 123 | footerdiv.width(footerdiv.width() - scrollbarpx); 124 | } 125 | 126 | //Set body height after other content added to parent 127 | var marginTop = parseFloat(bodydiv.css("margin-top")); 128 | marginTop -= headerdiv.height(); 129 | var marginBottom = parseFloat(bodydiv.css("margin-bottom")); 130 | marginBottom -= footerdiv.height(); 131 | if (self.width() + scrollbarpx >= divWidth) 132 | marginBottom -= scrollbarpx; 133 | bodydiv.css({ 'overflow': 'auto', 'margin-top': marginTop + 'px', 'margin-bottom': marginBottom + 'px' }).width(divWidth).height(divHeight - scrollbarpx); 134 | 135 | if (ie8) 136 | self.find('thead').hide(); 137 | 138 | //Add reactive resizing 139 | if (o.reactive) { 140 | $(window).resize(function () { 141 | if (prevParentWidth != parent.width()) { 142 | var newWidth = parent.width(); 143 | if (o.width && newWidth > o.width) 144 | return; 145 | outerdiv.css({ 'overflow': 'hidden' }).width(newWidth).height(divHeight); 146 | headerdiv.css({ 'overflow': 'hidden', 'position': 'relative' }).width(newWidth - scrollbarpx); 147 | bodydiv.css({ 'overflow': 'auto', 'margin-top': marginTop + 'px', 'margin-bottom': marginBottom + 'px' }).width(newWidth).height(divHeight - scrollbarpx); 148 | footerdiv.css({ 'overflow': 'hidden', 'position': 'relative', 'background-color': headBgColor }).width(newWidth - scrollbarpx); 149 | prevParentWidth = newWidth; 150 | } 151 | }); 152 | } 153 | 154 | }); 155 | }; 156 | })(jQuery); 157 | 158 | 159 | (function($) { 160 | // Get this browser's take on no fill 161 | // Must be appended else Chrome etc return 'initial' 162 | var $temp = $('
').appendTo('body'); 163 | var transparent = $temp.css('backgroundColor'); 164 | $temp.remove(); 165 | 166 | jQuery.fn.bkgcolor = function( fallback ) { 167 | function test( $elem ) { 168 | if ( $elem.css('backgroundColor') == transparent ) { 169 | return !$elem.is('body') ? test( $elem.parent() ) : fallback || transparent ; 170 | } else { 171 | return $elem.css('backgroundColor'); 172 | } 173 | } 174 | return test( $(this) ); 175 | }; 176 | 177 | })(jQuery); --------------------------------------------------------------------------------