diff options
Diffstat (limited to 'covoar/table.js')
-rw-r--r-- | covoar/table.js | 1002 |
1 files changed, 0 insertions, 1002 deletions
diff --git a/covoar/table.js b/covoar/table.js deleted file mode 100644 index e1e5d5d..0000000 --- a/covoar/table.js +++ /dev/null @@ -1,1002 +0,0 @@ -/** - * Copyright (c)2005-2009 Matt Kruse (javascripttoolbox.com) - * - * Dual licensed under the MIT and GPL licenses. - * This basically means you can use this code however you want for - * free, but don't claim to have written it yourself! - * Donations always accepted: http://www.JavascriptToolbox.com/donate/ - * - * Please do not link to the .js files on javascripttoolbox.com from - * your site. Copy the files locally to your server instead. - * - */ -/** - * Table.js - * Functions for interactive Tables - * - * Copyright (c) 2007 Matt Kruse (javascripttoolbox.com) - * Dual licensed under the MIT and GPL licenses. - * - * @version 0.981 - * - * @history 0.981 2007-03-19 Added Sort.numeric_comma, additional date parsing formats - * @history 0.980 2007-03-18 Release new BETA release pending some testing. Todo: Additional docs, examples, plus jQuery plugin. - * @history 0.959 2007-03-05 Added more "auto" functionality, couple bug fixes - * @history 0.958 2007-02-28 Added auto functionality based on class names - * @history 0.957 2007-02-21 Speed increases, more code cleanup, added Auto Sort functionality - * @history 0.956 2007-02-16 Cleaned up the code and added Auto Filter functionality. - * @history 0.950 2006-11-15 First BETA release. - * - * @todo Add more date format parsers - * @todo Add style classes to colgroup tags after sorting/filtering in case the user wants to highlight the whole column - * @todo Correct for colspans in data rows (this may slow it down) - * @todo Fix for IE losing form control values after sort? - */ - -/** - * Sort Functions - */ -var Sort = (function(){ - var sort = {}; - // Default alpha-numeric sort - // -------------------------- - sort.alphanumeric = function(a,b) { - return (a==b)?0:(a<b)?-1:1; - }; - sort['default'] = sort.alphanumeric; // IE chokes on sort.default - - // This conversion is generalized to work for either a decimal separator of , or . - sort.numeric_converter = function(separator) { - return function(val) { - if (typeof(val)=="string") { - val = parseFloat(val.replace(/^[^\d\.]*([\d., ]+).*/g,"$1").replace(new RegExp("[^\\\d"+separator+"]","g"),'').replace(/,/,'.')) || 0; - } - return val || 0; - }; - }; - - // Numeric Sort - // ------------ - sort.numeric = function(a,b) { - return sort.numeric.convert(a)-sort.numeric.convert(b); - }; - sort.numeric.convert = sort.numeric_converter("."); - - // Numeric Sort - comma decimal separator - // -------------------------------------- - sort.numeric_comma = function(a,b) { - return sort.numeric_comma.convert(a)-sort.numeric_comma.convert(b); - }; - sort.numeric_comma.convert = sort.numeric_converter(","); - - // Case-insensitive Sort - // --------------------- - sort.ignorecase = function(a,b) { - return sort.alphanumeric(sort.ignorecase.convert(a),sort.ignorecase.convert(b)); - }; - sort.ignorecase.convert = function(val) { - if (val==null) { return ""; } - return (""+val).toLowerCase(); - }; - - // Currency Sort - // ------------- - sort.currency = sort.numeric; // Just treat it as numeric! - sort.currency_comma = sort.numeric_comma; - - // Date sort - // --------- - sort.date = function(a,b) { - return sort.numeric(sort.date.convert(a),sort.date.convert(b)); - }; - // Convert 2-digit years to 4 - sort.date.fixYear=function(yr) { - yr = +yr; - if (yr<50) { yr += 2000; } - else if (yr<100) { yr += 1900; } - return yr; - }; - sort.date.formats = [ - // YY[YY]-MM-DD - { re:/(\d{2,4})-(\d{1,2})-(\d{1,2})/ , f:function(x){ return (new Date(sort.date.fixYear(x[1]),+x[2],+x[3])).getTime(); } } - // MM/DD/YY[YY] or MM-DD-YY[YY] - ,{ re:/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2,4})/ , f:function(x){ return (new Date(sort.date.fixYear(x[3]),+x[1],+x[2])).getTime(); } } - // Any catch-all format that new Date() can handle. This is not reliable except for long formats, for example: 31 Jan 2000 01:23:45 GMT - ,{ re:/(.*\d{4}.*\d+:\d+\d+.*)/, f:function(x){ var d=new Date(x[1]); if(d){return d.getTime();} } } - ]; - sort.date.convert = function(val) { - var m,v, f = sort.date.formats; - for (var i=0,L=f.length; i<L; i++) { - if (m=val.match(f[i].re)) { - v=f[i].f(m); - if (typeof(v)!="undefined") { return v; } - } - } - return 9999999999999; // So non-parsed dates will be last, not first - }; - - return sort; -})(); - -/** - * The main Table namespace - */ -var Table = (function(){ - - /** - * Determine if a reference is defined - */ - function def(o) {return (typeof o!="undefined");}; - - /** - * Determine if an object or class string contains a given class. - */ - function hasClass(o,name) { - return new RegExp("(^|\\s)"+name+"(\\s|$)").test(o.className); - }; - - /** - * Add a class to an object - */ - function addClass(o,name) { - var c = o.className || ""; - if (def(c) && !hasClass(o,name)) { - o.className += (c?" ":"") + name; - } - }; - - /** - * Remove a class from an object - */ - function removeClass(o,name) { - var c = o.className || ""; - o.className = c.replace(new RegExp("(^|\\s)"+name+"(\\s|$)"),"$1"); - }; - - /** - * For classes that match a given substring, return the rest - */ - function classValue(o,prefix) { - var c = o.className; - if (c.match(new RegExp("(^|\\s)"+prefix+"([^ ]+)"))) { - return RegExp.$2; - } - return null; - }; - - /** - * Return true if an object is hidden. - * This uses the "russian doll" technique to unwrap itself to the most efficient - * function after the first pass. This avoids repeated feature detection that - * would always fall into the same block of code. - */ - function isHidden(o) { - if (window.getComputedStyle) { - var cs = window.getComputedStyle; - return (isHidden = function(o) { - return 'none'==cs(o,null).getPropertyValue('display'); - })(o); - } - else if (window.currentStyle) { - return(isHidden = function(o) { - return 'none'==o.currentStyle['display']; - })(o); - } - return (isHidden = function(o) { - return 'none'==o.style['display']; - })(o); - }; - - /** - * Get a parent element by tag name, or the original element if it is of the tag type - */ - function getParent(o,a,b) { - if (o!=null && o.nodeName) { - if (o.nodeName==a || (b && o.nodeName==b)) { - return o; - } - while (o=o.parentNode) { - if (o.nodeName && (o.nodeName==a || (b && o.nodeName==b))) { - return o; - } - } - } - return null; - }; - - /** - * Utility function to copy properties from one object to another - */ - function copy(o1,o2) { - for (var i=2;i<arguments.length; i++) { - var a = arguments[i]; - if (def(o1[a])) { - o2[a] = o1[a]; - } - } - } - - // The table object itself - var table = { - //Class names used in the code - AutoStripeClassName:"table-autostripe", - StripeClassNamePrefix:"table-stripeclass:", - - AutoSortClassName:"table-autosort", - AutoSortColumnPrefix:"table-autosort:", - AutoSortTitle:"Click to sort", - SortedAscendingClassName:"table-sorted-asc", - SortedDescendingClassName:"table-sorted-desc", - SortableClassName:"table-sortable", - SortableColumnPrefix:"table-sortable:", - NoSortClassName:"table-nosort", - - AutoFilterClassName:"table-autofilter", - FilteredClassName:"table-filtered", - FilterableClassName:"table-filterable", - FilteredRowcountPrefix:"table-filtered-rowcount:", - RowcountPrefix:"table-rowcount:", - FilterAllLabel:"Filter: All", - - AutoPageSizePrefix:"table-autopage:", - AutoPageJumpPrefix:"table-page:", - PageNumberPrefix:"table-page-number:", - PageCountPrefix:"table-page-count:" - }; - - /** - * A place to store misc table information, rather than in the table objects themselves - */ - table.tabledata = {}; - - /** - * Resolve a table given an element reference, and make sure it has a unique ID - */ - table.uniqueId=1; - table.resolve = function(o,args) { - if (o!=null && o.nodeName && o.nodeName!="TABLE") { - o = getParent(o,"TABLE"); - } - if (o==null) { return null; } - if (!o.id) { - var id = null; - do { var id = "TABLE_"+(table.uniqueId++); } - while (document.getElementById(id)!=null); - o.id = id; - } - this.tabledata[o.id] = this.tabledata[o.id] || {}; - if (args) { - copy(args,this.tabledata[o.id],"stripeclass","ignorehiddenrows","useinnertext","sorttype","col","desc","page","pagesize"); - } - return o; - }; - - - /** - * Run a function against each cell in a table header or footer, usually - * to add or remove css classes based on sorting, filtering, etc. - */ - table.processTableCells = function(t, type, func, arg) { - t = this.resolve(t); - if (t==null) { return; } - if (type!="TFOOT") { - this.processCells(t.tHead, func, arg); - } - if (type!="THEAD") { - this.processCells(t.tFoot, func, arg); - } - }; - - /** - * Internal method used to process an arbitrary collection of cells. - * Referenced by processTableCells. - * It's done this way to avoid getElementsByTagName() which would also return nested table cells. - */ - table.processCells = function(section,func,arg) { - if (section!=null) { - if (section.rows && section.rows.length && section.rows.length>0) { - var rows = section.rows; - for (var j=0,L2=rows.length; j<L2; j++) { - var row = rows[j]; - if (row.cells && row.cells.length && row.cells.length>0) { - var cells = row.cells; - for (var k=0,L3=cells.length; k<L3; k++) { - var cellsK = cells[k]; - func.call(this,cellsK,arg); - } - } - } - } - } - }; - - /** - * Get the cellIndex value for a cell. This is only needed because of a Safari - * bug that causes cellIndex to exist but always be 0. - * Rather than feature-detecting each time it is called, the function will - * re-write itself the first time it is called. - */ - table.getCellIndex = function(td) { - var tr = td.parentNode; - var cells = tr.cells; - if (cells && cells.length) { - if (cells.length>1 && cells[cells.length-1].cellIndex>0) { - // Define the new function, overwrite the one we're running now, and then run the new one - (this.getCellIndex = function(td) { - return td.cellIndex; - })(td); - } - // Safari will always go through this slower block every time. Oh well. - for (var i=0,L=cells.length; i<L; i++) { - if (tr.cells[i]==td) { - return i; - } - } - } - return 0; - }; - - /** - * A map of node names and how to convert them into their "value" for sorting, filtering, etc. - * These are put here so it is extensible. - */ - table.nodeValue = { - 'INPUT':function(node) { - if (def(node.value) && node.type && ((node.type!="checkbox" && node.type!="radio") || node.checked)) { - return node.value; - } - return ""; - }, - 'SELECT':function(node) { - if (node.selectedIndex>=0 && node.options) { - // Sort select elements by the visible text - return node.options[node.selectedIndex].text; - } - return ""; - }, - 'IMG':function(node) { - return node.name || ""; - } - }; - - /** - * Get the text value of a cell. Only use innerText if explicitly told to, because - * otherwise we want to be able to handle sorting on inputs and other types - */ - table.getCellValue = function(td,useInnerText) { - if (useInnerText && def(td.innerText)) { - return td.innerText; - } - if (!td.childNodes) { - return ""; - } - var childNodes=td.childNodes; - var ret = ""; - for (var i=0,L=childNodes.length; i<L; i++) { - var node = childNodes[i]; - var type = node.nodeType; - // In order to get realistic sort results, we need to treat some elements in a special way. - // These behaviors are defined in the nodeValue() object, keyed by node name - if (type==1) { - var nname = node.nodeName; - if (this.nodeValue[nname]) { - ret += this.nodeValue[nname](node); - } - else { - ret += this.getCellValue(node); - } - } - else if (type==3) { - if (def(node.innerText)) { - ret += node.innerText; - } - else if (def(node.nodeValue)) { - ret += node.nodeValue; - } - } - } - return ret; - }; - - /** - * Consider colspan and rowspan values in table header cells to calculate the actual cellIndex - * of a given cell. This is necessary because if the first cell in row 0 has a rowspan of 2, - * then the first cell in row 1 will have a cellIndex of 0 rather than 1, even though it really - * starts in the second column rather than the first. - * See: http://www.javascripttoolbox.com/temp/table_cellindex.html - */ - table.tableHeaderIndexes = {}; - table.getActualCellIndex = function(tableCellObj) { - if (!def(tableCellObj.cellIndex)) { return null; } - var tableObj = getParent(tableCellObj,"TABLE"); - var cellCoordinates = tableCellObj.parentNode.rowIndex+"-"+this.getCellIndex(tableCellObj); - - // If it has already been computed, return the answer from the lookup table - if (def(this.tableHeaderIndexes[tableObj.id])) { - return this.tableHeaderIndexes[tableObj.id][cellCoordinates]; - } - - var matrix = []; - this.tableHeaderIndexes[tableObj.id] = {}; - var thead = getParent(tableCellObj,"THEAD"); - var trs = thead.getElementsByTagName('TR'); - - // Loop thru every tr and every cell in the tr, building up a 2-d array "grid" that gets - // populated with an "x" for each space that a cell takes up. If the first cell is colspan - // 2, it will fill in values [0] and [1] in the first array, so that the second cell will - // find the first empty cell in the first row (which will be [2]) and know that this is - // where it sits, rather than its internal .cellIndex value of [1]. - for (var i=0; i<trs.length; i++) { - var cells = trs[i].cells; - for (var j=0; j<cells.length; j++) { - var c = cells[j]; - var rowIndex = c.parentNode.rowIndex; - var cellId = rowIndex+"-"+this.getCellIndex(c); - var rowSpan = c.rowSpan || 1; - var colSpan = c.colSpan || 1; - var firstAvailCol; - if(!def(matrix[rowIndex])) { - matrix[rowIndex] = []; - } - var m = matrix[rowIndex]; - // Find first available column in the first row - for (var k=0; k<m.length+1; k++) { - if (!def(m[k])) { - firstAvailCol = k; - break; - } - } - this.tableHeaderIndexes[tableObj.id][cellId] = firstAvailCol; - for (var k=rowIndex; k<rowIndex+rowSpan; k++) { - if(!def(matrix[k])) { - matrix[k] = []; - } - var matrixrow = matrix[k]; - for (var l=firstAvailCol; l<firstAvailCol+colSpan; l++) { - matrixrow[l] = "x"; - } - } - } - } - // Store the map so future lookups are fast. - return this.tableHeaderIndexes[tableObj.id][cellCoordinates]; - }; - - /** - * Sort all rows in each TBODY (tbodies are sorted independent of each other) - */ - table.sort = function(o,args) { - var t, tdata, sortconvert=null; - // Allow for a simple passing of sort type as second parameter - if (typeof(args)=="function") { - args={sorttype:args}; - } - args = args || {}; - - // If no col is specified, deduce it from the object sent in - if (!def(args.col)) { - args.col = this.getActualCellIndex(o) || 0; - } - // If no sort type is specified, default to the default sort - args.sorttype = args.sorttype || Sort['default']; - - // Resolve the table - t = this.resolve(o,args); - tdata = this.tabledata[t.id]; - - // If we are sorting on the same column as last time, flip the sort direction - if (def(tdata.lastcol) && tdata.lastcol==tdata.col && def(tdata.lastdesc)) { - tdata.desc = !tdata.lastdesc; - } - else { - tdata.desc = !!args.desc; - } - - // Store the last sorted column so clicking again will reverse the sort order - tdata.lastcol=tdata.col; - tdata.lastdesc=!!tdata.desc; - - // If a sort conversion function exists, pre-convert cell values and then use a plain alphanumeric sort - var sorttype = tdata.sorttype; - if (typeof(sorttype.convert)=="function") { - sortconvert=tdata.sorttype.convert; - sorttype=Sort.alphanumeric; - } - - // Loop through all THEADs and remove sorted class names, then re-add them for the col - // that is being sorted - this.processTableCells(t,"THEAD", - function(cell) { - if (hasClass(cell,this.SortableClassName)) { - removeClass(cell,this.SortedAscendingClassName); - removeClass(cell,this.SortedDescendingClassName); - // If the computed colIndex of the cell equals the sorted colIndex, flag it as sorted - if (tdata.col==table.getActualCellIndex(cell) && (classValue(cell,table.SortableClassName))) { - addClass(cell,tdata.desc?this.SortedAscendingClassName:this.SortedDescendingClassName); - } - } - } - ); - - // Sort each tbody independently - var bodies = t.tBodies; - if (bodies==null || bodies.length==0) { return; } - - // Define a new sort function to be called to consider descending or not - var newSortFunc = (tdata.desc)? - function(a,b){return sorttype(b[0],a[0]);} - :function(a,b){return sorttype(a[0],b[0]);}; - - var useinnertext=!!tdata.useinnertext; - var col = tdata.col; - - for (var i=0,L=bodies.length; i<L; i++) { - var tb = bodies[i], tbrows = tb.rows, rows = []; - - // Allow tbodies to request that they not be sorted - if(!hasClass(tb,table.NoSortClassName)) { - // Create a separate array which will store the converted values and refs to the - // actual rows. This is the array that will be sorted. - var cRow, cRowIndex=0; - if (cRow=tbrows[cRowIndex]){ - // Funky loop style because it's considerably faster in IE - do { - if (rowCells = cRow.cells) { - var cellValue = (col<rowCells.length)?this.getCellValue(rowCells[col],useinnertext):null; - if (sortconvert) cellValue = sortconvert(cellValue); - rows[cRowIndex] = [cellValue,tbrows[cRowIndex]]; - } - } while (cRow=tbrows[++cRowIndex]) - } - - // Do the actual sorting - rows.sort(newSortFunc); - - // Move the rows to the correctly sorted order. Appending an existing DOM object just moves it! - cRowIndex=0; - var displayedCount=0; - var f=[removeClass,addClass]; - if (cRow=rows[cRowIndex]){ - do { - tb.appendChild(cRow[1]); - } while (cRow=rows[++cRowIndex]) - } - } - } - - // If paging is enabled on the table, then we need to re-page because the order of rows has changed! - if (tdata.pagesize) { - this.page(t); // This will internally do the striping - } - else { - // Re-stripe if a class name was supplied - if (tdata.stripeclass) { - this.stripe(t,tdata.stripeclass,!!tdata.ignorehiddenrows); - } - } - }; - - /** - * Apply a filter to rows in a table and hide those that do not match. - */ - table.filter = function(o,filters,args) { - var cell; - args = args || {}; - - var t = this.resolve(o,args); - var tdata = this.tabledata[t.id]; - - // If new filters were passed in, apply them to the table's list of filters - if (!filters) { - // If a null or blank value was sent in for 'filters' then that means reset the table to no filters - tdata.filters = null; - } - else { - // Allow for passing a select list in as the filter, since this is common design - if (filters.nodeName=="SELECT" && filters.type=="select-one" && filters.selectedIndex>-1) { - filters={ 'filter':filters.options[filters.selectedIndex].value }; - } - // Also allow for a regular input - if (filters.nodeName=="INPUT" && filters.type=="text") { - filters={ 'filter':"/^"+filters.value+"/" }; - } - // Force filters to be an array - if (typeof(filters)=="object" && !filters.length) { - filters = [filters]; - } - - // Convert regular expression strings to RegExp objects and function strings to function objects - for (var i=0,L=filters.length; i<L; i++) { - var filter = filters[i]; - if (typeof(filter.filter)=="string") { - // If a filter string is like "/expr/" then turn it into a Regex - if (filter.filter.match(/^\/(.*)\/$/)) { - filter.filter = new RegExp(RegExp.$1); - filter.filter.regex=true; - } - // If filter string is like "function (x) { ... }" then turn it into a function - else if (filter.filter.match(/^function\s*\(([^\)]*)\)\s*\{(.*)}\s*$/)) { - filter.filter = Function(RegExp.$1,RegExp.$2); - } - } - // If some non-table object was passed in rather than a 'col' value, resolve it - // and assign it's column index to the filter if it doesn't have one. This way, - // passing in a cell reference or a select object etc instead of a table object - // will automatically set the correct column to filter. - if (filter && !def(filter.col) && (cell=getParent(o,"TD","TH"))) { - filter.col = this.getCellIndex(cell); - } - - // Apply the passed-in filters to the existing list of filters for the table, removing those that have a filter of null or "" - if ((!filter || !filter.filter) && tdata.filters) { - delete tdata.filters[filter.col]; - } - else { - tdata.filters = tdata.filters || {}; - tdata.filters[filter.col] = filter.filter; - } - } - // If no more filters are left, then make sure to empty out the filters object - for (var j in tdata.filters) { var keep = true; } - if (!keep) { - tdata.filters = null; - } - } - // Everything's been setup, so now scrape the table rows - return table.scrape(o); - }; - - /** - * "Page" a table by showing only a subset of the rows - */ - table.page = function(t,page,args) { - args = args || {}; - if (def(page)) { args.page = page; } - return table.scrape(t,args); - }; - - /** - * Jump forward or back any number of pages - */ - table.pageJump = function(t,count,args) { - t = this.resolve(t,args); - return this.page(t,(table.tabledata[t.id].page||0)+count,args); - }; - - /** - * Go to the next page of a paged table - */ - table.pageNext = function(t,args) { - return this.pageJump(t,1,args); - }; - - /** - * Go to the previous page of a paged table - */ - table.pagePrevious = function(t,args) { - return this.pageJump(t,-1,args); - }; - - /** - * Scrape a table to either hide or show each row based on filters and paging - */ - table.scrape = function(o,args) { - var col,cell,filterList,filterReset=false,filter; - var page,pagesize,pagestart,pageend; - var unfilteredrows=[],unfilteredrowcount=0,totalrows=0; - var t,tdata,row,hideRow; - args = args || {}; - - // Resolve the table object - t = this.resolve(o,args); - tdata = this.tabledata[t.id]; - - // Setup for Paging - var page = tdata.page; - if (def(page)) { - // Don't let the page go before the beginning - if (page<0) { tdata.page=page=0; } - pagesize = tdata.pagesize || 25; // 25=arbitrary default - pagestart = page*pagesize+1; - pageend = pagestart + pagesize - 1; - } - - // Scrape each row of each tbody - var bodies = t.tBodies; - if (bodies==null || bodies.length==0) { return; } - for (var i=0,L=bodies.length; i<L; i++) { - var tb = bodies[i]; - for (var j=0,L2=tb.rows.length; j<L2; j++) { - row = tb.rows[j]; - hideRow = false; - - // Test if filters will hide the row - if (tdata.filters && row.cells) { - var cells = row.cells; - var cellsLength = cells.length; - // Test each filter - for (col in tdata.filters) { - if (!hideRow) { - filter = tdata.filters[col]; - if (filter && col<cellsLength) { - var val = this.getCellValue(cells[col]); - if (filter.regex && val.search) { - hideRow=(val.search(filter)<0); - } - else if (typeof(filter)=="function") { - hideRow=!filter(val,cells[col]); - } - else { - hideRow = (val!=filter); - } - } - } - } - } - - // Keep track of the total rows scanned and the total runs _not_ filtered out - totalrows++; - if (!hideRow) { - unfilteredrowcount++; - if (def(page)) { - // Temporarily keep an array of unfiltered rows in case the page we're on goes past - // the last page and we need to back up. Don't want to filter again! - unfilteredrows.push(row); - if (unfilteredrowcount<pagestart || unfilteredrowcount>pageend) { - hideRow = true; - } - } - } - - row.style.display = hideRow?"none":""; - } - } - - if (def(page)) { - // Check to see if filtering has put us past the requested page index. If it has, - // then go back to the last page and show it. - if (pagestart>=unfilteredrowcount) { - pagestart = unfilteredrowcount-(unfilteredrowcount%pagesize); - tdata.page = page = pagestart/pagesize; - for (var i=pagestart,L=unfilteredrows.length; i<L; i++) { - unfilteredrows[i].style.display=""; - } - } - } - - // Loop through all THEADs and add/remove filtered class names - this.processTableCells(t,"THEAD", - function(c) { - ((tdata.filters && def(tdata.filters[table.getCellIndex(c)]) && hasClass(c,table.FilterableClassName))?addClass:removeClass)(c,table.FilteredClassName); - } - ); - - // Stripe the table if necessary - if (tdata.stripeclass) { - this.stripe(t); - } - - // Calculate some values to be returned for info and updating purposes - var pagecount = Math.floor(unfilteredrowcount/pagesize)+1; - if (def(page)) { - // Update the page number/total containers if they exist - if (tdata.container_number) { - tdata.container_number.innerHTML = page+1; - } - if (tdata.container_count) { - tdata.container_count.innerHTML = pagecount; - } - } - - // Update the row count containers if they exist - if (tdata.container_filtered_count) { - tdata.container_filtered_count.innerHTML = unfilteredrowcount; - } - if (tdata.container_all_count) { - tdata.container_all_count.innerHTML = totalrows; - } - return { 'data':tdata, 'unfilteredcount':unfilteredrowcount, 'total':totalrows, 'pagecount':pagecount, 'page':page, 'pagesize':pagesize }; - }; - - /** - * Shade alternate rows, aka Stripe the table. - */ - table.stripe = function(t,className,args) { - args = args || {}; - args.stripeclass = className; - - t = this.resolve(t,args); - var tdata = this.tabledata[t.id]; - - var bodies = t.tBodies; - if (bodies==null || bodies.length==0) { - return; - } - - className = tdata.stripeclass; - // Cache a shorter, quicker reference to either the remove or add class methods - var f=[removeClass,addClass]; - for (var i=0,L=bodies.length; i<L; i++) { - var tb = bodies[i], tbrows = tb.rows, cRowIndex=0, cRow, displayedCount=0; - if (cRow=tbrows[cRowIndex]){ - // The ignorehiddenrows test is pulled out of the loop for a slight speed increase. - // Makes a bigger difference in FF than in IE. - // In this case, speed always wins over brevity! - if (tdata.ignoreHiddenRows) { - do { - f[displayedCount++%2](cRow,className); - } while (cRow=tbrows[++cRowIndex]) - } - else { - do { - if (!isHidden(cRow)) { - f[displayedCount++%2](cRow,className); - } - } while (cRow=tbrows[++cRowIndex]) - } - } - } - }; - - /** - * Build up a list of unique values in a table column - */ - table.getUniqueColValues = function(t,col) { - var values={}, bodies = this.resolve(t).tBodies; - for (var i=0,L=bodies.length; i<L; i++) { - var tbody = bodies[i]; - for (var r=0,L2=tbody.rows.length; r<L2; r++) { - values[this.getCellValue(tbody.rows[r].cells[col])] = true; - } - } - var valArray = []; - for (var val in values) { - valArray.push(val); - } - return valArray.sort(); - }; - - /** - * Scan the document on load and add sorting, filtering, paging etc ability automatically - * based on existence of class names on the table and cells. - */ - table.auto = function(args) { - var cells = [], tables = document.getElementsByTagName("TABLE"); - var val,tdata; - if (tables!=null) { - for (var i=0,L=tables.length; i<L; i++) { - var t = table.resolve(tables[i]); - tdata = table.tabledata[t.id]; - if (val=classValue(t,table.StripeClassNamePrefix)) { - tdata.stripeclass=val; - } - // Do auto-filter if necessary - if (hasClass(t,table.AutoFilterClassName)) { - table.autofilter(t); - } - // Do auto-page if necessary - if (val = classValue(t,table.AutoPageSizePrefix)) { - table.autopage(t,{'pagesize':+val}); - } - // Do auto-sort if necessary - if ((val = classValue(t,table.AutoSortColumnPrefix)) || (hasClass(t,table.AutoSortClassName))) { - table.autosort(t,{'col':(val==null)?null:+val}); - } - // Do auto-stripe if necessary - if (tdata.stripeclass && hasClass(t,table.AutoStripeClassName)) { - table.stripe(t); - } - } - } - }; - - /** - * Add sorting functionality to a table header cell - */ - table.autosort = function(t,args) { - t = this.resolve(t,args); - var tdata = this.tabledata[t.id]; - this.processTableCells(t, "THEAD", function(c) { - var type = classValue(c,table.SortableColumnPrefix); - if (type!=null) { - type = type || "default"; - c.title =c.title || table.AutoSortTitle; - addClass(c,table.SortableClassName); - c.onclick = Function("","Table.sort(this,{'sorttype':Sort['"+type+"']})"); - // If we are going to auto sort on a column, we need to keep track of what kind of sort it will be - if (args.col!=null) { - if (args.col==table.getActualCellIndex(c)) { - tdata.sorttype=Sort['"+type+"']; - } - } - } - } ); - if (args.col!=null) { - table.sort(t,args); - } - }; - - /** - * Add paging functionality to a table - */ - table.autopage = function(t,args) { - t = this.resolve(t,args); - var tdata = this.tabledata[t.id]; - if (tdata.pagesize) { - this.processTableCells(t, "THEAD,TFOOT", function(c) { - var type = classValue(c,table.AutoPageJumpPrefix); - if (type=="next") { type = 1; } - else if (type=="previous") { type = -1; } - if (type!=null) { - c.onclick = Function("","Table.pageJump(this,"+type+")"); - } - } ); - if (val = classValue(t,table.PageNumberPrefix)) { - tdata.container_number = document.getElementById(val); - } - if (val = classValue(t,table.PageCountPrefix)) { - tdata.container_count = document.getElementById(val); - } - return table.page(t,0,args); - } - }; - - /** - * A util function to cancel bubbling of clicks on filter dropdowns - */ - table.cancelBubble = function(e) { - e = e || window.event; - if (typeof(e.stopPropagation)=="function") { e.stopPropagation(); } - if (def(e.cancelBubble)) { e.cancelBubble = true; } - }; - - /** - * Auto-filter a table - */ - table.autofilter = function(t,args) { - args = args || {}; - t = this.resolve(t,args); - var tdata = this.tabledata[t.id],val; - table.processTableCells(t, "THEAD", function(cell) { - if (hasClass(cell,table.FilterableClassName)) { - var cellIndex = table.getCellIndex(cell); - var colValues = table.getUniqueColValues(t,cellIndex); - if (colValues.length>0) { - if (typeof(args.insert)=="function") { - func.insert(cell,colValues); - } - else { - var sel = '<select onchange="Table.filter(this,this)" onclick="Table.cancelBubble(event)" class="'+table.AutoFilterClassName+'"><option value="">'+table.FilterAllLabel+'</option>'; - for (var i=0; i<colValues.length; i++) { - sel += '<option value="'+colValues[i]+'">'+colValues[i]+'</option>'; - } - sel += '</select>'; - cell.innerHTML += "<br>"+sel; - } - } - } - }); - if (val = classValue(t,table.FilteredRowcountPrefix)) { - tdata.container_filtered_count = document.getElementById(val); - } - if (val = classValue(t,table.RowcountPrefix)) { - tdata.container_all_count = document.getElementById(val); - } - }; - - /** - * Attach the auto event so it happens on load. - * use jQuery's ready() function if available - */ - if (typeof(jQuery)!="undefined") { - jQuery(table.auto); - } - else if (window.addEventListener) { - window.addEventListener( "load", table.auto, false ); - } - else if (window.attachEvent) { - window.attachEvent( "onload", table.auto ); - } - - return table; -})(); |