/* 
 | 
 * jQuery TableFix plugin ver 1.0.1 
 | 
 * Copyright (c) 2010 Otchy 
 | 
 * This source file is subject to the MIT license. 
 | 
 * http://www.otchy.net/javascript/tablefix/ 
 | 
 */ 
 | 
(function($){ 
 | 
    $.fn.tablefix = function(options) { 
 | 
        var sbwidth = scrollbarWidth(); 
 | 
        return this.each(function(index){ 
 | 
            // 処理継続の判定 
 | 
            var opts = $.extend({}, options); 
 | 
            var baseTable = $(this); 
 | 
            var withWidth = (opts.width > 0); 
 | 
            var withHeight = (opts.height > 0); 
 | 
            if (withWidth) { 
 | 
                withWidth = (opts.width < baseTable.width()); 
 | 
            } else { 
 | 
                opts.width = baseTable.width(); 
 | 
            } 
 | 
            if (withHeight) { 
 | 
                withHeight = (opts.height < baseTable.height()); 
 | 
            } else { 
 | 
                opts.height = baseTable.height(); 
 | 
            } 
 | 
            if (withWidth || withHeight) { 
 | 
                if (withWidth) { 
 | 
                    opts.height -= sbwidth; 
 | 
                } 
 | 
                if (withHeight) { 
 | 
                    opts.width -= sbwidth; 
 | 
                } 
 | 
            } else { 
 | 
                return; 
 | 
            } 
 | 
            // 外部 div の設定 
 | 
            baseTable.wrap("<div></div>"); 
 | 
            var div = baseTable.parent(); 
 | 
            div.css({position: "relative"}); 
 | 
            // スクロール部オフセットの取得、tdにwidthとheightを固定 
 | 
            var fixRows = (opts.fixRows > 0) ? opts.fixRows : 0; 
 | 
            var fixCols = (opts.fixCols > 0) ? opts.fixCols : 0; 
 | 
            var offsetX = 0; 
 | 
            var offsetY = 0; 
 | 
            baseTable.find('tr').each(function(indexY) { 
 | 
                var trThis = $(this); 
 | 
                if(jQuery.browser.msie) { 
 | 
                    trThis.height(trThis.height() + 1); 
 | 
                } else { 
 | 
                    trThis.height(trThis.height()); 
 | 
                } 
 | 
                trThis.find('td,th').each(function(indexX) { 
 | 
                    // 先頭の行 
 | 
                    if (indexY <= fixRows) { 
 | 
                        var cell = $(this); 
 | 
                        if (indexY == fixRows && indexX == fixCols) { 
 | 
                            offsetX = cell.position().left; 
 | 
                            offsetY = cell.parent('tr').position().top; 
 | 
                        } 
 | 
                        cell.width(cell.width()); 
 | 
                        cell.height(cell.height()); 
 | 
                    } 
 | 
                    // 先頭の列 
 | 
                    else if (indexX <= fixCols) { 
 | 
                        var cell = $(this); 
 | 
                        cell.width(cell.width()); 
 | 
                        cell.height(cell.height()); 
 | 
                    } 
 | 
                    else { 
 | 
                        return false; 
 | 
                    } 
 | 
                }); 
 | 
            }); 
 | 
            // テーブルの分割と初期化 
 | 
            var bodyTable = baseTable.wrap('<div name="bodyTable"></div>'); 
 | 
            var rowTable = baseTable.shallowClone().removeAttr('id').wrap('<div name="rowTable"></div>'); 
 | 
            var colTable = baseTable.shallowClone().removeAttr('id').wrap('<div name="colTable"></div>'); 
 | 
            var crossTable = baseTable.shallowClone().removeAttr('id').wrap('<div name="crossTable"></div>'); 
 | 
            baseTable.find('tr').each(function(indexY) { 
 | 
                var trThis = $(this); 
 | 
                var trRow, trCol, trCross; 
 | 
                if (indexY < fixRows) { 
 | 
                    trRow = trThis.shallowClone().removeAttr('id').appendTo(rowTable); 
 | 
                    trCross = trThis.shallowClone().removeAttr('id').appendTo(crossTable); 
 | 
                } 
 | 
                trThis.find('td,th').each(function(indexX) { 
 | 
                    var cell = $(this); 
 | 
                    // 先頭の行 
 | 
                    if (indexY < fixRows) { 
 | 
                        // 同時に先頭の列 
 | 
                        if (indexX < fixCols) { 
 | 
                            trCross.append(cell); 
 | 
                        } 
 | 
                        // 単なる先頭の行 
 | 
                        else { 
 | 
                            trRow.append(cell); 
 | 
                        } 
 | 
                    } 
 | 
                    // 先頭の列 
 | 
                    else if (indexX < fixCols) { 
 | 
                        if (!trCol) { 
 | 
                            trCol = trThis.shallowClone().removeAttr('id').appendTo(colTable); 
 | 
                        } 
 | 
                        trCol.append(cell); 
 | 
                    } 
 | 
                    else { 
 | 
                        return false; 
 | 
                    } 
 | 
                }); 
 | 
                if (indexY < fixRows) { 
 | 
                    trThis.remove(); 
 | 
                } 
 | 
            }); 
 | 
            var crossDiv = crossTable.parent().css({position: "absolute", overflow: "hidden"}); 
 | 
            var rowDiv = rowTable.parent().css({position: "absolute", overflow: "hidden"}); 
 | 
            var colDiv = colTable.parent().css({position: "absolute", overflow: "hidden"}); 
 | 
            var bodyDiv = bodyTable.parent().css({position: "absolute", overflow: "auto"}); 
 | 
            // クリップ領域の設定 
 | 
            var bodyWidth = opts.width - offsetX; 
 | 
            var bodyHeight = opts.height - offsetY; 
 | 
            crossDiv 
 | 
                .width(offsetX) 
 | 
                .height(offsetY); 
 | 
            crossTable.width(offsetX); 
 | 
            rowDiv 
 | 
                .width(bodyWidth) 
 | 
                .height(offsetY) 
 | 
                .css({left: offsetX + 'px'}); 
 | 
            colDiv 
 | 
                .width(offsetX) 
 | 
                .height(bodyHeight) 
 | 
                .css({top: offsetY + 'px'}); 
 | 
            colTable.width(offsetX); 
 | 
            bodyDiv 
 | 
                .width(bodyWidth + (withHeight ? sbwidth : 0)) 
 | 
                .height(bodyHeight + (withWidth ? sbwidth : 0)) 
 | 
                .css({left: offsetX + 'px', top: offsetY + 'px'}); 
 | 
            div.append(rowDiv).append(colDiv).append(crossDiv); 
 | 
            // スクロール連動 
 | 
            bodyDiv.scroll(function() { 
 | 
                rowDiv.scrollLeft(bodyDiv.scrollLeft()); 
 | 
                colDiv.scrollTop(bodyDiv.scrollTop()); 
 | 
            }); 
 | 
            rowDiv.scroll(function() { 
 | 
                bodyDiv.scrollLeft(rowDiv.scrollLeft()); 
 | 
            }); 
 | 
            colDiv.scroll(function() { 
 | 
                bodyDiv.scrollLeft(colDiv.scrollLeft()); 
 | 
            }); 
 | 
            // 外部 div の設定 
 | 
            div 
 | 
                .width(opts.width + (withHeight ? sbwidth : 0)) 
 | 
                .height(opts.height + (withWidth ? sbwidth : 0)); 
 | 
        }); 
 | 
    } 
 | 
})(jQuery); 
 | 
  
 | 
