(function (window, doc) { var dummyStyle = doc.createElement('div').style, vendor = (function () { var vendors = 't,webkitT,MozT,msT,OT'.split(','), t, i = 0, l = vendors.length; for ( ; i < l; i++ ) { t = vendors[i] + 'ransform'; if ( t in dummyStyle ) { return vendors[i].substr(0, vendors[i].length - 1); } } return false; })(), cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '', // style properties transform = prefixStyle('transform'), transitionProperty = prefixStyle('transitionProperty'), transitionDuration = prefixStyle('transitionDuration'), transformOrigin = prefixStyle('transformOrigin'), transitionTimingFunction = prefixStyle('transitionTimingFunction'), transitionDelay = prefixStyle('transitionDelay'), // 3d has3d = prefixStyle('perspective') in dummyStyle, //translateZ = has3d ? ' translateZ(0)' : '', translateZ = ''; nextFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { return setTimeout(callback, 1); }; })(), // events RESIZE_EV = 'onorientationchange', START_EV = 'touchstart', MOVE_EV = 'touchmove', END_EV = 'touchend', CANCEL_EV = 'touchcancel', TRNEND_EV = (function () { if ( vendor === false ) return false; var transitionEnd = { '' : 'transitionend', 'webkit' : 'webkitTransitionEnd', 'Moz' : 'transitionend', 'O' : 'otransitionend', 'ms' : 'MSTransitionEnd' }; return transitionEnd[vendor]; })(); function prefixStyle (style) { if ( vendor === '' ) return style; style = style.charAt(0).toUpperCase() + style.substr(1); return vendor + style; } Scroll = function(el, options) { var that = this, i; that.wrapper = typeof el == 'object' ? el : doc.getElementById(el); that.wrapper.style.overflow = 'hidden'; that.scroller = that.wrapper.children[0]; // default options that.options = { hScroll: true, vScroll: true, x: 0, y: 0, topOffset: 0, bounce: false, bounceLock: false, lockDirection: true, momentum: false, // scrollbar hScrollbar: true, vScrollbar: true, fixedScrollbar: true, hideScrollbar: false, fadeScrollbar: false, // Events onRefresh: null, onBeforeScrollStart: function (e) {e.preventDefault();}, onScrollStart: null, onBeforeScrollMove: null, onScrollMove: null, onBeforeScrollEnd: null, onScrollEnd: null, onTouchEnd: null, onDestroy: null } // user defined options for (i in options) that.options[i] = options[i]; // set starting position that.x = that.options.x; that.y = that.options.y; // set some default styles that.scroller.style[transitionProperty] = cssVendor + 'transform'; that.scroller.style[transitionDuration] = '0'; that.scroller.style[transformOrigin] = '0 0'; that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)'; that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ; that.refresh(); that._bind('onorientationchange', window); that._bind('touchstart'); }; Scroll.prototype = { enabled: true, x: 0, y: 0, steps: [], scale: 1, currPageX: 0, currPageY: 0, pagesX: [], pagesY: [], aniTime: null, // handle event handleEvent: function (e) { var that = this; switch(e.type) { case 'touchstart': that._start(e);break; case 'touchmove': that._move(e);break; case 'touchend': case 'touchcancel': that._end(e);break; case 'onorientationchange': that._resize();break; case TRNEND_EV: that._transitionEnd(e); break; } }, // private methods _setup: function () { }, _bind: function (type, el, bubble) { (el || this.scroller).addEventListener(type, this, !!bubble); }, _unbind: function (type, el, bubble) { (el || this.scroller).removeEventListener(type, this, !!bubble); }, _start: function (e) { var that = this, point = e.touches[0], matrix, x, y, c1, c2; if (!that.enabled) return; if (that.options.onBforeScrollStart) that.options.onBeforeScrollStart.call(that, e); that._transitionTime(0); that.moved = false; that.animating = false; that.distX = 0; that.distY = 0; that.absDistX = 0; that.absDistY = 0; that.dirX = 0; that.dirY = 0; if (that.options.momentum) { matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(','); x = +(matrix[12] || matrix[4]); y = +(matrix[13] || matrix[5]); if (x != that.x || y != that.y) { that._unbind(TRNEND_EV); that.steps = []; that._pos(x, y); if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); } } that.absStartX = that.x; that.absStartY = that.y; that.startX = that.x; that.startY = that.y; that.pointX = point.pageX; that.pointY = point.pageY; that.startTime = e.timeStamp || Date.now(); if (that.options.onScrollStart) that.options.onScrollStart.call(that, e); that._bind('touchmove', window); that._bind('touchend', window); that._bind('touchcancel', window); }, _move: function (e) { var that = this, point = e.touches[0], deltaX = point.pageX - that.pointX, deltaY = point.pageY - that.pointY, newX = that.x + deltaX, newY = that.y + deltaY, c1, c2, scale, timestamp = e.timeStamp || Date.now(); if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e); that.pointX = point.pageX; that.pointY = point.pageY; if (newX > 0 || newX < that.maxScrollX) { newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX; } if (newY > that.minScrollY || newY < that.maxScrollY) { newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY; } that.distX += deltaX; that.distY += deltaY; that.absDistX = Math.abs(that.distX); that.absDistY = Math.abs(that.distY); if (that.absDistX < 6 && that.absDistY < 6) { return; } // Lock direction if (that.options.lockDirection) { if (that.absDistX > that.absDistY + 5) { newY = that.y; deltaY = 0; } else if (that.absDistY > that.absDistX + 5) { newX = that.x; deltaX = 0; } } that.moved = true; that._pos(newX, newY); that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; if (timestamp - that.startTime > 300) { that.startTime = timestamp; that.startX = that.x; that.startY = that.y; } if (that.options.onScrollMove) that.options.onScrollMove.call(that, e); }, _end: function (e) { if (e.touches.length !== 0) return; var that = this, point = e.changedTouches[0], target, ev, momentumX = { dist:0, time:0 }, momentumY = { dist:0, time:0 }, duration = (e.timeStamp || Date.now()) - that.startTime, newPosX = that.x, newPosY = that.y, distX, distY, newDuration; that._unbind('touchmove', window); that._unbind('touchend', window); that._unbind('touchcancel', window); if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e); if (!that.moved) { that._resetPos(400); if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); return; } if (duration < 300 && that.options.momentum) { momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX; momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY; newPosX = that.x + momentumX.dist; newPosY = that.y + momentumY.dist; if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 }; if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 }; } if (momentumX.dist || momentumY.dist) { newDuration = Math.max(Math.max(momentumX.time, momentumY.time), 10); that.scrollTo(Math.round(newPosX), Math.round(newPosY), newDuration); if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); return; } that._resetPos(200); if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e); }, _resize: function () { var that = this; setTimeout(function () { that.refresh(); }, 200); }, _resetPos: function (time) { var that = this, resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x, resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y; if (resetX == that.x && resetY == that.y) { if (that.moved) { that.moved = false; if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end } if (that.hScrollbar) { if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms'; that.hScrollbarWrapper.style.opacity = '0'; } if (that.vScrollbar) { if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms'; that.vScrollbarWrapper.style.opacity = '0'; } return; } that.scrollTo(resetX, resetY, time || 0); }, _pos: function (x, y) { x = this.hScroll ? x : 0; y = this.vScroll ? y : 0; this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ; this.x = x; this.y = y; this._scrollbarPos('h'); this._scrollbarPos('v'); }, _transitionEnd: function (e) { var that = this; if (e.target != that.scroller) return; that._unbind(TRNEND_EV); that._startAni(); }, _startAni: function () { var that = this, startX = that.x, startY = that.y, startTime = Date.now(), step, easeOut, animate; if (that.animating) return; if (!that.steps.length) { that._resetPos(400); return; } step = that.steps.shift(); if (step.x == startX && step.y == startY) step.time = 0; that.animating = true; that.moved = true; if (that.options.useTransition) { that._transitionTime(step.time); that._pos(step.x, step.y); that.animating = false; if (step.time) that._bind(TRNEND_EV); else that._resetPos(0); return; } animate = function () { var now = Date.now(), newX, newY; if (now >= startTime + step.time) { that._pos(step.x, step.y); that.animating = false; if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end that._startAni(); return; } now = (now - startTime) / step.time - 1; easeOut = Math.sqrt(1 - now * now); newX = (step.x - startX) * easeOut + startX; newY = (step.y - startY) * easeOut + startY; that._pos(newX, newY); if (that.animating) that.aniTime = nextFrame(animate); }; animate(); }, _transitionTime: function (time) { time += 'ms'; this.scroller.style[transitionDuration] = time; if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time; if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time; }, _offset: function(el) { var left = -el.offsetLeft, top = -el.offsetTop; while (el = el.offsetParent) { left -= el.offsetLeft; top -= el.offsetTop; } if (el != this.wrapper) { left *= this.scale; top *= this.scale; } return { left: left, top: top }; }, _scrollbar: function(dir) { var that = this, bar; if (!that[dir + 'Scrollbar']) { if (that[dir + 'ScrollbarWrapper']) { if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = ''; that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']); that[dir + 'ScrollbarWrapper'] = null; that[dir + 'ScrollbarIndicator'] = null; } return; } if (!that[dir + 'ScrollbarWrapper']) { bar = doc.createElement('div'); bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px'); bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1'); that.wrapper.appendChild(bar); that[dir + 'ScrollbarWrapper'] = bar; bar = doc.createElement('div'); bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px'; bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ; bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)'; that[dir + 'ScrollbarWrapper'].appendChild(bar); that[dir + 'ScrollbarIndicator'] = bar; } if (dir == 'h') { that.hScrollbarSize = that.hScrollbarWrapper.clientWidth; that.hScrollbarIndicatorSize = Math.max(Math.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8); that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px'; that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize; that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX; } else { that.vScrollbarSize = that.vScrollbarWrapper.clientHeight; that.vScrollbarIndicatorSize = Math.max(Math.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8); that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px'; that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize; that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY; } that._scrollbarPos(dir, true); }, _scrollbarPos: function(dir, hidden) { var that = this, pos = dir == 'h' ? that.x : that.y, size; if (!that[dir + 'Scrollbar']) { return; } pos = that[dir + 'ScrollbarProp'] * pos; if (pos < 0) { if (!that.options.fixedScrollbar) { size = that[dir + 'ScrollbarIndicatorSize'] + Math.round(pos * 3); if (size < 8) size = 8; that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; } pos = 0; } else if (pos > that[dir + 'ScrollbarMaxScroll']) { if (!that.options.fixedScrollbar) { size = that[dir + 'ScrollbarIndicatorSize'] - Math.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3); if (size < 8) size = 8; that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px'; pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size); } else { pos = that[dir + 'ScrollbarMaxScroll']; } } that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0'; that[dir + 'ScrollbarWrapper'].style.opacity = hidden ? '0' : '1'; that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ; }, _momentum: function (dist, time, maxDistUpper, maxDistLower, size) { var deceleration = 0.0006, speed = Math.abs(dist) / time, newDist = (speed * speed) / (2 * deceleration), newTime = 0, outsideDist = 0; // Proportinally reduce speed if we are outside of the boundaries if (dist > 0 && newDist > maxDistUpper) { outsideDist = size / (6 / (newDist / speed * deceleration)); maxDistUpper = maxDistUpper + outsideDist; speed = speed * maxDistUpper / newDist; newDist = maxDistUpper; } else if (dist < 0 && newDist > maxDistLower) { outsideDist = size / (6 / (newDist / speed * deceleration)); maxDistLower = maxDistLower + outsideDist; speed = speed * maxDistLower / newDist; newDist = maxDistLower; } newDist = newDist * (dist < 0 ? -1 : 1); newTime = speed / deceleration; return { dist: newDist, time: Math.round(newTime) }; }, // public methods destroy: function () { var that = this; that.scroller.style[transform] = ''; // Remove the scrollbars that.hScrollbar = false; that.vScrollbar = false; that._scrollbar('h'); that._scrollbar('v'); // Remove the event listeners that._unbind('onorientationchange', window); that._unbind('touchstart'); that._unbind('touchmove', window); that._unbind('touchend', window); that._unbind('touchcancel', window); if (that.options.useTransition) that._unbind(TRNEND_EV); if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime); if (that.options.onDestroy) that.options.onDestroy.call(that); }, refresh: function () { var that = this, offset, i, l, els, pos = 0, page = 0; that.wrapperW = that.wrapper.clientWidth || 1; that.wrapperH = that.wrapper.clientHeight || 1; that.minScrollY = -that.options.topOffset || 0; that.scrollerW = Math.round(that.scroller.offsetWidth ); that.scrollerH = Math.round(that.scroller.offsetHeight + that.minScrollY); that.maxScrollX = that.wrapperW - that.scrollerW; that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY; that.dirX = 0; that.dirY = 0; if (that.options.onRefresh) that.options.onRefresh.call(that); that.hScroll = that.options.hScroll && that.maxScrollX < 0; that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH); that.hScrollbar = that.hScroll && that.options.hScrollbar; that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH; offset = that._offset(that.wrapper); that.wrapperOffsetLeft = -offset.left; that.wrapperOffsetTop = -offset.top; that._scrollbar('h'); that._scrollbar('v'); that.scroller.style[transitionDuration] = '0'; that._resetPos(400); }, scrollTo: function (x, y, time, relative) { var that = this, step = x, i, l; that.stop(); if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }]; for (i=0, l=step.length; i 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left; pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top; time = time === undefined ? Math.max(Math.abs(pos.left)*2, Math.abs(pos.top)*2) : time; that.scrollTo(pos.left, pos.top, time); }, scrollToPage: function (pageX, pageY, time) { var that = this, x, y; time = time === undefined ? 400 : time; if (that.options.onScrollStart) that.options.onScrollStart.call(that); x = -that.wrapperW * pageX; y = -that.wrapperH * pageY; if (x < that.maxScrollX) x = that.maxScrollX; if (y < that.maxScrollY) y = that.maxScrollY; that.scrollTo(x, y, time); }, disable: function () { this.stop(); this._resetPos(0); this.enabled = false; // If disabled after touchstart we make sure that there are no left over events this._unbind('touchmove', window); this._unbind('touchend', window); this._unbind('touchcancel', window); }, enable: function () { this.enabled = true; }, stop: function () { this._unbind(TRNEND_EV); this.steps = []; this.moved = false; this.animating = false; }, isReady: function () { return !this.moved && !this.animating; } }; dummyStyle = null; window.Scroll = Scroll; })(window, document); (function ($) { $.fn.scrollFixedTable = function () { var defaults = { width: '100%', height: '100%', borderCollapse: true, themeClass: 'fht-default', fixedColumn: true, // fixed first column autoShow: true, // hide table after its created loader: false, footer: false, // show footer cloneHeadToFoot: false, // clone head and use as footer autoResize: false, // resize table if its parent wrapper changes size create: null // callback after plugin completes }; var settings = {}; var methods = { init : function(options) { settings = $.extend({}, defaults, options); // iterate through all the DOM elements we are attaching the plugin to return this.each(function() { var $self = $(this), // reference the jQuery version of the current DOM element self = this; // reference to the actual DOM element if ( helpers._isTable($self) ) { methods.setup.apply(this, Array.prototype.slice.call(arguments, 1)); $.isFunction(settings.create) && settings.create.call(this); } else { $.error('Invalid table mark-up'); } }); }, setup: function() { var $self = $(this), self = this, $thead = $self.find('thead'), $tfoot = $self.find('tfoot'), $tbody = $self.find('tbody'), $wrapper, $divHead, $divFoot, $divBody, $fixedHeadRow, $temp, tfootHeight = 0; settings.includePadding = helpers._isPaddingIncludedWithWidth(); settings.scrollbarOffset = helpers._getScrollbarWidth(); settings.themeClassName = settings.themeClass; if ( settings.width.search('%') > -1 ) { var widthMinusScrollbar = $self.parent().width() - settings.scrollbarOffset; } else { var widthMinusScrollbar = settings.width - settings.scrollbarOffset; } $self.css({ width: widthMinusScrollbar }); if ( !$self.closest('.fht-table-wrapper').length ) { $self.addClass('fht-table'); $self.wrap('
'); } $wrapper = $self.closest('.fht-table-wrapper'); if ( settings.fixedColumn == true && $wrapper.find('.fht-fixed-column').length == 0 ) { $self.wrap('
'); var $fixedColumn = $('
').prependTo($wrapper), $fixedBody = $wrapper.find('.fht-fixed-body'); } $wrapper.css({ width: settings.width, height: settings.height }) .addClass(settings.themeClassName); if ( !$self.hasClass('fht-table-init') ) { $self.wrap('
'); } $divBody = $self.closest('.fht-tbody'); var tableProps = helpers._getTableProps($self); helpers._setupClone( $divBody, tableProps.tbody ); if ( !$self.hasClass('fht-table-init') ) { if ( settings.fixedColumn == true ) { $divHead = $('
').prependTo($fixedBody); } else { $divHead = $('
').prependTo($wrapper); } $thead.clone().appendTo($divHead.find('table')); } else { $divHead = $wrapper.find('div.fht-thead'); } helpers._setupClone( $divHead, tableProps.thead ); $self.css({ 'margin-top': -$divHead.outerHeight(true) }); /* * Check for footer * Setup footer if present */ if ( settings.footer == true ) { helpers._setupTableFooter( $self, self, tableProps ); if ( !$tfoot.length ) { $tfoot = $wrapper.find('div.fht-tfoot table'); } tfootHeight = $tfoot.outerHeight(true); } var tbodyHeight = $wrapper.height() - $thead.outerHeight(true) - tfootHeight - tableProps.border; $divBody.css({ 'height': tbodyHeight }); $self.addClass('fht-table-init'); if ( typeof(settings.altClass) !== 'undefined' ) { $self.find('tbody tr:odd') .addClass(settings.altClass); } if ( settings.fixedColumn == true ) { helpers._setupFixedColumn( $self, self, tableProps ); } if ( !settings.autoShow ) { $wrapper.hide(); } helpers._bindScroll( $divBody, tableProps ); return self; } }; var helpers = { /* * return boolean * True if a thead and tbody exist. */ _isTable: function( $obj ) { var $self = $obj, hasTable = $self.is('table'), hasThead = $self.find('thead').length > 0, hasTbody = $self.find('tbody').length > 0; if ( hasTable && hasThead && hasTbody ) { return true; } return false; }, /* * return void * bind scroll event */ _bindScroll: function( $obj, tableProps ) { var $self = $obj, $wrapper = $self.closest('.fht-table-wrapper'), $thead = $self.siblings('.fht-thead'), $tfoot = $self.siblings('.fht-tfoot'), that = this; scroll = new Scroll($obj.get(0), { onScrollMove: function (e) { var $fixedColumn = $wrapper.find('.fht-fixed-column'); $fixedColumn.find('.fht-tbody table').css('-webkit-transform', 'translate(0,' + this.y + 'px)'); $thead.find('table').css('-webkit-transform', 'translate(' + this.x + 'px,0)') }, onTouchEnd: function(e) { var $fixedColumn = $wrapper.find('.fht-fixed-column'); $fixedColumn.find('.fht-tbody table').css('-webkit-transform', 'translate(0,' + this.y + 'px)'); $thead.find('table').css('-webkit-transform', 'translate(' + this.x + 'px,0)') }}); // $self.bind('scroll', function() { // if ( settings.fixedColumn == true ) { // var $fixedColumn = $wrapper.find('.fht-fixed-column'); // $fixedColumn.find('.fht-tbody table') // .css({ // 'margin-top': -$self.scrollTop() // }); // } // $thead.find('table') // .css({ // 'margin-left': -this.scrollLeft // }); // if ( settings.cloneHeadToFoot ) { // $tfoot.find('table') // .css({ // 'margin-left': -this.scrollLeft // }); // } // }); }, /* * return void */ _fixHeightWithCss: function ( $obj, tableProps ) { if ( settings.includePadding ) { $obj.css({ 'height': $obj.height() + tableProps.border }); } else { $obj.css({ 'height': $obj.parent().height() + tableProps.border }); } }, /* * return void */ _fixWidthWithCss: function( $obj, tableProps ) { if ( settings.includePadding ) { $obj.css({ 'width': $obj.width() + tableProps.border }); } else { $obj.css({ 'width': $obj.parent().width() + tableProps.border }); } }, /* * return void */ _setupFixedColumn: function ( $obj, obj, tableProps ) { var $self = $obj, self = obj, $wrapper = $self.closest('.fht-table-wrapper'), $fixedBody = $wrapper.find('.fht-fixed-body'), $fixedColumn = $wrapper.find('.fht-fixed-column'), $thead = $('
'), $tbody = $('
'), $tfoot = $('
'), $firstThChild = $fixedBody.find('.fht-thead thead tr th:first-child'), $firstTdChildren, fixedColumnWidth = $firstThChild.outerWidth(true) + tableProps.border, fixedBodyWidth = $wrapper.width(), fixedBodyHeight = $fixedBody.find('.fht-tbody').height() - settings.scrollbarOffset, $newRow; // Fix cell heights helpers._fixHeightWithCss( $firstThChild, tableProps ); helpers._fixWidthWithCss( $firstThChild, tableProps ); $firstTdChildren = $fixedBody.find('tbody tr td:first-child') .each( function(index) { helpers._fixHeightWithCss( $(this), tableProps ); helpers._fixWidthWithCss( $(this), tableProps ); }); // clone header $thead.appendTo($fixedColumn) .find('tr') .append($firstThChild.clone()); $tbody.appendTo($fixedColumn) .css({ 'margin-top': -1, 'height': fixedBodyHeight + tableProps.border }); $firstTdChildren.each(function(index) { $newRow = $('').appendTo($tbody.find('tbody')); if ( settings.altClass && $(this).parent().hasClass(settings.altClass) ) { $newRow.addClass(settings.altClass); } $(this).clone() .appendTo($newRow); }); // set width of fixed column wrapper $fixedColumn.css({ 'width': fixedColumnWidth }); // set width of body table wrapper $fixedBody.css({ 'width': fixedBodyWidth }); // setup clone footer with fixed column if ( settings.footer == true || settings.cloneHeadToFoot == true ) { var $firstTdFootChild = $fixedBody.find('.fht-tfoot thead tr th:first-child'); helpers._fixHeightWithCss( $firstTdFootChild, tableProps ); $tfoot.appendTo($fixedColumn) .find('tr') .append($firstTdFootChild.clone()); $tfoot.css({ 'top': settings.scrollbarOffset }); } }, /* * return void */ _setupTableFooter: function ( $obj, obj, tableProps ) { var $self = $obj, self = obj, $wrapper = $self.closest('.fht-table-wrapper'), $tfoot = $self.find('tfoot'), $divFoot = $wrapper.find('div.fht-tfoot'); if ( !$divFoot.length ) { if ( settings.fixedColumn == true ) { $divFoot = $('
').appendTo($wrapper.find('.fht-fixed-body')); } else { $divFoot = $('
').appendTo($wrapper); } } switch (true) { case !$tfoot.length && settings.cloneHeadToFoot == true && settings.footer == true: var $divHead = $wrapper.find('div.fht-thead'); $divFoot.empty(); $divHead.find('table') .clone() .appendTo($divFoot); break; case $tfoot.length && settings.cloneHeadToFoot == false && settings.footer == true: $divFoot.find('table') .append($tfoot) .css({ 'margin-top': -tableProps.border }); helpers._setupClone( $divFoot, tableProps.tfoot ); break; } }, /* * return object * Widths of each thead cell and tbody cell for the first rows. * Used in fixing widths for the fixed header and optional footer. */ _getTableProps: function( $obj ) { var tableProp = { thead: {}, tbody: {}, tfoot: {}, border: 0 }, borderCollapse = 1; if ( settings.borderCollapse == true ) { borderCollapse = 2; } tableProp.border = ( $obj.find('th:first-child').outerWidth() - $obj.find('th:first-child').innerWidth() ) / borderCollapse; $obj.find('thead tr:first-child th').each(function(index) { tableProp.thead[index] = $(this).width() + tableProp.border; }); $obj.find('tfoot tr:first-child td').each(function(index) { tableProp.tfoot[index] = $(this).width() + tableProp.border; }); $obj.find('tbody tr:first-child td').each(function(index) { tableProp.tbody[index] = $(this).width() + tableProp.border; }); return tableProp; }, /* * return void * Fix widths of each cell in the first row of obj. */ _setupClone: function( $obj, cellArray ) { var $self = $obj, selector = ( $self.find('thead').length ) ? 'thead th' : ( $self.find('tfoot').length ) ? 'tfoot td' : 'tbody td', $cell; $self.find(selector).each(function(index) { $cell = ( $(this).find('div.fht-cell').length ) ? $(this).find('div.fht-cell') : $('
').appendTo($(this)); $cell.css({ 'width': parseInt(cellArray[index]) }); /* * Fixed Header and Footer should extend the full width * to align with the scrollbar of the body */ if ( !$(this).closest('.fht-tbody').length && $(this).is(':last-child') && !$(this).closest('.fht-fixed-column').length ) { var padding = ( ( $(this).innerWidth() - $(this).width() ) / 2 ) + settings.scrollbarOffset; $(this).css({ 'padding-right': padding + 'px' }); } }); }, /* * return boolean * Determine how the browser calculates fixed widths with padding for tables * true if width = padding + width * false if width = width */ _isPaddingIncludedWithWidth: function() { var $obj = $('
test
'), defaultHeight, newHeight; $obj.appendTo('body'); defaultHeight = $obj.find('td').height(); $obj.find('td') .css('height', $obj.find('tr').height()); newHeight = $obj.find('td').height(); $obj.remove(); if ( defaultHeight != newHeight ) { return true; } else { return false; } }, /* * return int * get the width of the browsers scroll bar */ _getScrollbarWidth: function() { var scrollbarWidth = 0; if ( !scrollbarWidth ) { if ( $.browser.msie ) { var $textarea1 = $('') .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'), $textarea2 = $('') .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'); scrollbarWidth = $textarea1.width() - $textarea2.width() + 2; // + 2 for border offset $textarea1.add($textarea2).remove(); } else { var $div = $('
') .css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: -1000 }) .prependTo('body').append('
').find('div') .css({ width: '100%', height: 200 }); scrollbarWidth = 100 - $div.width(); $div.parent().remove(); } } return scrollbarWidth; } }; return methods.init.apply(this, arguments); } })(jQuery)