/*! Widget: resizable */ ;(function ($, window) { 'use strict'; var ts = $.tablesorter = $.tablesorter || {}; $.extend(ts.css, { resizer : 'tablesorter-resizer' // resizable }); // this widget saves the column widths if // $.tablesorter.storage function is included // ************************** ts.addWidget({ id: "resizable", priority: 40, options: { resizable : true, resizable_addLastColumn : false, resizable_widths : [], resizable_throttle : false // set to true (5ms) or any number 0-10 range }, format: function(table, c, wo) { if (c.$table.hasClass('hasResizable')) { return; } c.$table.addClass('hasResizable'); ts.resizableReset(table, true); // set default widths var $rows, $columns, $column, column, timer, storedSizes = {}, $table = c.$table, $wrap = $table.parent(), overflow = $table.parent().css('overflow') === 'auto', mouseXPosition = 0, $target = null, $next = null, fullWidth = Math.abs($table.parent().width() - $table.width()) < 20, mouseMove = function(event){ if (mouseXPosition === 0 || !$target) { return; } // resize columns var leftEdge = event.pageX - mouseXPosition, targetWidth = $target.width(); $target.width( targetWidth + leftEdge ); if ($target.width() !== targetWidth && fullWidth) { $next.width( $next.width() - leftEdge ); } else if (overflow) { $table.width(function(i, w){ return w + leftEdge; }); if (!$next.length) { // if expanding right-most column, scroll the wrapper $wrap[0].scrollLeft = $table.width(); } } mouseXPosition = event.pageX; }, stopResize = function() { if (ts.storage && $target && $next) { storedSizes = {}; storedSizes[$target.index()] = $target.width(); storedSizes[$next.index()] = $next.width(); $target.width( storedSizes[$target.index()] ); $next.width( storedSizes[$next.index()] ); if (wo.resizable !== false) { // save all column widths ts.storage(table, 'tablesorter-resizable', c.$headers.map(function(){ return $(this).width(); }).get() ); } } mouseXPosition = 0; $target = $next = null; $(window).trigger('resize'); // will update stickyHeaders, just in case }; storedSizes = (ts.storage && wo.resizable !== false) ? ts.storage(table, 'tablesorter-resizable') : {}; // process only if table ID or url match if (storedSizes) { for (column in storedSizes) { if (!isNaN(column) && column < c.$headers.length) { c.$headers.eq(column).width(storedSizes[column]); // set saved resizable widths } } } $rows = $table.children('thead:first').children('tr'); // add resizable-false class name to headers (across rows as needed) $rows.children().each(function() { var canResize, $column = $(this); column = $column.attr('data-column'); canResize = ts.getData( $column, ts.getColumnData( table, c.headers, column ), 'resizable') === "false"; $rows.children().filter('[data-column="' + column + '"]')[canResize ? 'addClass' : 'removeClass']('resizable-false'); }); // add wrapper inside each cell to allow for positioning of the resizable target block $rows.each(function() { $column = $(this).children().not('.resizable-false'); if (!$(this).find('.' + ts.css.wrapper).length) { // Firefox needs this inner div to position the resizer correctly $column.wrapInner('
'); } // don't include the last column of the row if (!wo.resizable_addLastColumn) { $column = $column.slice(0,-1); } $columns = $columns ? $columns.add($column) : $column; }); $columns .each(function() { var $column = $(this), padding = parseInt($column.css('padding-right'), 10) + 10; // 10 is 1/2 of the 20px wide resizer $column .find('.' + ts.css.wrapper) .append(''); }) .find('.' + ts.css.resizer) .bind('mousedown', function(event) { // save header cell and mouse position $target = $(event.target).closest('th'); var $header = c.$headers.filter('[data-column="' + $target.attr('data-column') + '"]'); if ($header.length > 1) { $target = $target.add($header); } // if table is not as wide as it's parent, then resize the table $next = event.shiftKey ? $target.parent().find('th').not('.resizable-false').filter(':last') : $target.nextAll(':not(.resizable-false)').eq(0); mouseXPosition = event.pageX; }); $(document) .bind('mousemove.tsresize', function(event) { // ignore mousemove if no mousedown if (mouseXPosition === 0 || !$target) { return; } if (wo.resizable_throttle) { clearTimeout(timer); timer = setTimeout(function(){ mouseMove(event); }, isNaN(wo.resizable_throttle) ? 5 : wo.resizable_throttle ); } else { mouseMove(event); } }) .bind('mouseup.tsresize', function() { stopResize(); }); // right click to reset columns to default widths $table.find('thead:first').bind('contextmenu.tsresize', function() { ts.resizableReset(table); // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset var allowClick = $.isEmptyObject ? $.isEmptyObject(storedSizes) : true; storedSizes = {}; return allowClick; }); }, remove: function(table, c) { c.$table .removeClass('hasResizable') .children('thead') .unbind('mouseup.tsresize mouseleave.tsresize contextmenu.tsresize') .children('tr').children() .unbind('mousemove.tsresize mouseup.tsresize') // don't remove "tablesorter-wrapper" as uitheme uses it too .find('.' + ts.css.resizer).remove(); ts.resizableReset(table); } }); ts.resizableReset = function(table, nosave) { $(table).each(function(){ var $t, c = this.config, wo = c && c.widgetOptions; if (table && c) { c.$headers.each(function(i){ $t = $(this); if (wo.resizable_widths && wo.resizable_widths[i]) { $t.css('width', wo.resizable_widths[i]); } else if (!$t.hasClass('resizable-false')) { // don't clear the width of any column that is not resizable $t.css('width',''); } }); if (ts.storage && !nosave) { ts.storage(this, 'tablesorter-resizable', {}); } } }); }; })(jQuery, window);