jQuery.fn.extend({ 
 | 
    shallowClone: function() { 
 | 
        return this.map(function () { 
 | 
            return jQuery.shallowClone(this); 
 | 
        }); 
 | 
    } 
 | 
}); 
 | 
jQuery.extend({ 
 | 
    shallowClone: function(elem) { 
 | 
        var clone; 
 | 
        clone = elem.cloneNode(false); 
 | 
        return clone; 
 | 
    } 
 | 
}); 
 | 
// http://chris-spittles.co.uk/jquery-calculate-scrollbar-width/ 
 | 
function scrollbarWidth() { 
 | 
    var $inner = jQuery('<div style="width: 100%; height:200px;">test</div>'), 
 | 
        $outer = jQuery('<div style="width:200px;height:150px; position: absolute; top: 0; left: 0; visibility: hidden; overflow:hidden;"></div>').append($inner), 
 | 
        inner = $inner[0], 
 | 
        outer = $outer[0]; 
 | 
      
 | 
    jQuery('body').append(outer); 
 | 
    var width1 = inner.offsetWidth; 
 | 
    $outer.css('overflow', 'scroll'); 
 | 
    var width2 = outer.clientWidth; 
 | 
    $outer.remove(); 
 | 
  
 | 
    return (width1 - width2); 
 | 
} 
 |