mirror of
https://github.com/koalyptus/TableFilter.git
synced 2024-05-10 02:16:40 +02:00
Added ColOps module + tests
This commit is contained in:
parent
c50abe6502
commit
4603ce4302
2
dist/filtergrid.css
vendored
2
dist/filtergrid.css
vendored
|
@ -1,6 +1,6 @@
|
||||||
/*------------------------------------------------------------------------
|
/*------------------------------------------------------------------------
|
||||||
- TableFilter stylesheet by Max Guglielmi
|
- TableFilter stylesheet by Max Guglielmi
|
||||||
- (build date: Sun Nov 09 2014 19:28:32)
|
- (build date: Sat Nov 15 2014 19:34:47)
|
||||||
- Edit below for your projects' needs
|
- Edit below for your projects' needs
|
||||||
------------------------------------------------------------------------*/
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
10
dist/tablefilter.js
vendored
10
dist/tablefilter.js
vendored
File diff suppressed because one or more lines are too long
|
@ -6,6 +6,15 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<table id="demo" cellpadding="0" cellspacing="0">
|
<table id="demo" cellpadding="0" cellspacing="0">
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>Tot:</td>
|
||||||
|
<td></td>
|
||||||
|
<td id="sum1"></td>
|
||||||
|
<td id="sum2"></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>From</th>
|
<th>From</th>
|
||||||
|
@ -68,6 +77,9 @@
|
||||||
|
|
||||||
<script type="text/javascript" src="../dist/tablefilter.js"></script>
|
<script type="text/javascript" src="../dist/tablefilter.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
var table = document.getElementById('demo');
|
||||||
|
var totRowIndex = table.getElementsByTagName("tr").length;
|
||||||
|
|
||||||
var tf = new TableFilter("demo", {
|
var tf = new TableFilter("demo", {
|
||||||
col_0: 'select',
|
col_0: 'select',
|
||||||
col_3: 'checklist',
|
col_3: 'checklist',
|
||||||
|
@ -79,7 +91,18 @@
|
||||||
match_case: false,
|
match_case: false,
|
||||||
remember_grid_values: true,
|
remember_grid_values: true,
|
||||||
btn_reset: true,
|
btn_reset: true,
|
||||||
grid_layout: false
|
grid_layout: false,
|
||||||
|
|
||||||
|
rows_always_visible: [totRowIndex],
|
||||||
|
col_operation: {
|
||||||
|
id: ["sum1", "sum2"],
|
||||||
|
col: [2, 3],
|
||||||
|
operation: ["sum", "mean"],
|
||||||
|
write_method: ["innerhtml", 'innerhtml'],
|
||||||
|
exclude_row: [totRowIndex],
|
||||||
|
decimal_precision: [0, 2],
|
||||||
|
tot_row_index: [totRowIndex, totRowIndex]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tf.init();
|
tf.init();
|
||||||
|
|
|
@ -11,7 +11,7 @@ define(function (require) {
|
||||||
has: function(arr, val, caseSensitive){
|
has: function(arr, val, caseSensitive){
|
||||||
var sCase = caseSensitive===undefined ? false : caseSensitive;
|
var sCase = caseSensitive===undefined ? false : caseSensitive;
|
||||||
for (var i=0; i<arr.length; i++){
|
for (var i=0; i<arr.length; i++){
|
||||||
if(str.matchCase(arr[i].toString(), sCase) === val){
|
if(str.matchCase(arr[i].toString(), sCase) == val){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ define(function (require) {
|
||||||
indexByValue: function(arr, val, caseSensitive){
|
indexByValue: function(arr, val, caseSensitive){
|
||||||
var sCase = caseSensitive===undefined ? false : caseSensitive;
|
var sCase = caseSensitive===undefined ? false : caseSensitive;
|
||||||
for (var i=0; i<arr.length; i++){
|
for (var i=0; i<arr.length; i++){
|
||||||
if(str.matchCase(arr[i].toString(), sCase) === val){
|
if(str.matchCase(arr[i].toString(), sCase) == val){
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
313
src/core.js
313
src/core.js
|
@ -198,10 +198,6 @@ function TableFilter(id) {
|
||||||
//defines css class for single-filter
|
//defines css class for single-filter
|
||||||
this.singleFltCssClass = f.single_flt_css_class || 'single_flt';
|
this.singleFltCssClass = f.single_flt_css_class || 'single_flt';
|
||||||
this.isStartBgAlternate = true;
|
this.isStartBgAlternate = true;
|
||||||
// //defines css class for even rows
|
|
||||||
// this.rowBgEvenCssClass = f.even_row_css_class || 'even';
|
|
||||||
// //defines css class for odd rows
|
|
||||||
// this.rowBgOddCssClass = f.odd_row_css_class || 'odd';
|
|
||||||
|
|
||||||
/*** filters' grid behaviours ***/
|
/*** filters' grid behaviours ***/
|
||||||
//enables/disables enter key
|
//enables/disables enter key
|
||||||
|
@ -230,10 +226,10 @@ function TableFilter(id) {
|
||||||
//id of active filter
|
//id of active filter
|
||||||
this.activeFilterId = null;
|
this.activeFilterId = null;
|
||||||
//enables/disbles column operation(sum,mean)
|
//enables/disbles column operation(sum,mean)
|
||||||
this.hasColOperation = f.col_operation===true ? true : false;
|
this.hasColOperation = f.col_operation ? true : false;
|
||||||
this.colOperation = null;
|
this.colOperation = null;
|
||||||
//enables always visible rows
|
//enables always visible rows
|
||||||
this.hasVisibleRows = f.rows_always_visible===true ? true : false;
|
this.hasVisibleRows = f.rows_always_visible ? true : false;
|
||||||
//array containing always visible rows
|
//array containing always visible rows
|
||||||
this.visibleRows = this.hasVisibleRows ? f.rows_always_visible : [];
|
this.visibleRows = this.hasVisibleRows ? f.rows_always_visible : [];
|
||||||
//defines search type: include or exclude
|
//defines search type: include or exclude
|
||||||
|
@ -679,7 +675,8 @@ function TableFilter(id) {
|
||||||
// Components
|
// Components
|
||||||
this.Cpt = {
|
this.Cpt = {
|
||||||
loader: null,
|
loader: null,
|
||||||
alternateRows: null
|
alternateRows: null,
|
||||||
|
colOps: null
|
||||||
};
|
};
|
||||||
|
|
||||||
/*** TF events ***/
|
/*** TF events ***/
|
||||||
|
@ -1224,9 +1221,10 @@ TableFilter.prototype = {
|
||||||
this.Cpt.alternateRows = new AlternateRows(this);
|
this.Cpt.alternateRows = new AlternateRows(this);
|
||||||
this.Cpt.alternateRows.set();
|
this.Cpt.alternateRows.set();
|
||||||
}
|
}
|
||||||
if(this.hasColOperation && this.fltGrid){
|
if(this.hasColOperation){
|
||||||
this.colOperation = f.col_operation;
|
var ColOps = require('modules/colOps');
|
||||||
this.SetColOperation();
|
this.Cpt.colOps = new ColOps(this);
|
||||||
|
this.Cpt.colOps.set();
|
||||||
}
|
}
|
||||||
if(this.sort || this.gridLayout){
|
if(this.sort || this.gridLayout){
|
||||||
this.SetSort();
|
this.SetSort();
|
||||||
|
@ -5167,11 +5165,12 @@ TableFilter.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
//shows rows always visible
|
//shows rows always visible
|
||||||
if(this.visibleRows)
|
if(this.visibleRows){
|
||||||
this.SetVisibleRows();
|
this.SetVisibleRows();
|
||||||
|
}
|
||||||
//makes operation on a col
|
//makes operation on a col
|
||||||
if(this.colOperation){
|
if(this.hasColOperation){
|
||||||
this.SetColOperation();
|
this.Cpt.colOps.set();
|
||||||
}
|
}
|
||||||
//re-populates drop-down filters
|
//re-populates drop-down filters
|
||||||
if(this.refreshFilters){
|
if(this.refreshFilters){
|
||||||
|
@ -5212,7 +5211,7 @@ TableFilter.prototype = {
|
||||||
for(var i=this.refRow; i<this.nbRows; i++){
|
for(var i=this.refRow; i<this.nbRows; i++){
|
||||||
var isExludedRow = false;
|
var isExludedRow = false;
|
||||||
// checks if current row index appears in exclude array
|
// checks if current row index appears in exclude array
|
||||||
if(exclude && types.isObj(exclude)){
|
if(exclude && types.isArray(exclude)){
|
||||||
isExludedRow = array.has(exclude, i); //boolean
|
isExludedRow = array.has(exclude, i); //boolean
|
||||||
}
|
}
|
||||||
var cell = row[i].cells,
|
var cell = row[i].cells,
|
||||||
|
@ -5751,292 +5750,6 @@ TableFilter.prototype = {
|
||||||
}// for i
|
}// for i
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/*====================================================
|
|
||||||
- Calculates values of a column
|
|
||||||
- params are stored in 'colOperation' table's
|
|
||||||
attribute
|
|
||||||
- colOperation['id'] contains ids of elements
|
|
||||||
showing result (array)
|
|
||||||
- colOperation['col'] contains index of
|
|
||||||
columns (array)
|
|
||||||
- colOperation['operation'] contains operation
|
|
||||||
type (array, values: sum, mean)
|
|
||||||
- colOperation['write_method'] array defines
|
|
||||||
which method to use for displaying the
|
|
||||||
result (innerHTML, setValue, createTextNode).
|
|
||||||
Note that innerHTML is the default value.
|
|
||||||
- colOperation['tot_row_index'] defines in
|
|
||||||
which row results are displayed (integers array)
|
|
||||||
|
|
||||||
- changes made by Nuovella:
|
|
||||||
(1) optimized the routine (now it will only
|
|
||||||
process each column once),
|
|
||||||
(2) added calculations for the median, lower and
|
|
||||||
upper quartile.
|
|
||||||
=====================================================*/
|
|
||||||
SetColOperation: function(){
|
|
||||||
if(!this.isFirstLoad && !this.hasGrid){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.onBeforeOperation){
|
|
||||||
this.onBeforeOperation.call(null,this);
|
|
||||||
}
|
|
||||||
|
|
||||||
var colOperation = this.colOperation,
|
|
||||||
labelId = colOperation.id,
|
|
||||||
colIndex = colOperation.col,
|
|
||||||
operation = colOperation.operation,
|
|
||||||
outputType = colOperation.write_method,
|
|
||||||
totRowIndex = colOperation.tot_row_index,
|
|
||||||
excludeRow = colOperation.exclude_row,
|
|
||||||
decimalPrecision = colOperation.decimal_precision !== undefined ?
|
|
||||||
colOperation.decimal_precision : 2;
|
|
||||||
|
|
||||||
//nuovella: determine unique list of columns to operate on
|
|
||||||
var ucolIndex = [],
|
|
||||||
ucolMax = 0;
|
|
||||||
ucolIndex[ucolMax] = colIndex[0];
|
|
||||||
|
|
||||||
for(var ii=1; ii<colIndex.length; ii++){
|
|
||||||
var saved = 0;
|
|
||||||
//see if colIndex[ii] is already in the list of unique indexes
|
|
||||||
for(var jj=0; jj<=ucolMax; jj++){
|
|
||||||
if(ucolIndex[jj] === colIndex[ii]){
|
|
||||||
saved = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if not saved then, save the index;
|
|
||||||
if (saved === 0){
|
|
||||||
ucolMax++;
|
|
||||||
ucolIndex[ucolMax] = colIndex[ii];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(str.lower(typeof labelId)=='object' &&
|
|
||||||
str.lower(typeof colIndex)=='object' &&
|
|
||||||
str.lower(typeof operation)=='object'){
|
|
||||||
var row = this.tbl.rows,
|
|
||||||
colvalues = [];
|
|
||||||
|
|
||||||
for(var ucol=0; ucol<=ucolMax; ucol++){
|
|
||||||
//this retrieves col values
|
|
||||||
//use ucolIndex because we only want to pass through this loop
|
|
||||||
//once for each column get the values in this unique column
|
|
||||||
colvalues.push(
|
|
||||||
this.GetColValues(ucolIndex[ucol],true,excludeRow));
|
|
||||||
|
|
||||||
//next: calculate all operations for this column
|
|
||||||
var result,
|
|
||||||
nbvalues=0,
|
|
||||||
temp,
|
|
||||||
meanValue=0,
|
|
||||||
sumValue=0,
|
|
||||||
minValue=null,
|
|
||||||
maxValue=null,
|
|
||||||
q1Value=null,
|
|
||||||
medValue=null,
|
|
||||||
q3Value=null,
|
|
||||||
meanFlag=0,
|
|
||||||
sumFlag=0,
|
|
||||||
minFlag=0,
|
|
||||||
maxFlag=0,
|
|
||||||
q1Flag=0,
|
|
||||||
medFlag=0,
|
|
||||||
q3Flag=0,
|
|
||||||
theList=[],
|
|
||||||
opsThisCol=[],
|
|
||||||
decThisCol=[],
|
|
||||||
labThisCol=[],
|
|
||||||
oTypeThisCol=[],
|
|
||||||
mThisCol=-1;
|
|
||||||
|
|
||||||
for(var k=0; k<colIndex.length; k++){
|
|
||||||
if(colIndex[k] === ucolIndex[ucol]){
|
|
||||||
mThisCol++;
|
|
||||||
opsThisCol[mThisCol]=str.lower(operation[k]);
|
|
||||||
decThisCol[mThisCol]=decimalPrecision[k];
|
|
||||||
labThisCol[mThisCol]=labelId[k];
|
|
||||||
oTypeThisCol = outputType !== undefined &&
|
|
||||||
str.lower(typeof outputType)==='object' ?
|
|
||||||
outputType[k] : null;
|
|
||||||
|
|
||||||
switch(opsThisCol[mThisCol]){
|
|
||||||
case 'mean':
|
|
||||||
meanFlag=1;
|
|
||||||
break;
|
|
||||||
case 'sum':
|
|
||||||
sumFlag=1;
|
|
||||||
break;
|
|
||||||
case 'min':
|
|
||||||
minFlag=1;
|
|
||||||
break;
|
|
||||||
case 'max':
|
|
||||||
maxFlag=1;
|
|
||||||
break;
|
|
||||||
case 'median':
|
|
||||||
medFlag=1;
|
|
||||||
break;
|
|
||||||
case 'q1':
|
|
||||||
q1Flag=1;
|
|
||||||
break;
|
|
||||||
case 'q3':
|
|
||||||
q3Flag=1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var j=0; j<colvalues[ucol].length; j++){
|
|
||||||
//sort the list for calculation of median and quartiles
|
|
||||||
if((q1Flag==1)||(q3Flag==1) || (medFlag==1)){
|
|
||||||
if (j<colvalues[ucol].length -1){
|
|
||||||
for(k=j+1;k<colvalues[ucol].length; k++) {
|
|
||||||
if(eval(colvalues[ucol][k]) <
|
|
||||||
eval(colvalues[ucol][j])){
|
|
||||||
temp = colvalues[ucol][j];
|
|
||||||
colvalues[ucol][j] = colvalues[ucol][k];
|
|
||||||
colvalues[ucol][k] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var cvalue = parseFloat(colvalues[ucol][j]);
|
|
||||||
theList[j] = parseFloat(cvalue);
|
|
||||||
|
|
||||||
if(!isNaN(cvalue)){
|
|
||||||
nbvalues++;
|
|
||||||
if(sumFlag===1 || meanFlag===1){
|
|
||||||
sumValue += parseFloat( cvalue );
|
|
||||||
}
|
|
||||||
if(minFlag===1){
|
|
||||||
if(minValue===null){
|
|
||||||
minValue = parseFloat( cvalue );
|
|
||||||
} else{
|
|
||||||
minValue = parseFloat( cvalue ) < minValue ?
|
|
||||||
parseFloat( cvalue ): minValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(maxFlag===1){
|
|
||||||
if (maxValue===null){
|
|
||||||
maxValue = parseFloat( cvalue );
|
|
||||||
} else {
|
|
||||||
maxValue = parseFloat( cvalue ) > maxValue ?
|
|
||||||
parseFloat( cvalue ): maxValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//for j
|
|
||||||
if(meanFlag===1){
|
|
||||||
meanValue = sumValue/nbvalues;
|
|
||||||
}
|
|
||||||
if(medFlag===1){
|
|
||||||
var aux = 0;
|
|
||||||
if(nbvalues%2 === 1){
|
|
||||||
aux = Math.floor(nbvalues/2);
|
|
||||||
medValue = theList[aux];
|
|
||||||
} else{
|
|
||||||
medValue =
|
|
||||||
(theList[nbvalues/2] + theList[((nbvalues/2)-1)])/2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var posa;
|
|
||||||
if(q1Flag===1){
|
|
||||||
posa=0.0;
|
|
||||||
posa = Math.floor(nbvalues/4);
|
|
||||||
if(4*posa == nbvalues){
|
|
||||||
q1Value = (theList[posa-1] + theList[posa])/2;
|
|
||||||
} else {
|
|
||||||
q1Value = theList[posa];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (q3Flag===1){
|
|
||||||
posa=0.0;
|
|
||||||
var posb=0.0;
|
|
||||||
posa = Math.floor(nbvalues/4);
|
|
||||||
if (4*posa === nbvalues){
|
|
||||||
posb = 3*posa;
|
|
||||||
q3Value = (theList[posb] + theList[posb-1])/2;
|
|
||||||
} else {
|
|
||||||
q3Value = theList[nbvalues-posa-1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i=0; i<=mThisCol; i++){
|
|
||||||
switch( opsThisCol[i] ){
|
|
||||||
case 'mean':
|
|
||||||
result=meanValue;
|
|
||||||
break;
|
|
||||||
case 'sum':
|
|
||||||
result=sumValue;
|
|
||||||
break;
|
|
||||||
case 'min':
|
|
||||||
result=minValue;
|
|
||||||
break;
|
|
||||||
case 'max':
|
|
||||||
result=maxValue;
|
|
||||||
break;
|
|
||||||
case 'median':
|
|
||||||
result=medValue;
|
|
||||||
break;
|
|
||||||
case 'q1':
|
|
||||||
result=q1Value;
|
|
||||||
break;
|
|
||||||
case 'q3':
|
|
||||||
result=q3Value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var precision = decThisCol[i] && !isNaN( decThisCol[i] ) ?
|
|
||||||
decThisCol[i] : 2;
|
|
||||||
//if outputType is defined
|
|
||||||
if(oTypeThisCol && result){
|
|
||||||
result = result.toFixed( precision );
|
|
||||||
if(dom.id(labThisCol[i])){
|
|
||||||
switch( str.lower(oTypeThisCol) ){
|
|
||||||
case 'innerhtml':
|
|
||||||
if (isNaN(result) || !isFinite(result) ||
|
|
||||||
nbvalues===0){
|
|
||||||
dom.id(labThisCol[i]).innerHTML = '.';
|
|
||||||
} else{
|
|
||||||
dom.id(labThisCol[i]).innerHTML = result;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'setvalue':
|
|
||||||
dom.id( labThisCol[i] ).value = result;
|
|
||||||
break;
|
|
||||||
case 'createtextnode':
|
|
||||||
var oldnode = dom.id(labThisCol[i])
|
|
||||||
.firstChild;
|
|
||||||
var txtnode = dom.text(result);
|
|
||||||
dom.id(labThisCol[i])
|
|
||||||
.replaceChild(txtnode, oldnode);
|
|
||||||
break;
|
|
||||||
}//switch
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try{
|
|
||||||
if(isNaN(result) || !isFinite(result) ||
|
|
||||||
nbvalues===0){
|
|
||||||
dom.id(labThisCol[i]).innerHTML = '.';
|
|
||||||
} else {
|
|
||||||
dom.id(labThisCol[i]).innerHTML = result.toFixed(
|
|
||||||
precision);
|
|
||||||
}
|
|
||||||
} catch(e) {}//catch
|
|
||||||
}//else
|
|
||||||
}//for i
|
|
||||||
//eventual row(s) with result are always visible
|
|
||||||
if(totRowIndex && row[totRowIndex[ucol]]){
|
|
||||||
row[totRowIndex[ucol]].style.display = '';
|
|
||||||
}
|
|
||||||
}//for ucol
|
|
||||||
}//if typeof
|
|
||||||
|
|
||||||
if(this.onAfterOperation){
|
|
||||||
this.onAfterOperation.call(null,this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*====================================================
|
/*====================================================
|
||||||
- removes keyword highlighting
|
- removes keyword highlighting
|
||||||
|
|
300
src/modules/colOps.js
Normal file
300
src/modules/colOps.js
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
define(['../dom', '../string'], function (dom, str) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Column calculations
|
||||||
|
* @param {Object} tf TableFilter instance
|
||||||
|
*/
|
||||||
|
function ColOps(tf) {
|
||||||
|
var f = tf.fObj;
|
||||||
|
this.colOperation = f.col_operation;
|
||||||
|
|
||||||
|
this.tf = tf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates columns' values
|
||||||
|
* Configuration options are stored in 'colOperation' property
|
||||||
|
* - 'id' contains ids of elements showing result (array)
|
||||||
|
* - 'col' contains the columns' indexes (array)
|
||||||
|
* - 'operation' contains operation type (array, values: 'sum', 'mean',
|
||||||
|
* 'min', 'max', 'median', 'q1', 'q3')
|
||||||
|
* - 'write_method' array defines which method to use for displaying the
|
||||||
|
* result (innerHTML, setValue, createTextNode) - default: 'innerHTML'
|
||||||
|
* - 'tot_row_index' defines in which row results are displayed
|
||||||
|
* (integers array)
|
||||||
|
*
|
||||||
|
* - changes made by Nuovella:
|
||||||
|
* (1) optimized the routine (now it will only process each column once),
|
||||||
|
* (2) added calculations for the median, lower and upper quartile.
|
||||||
|
*/
|
||||||
|
ColOps.prototype.set = function() {
|
||||||
|
if(!this.tf.isFirstLoad && !this.tf.hasGrid){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.tf.onBeforeOperation){
|
||||||
|
this.tf.onBeforeOperation.call(null, this.tf);
|
||||||
|
}
|
||||||
|
|
||||||
|
var colOperation = this.colOperation,
|
||||||
|
labelId = colOperation.id,
|
||||||
|
colIndex = colOperation.col,
|
||||||
|
operation = colOperation.operation,
|
||||||
|
outputType = colOperation.write_method,
|
||||||
|
totRowIndex = colOperation.tot_row_index,
|
||||||
|
excludeRow = colOperation.exclude_row,
|
||||||
|
decimalPrecision = colOperation.decimal_precision !== undefined ?
|
||||||
|
colOperation.decimal_precision : 2;
|
||||||
|
|
||||||
|
//nuovella: determine unique list of columns to operate on
|
||||||
|
var ucolIndex = [],
|
||||||
|
ucolMax = 0;
|
||||||
|
ucolIndex[ucolMax] = colIndex[0];
|
||||||
|
|
||||||
|
for(var ii=1; ii<colIndex.length; ii++){
|
||||||
|
var saved = 0;
|
||||||
|
//see if colIndex[ii] is already in the list of unique indexes
|
||||||
|
for(var jj=0; jj<=ucolMax; jj++){
|
||||||
|
if(ucolIndex[jj] === colIndex[ii]){
|
||||||
|
saved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if not saved then, save the index;
|
||||||
|
if (saved === 0){
|
||||||
|
ucolMax++;
|
||||||
|
ucolIndex[ucolMax] = colIndex[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str.lower(typeof labelId)=='object' &&
|
||||||
|
str.lower(typeof colIndex)=='object' &&
|
||||||
|
str.lower(typeof operation)=='object'){
|
||||||
|
var row = this.tf.tbl.rows,
|
||||||
|
colvalues = [];
|
||||||
|
|
||||||
|
for(var ucol=0; ucol<=ucolMax; ucol++){
|
||||||
|
//this retrieves col values
|
||||||
|
//use ucolIndex because we only want to pass through this loop
|
||||||
|
//once for each column get the values in this unique column
|
||||||
|
colvalues.push(
|
||||||
|
this.tf.GetColValues(ucolIndex[ucol], true, excludeRow));
|
||||||
|
|
||||||
|
//next: calculate all operations for this column
|
||||||
|
var result,
|
||||||
|
nbvalues=0,
|
||||||
|
temp,
|
||||||
|
meanValue=0,
|
||||||
|
sumValue=0,
|
||||||
|
minValue=null,
|
||||||
|
maxValue=null,
|
||||||
|
q1Value=null,
|
||||||
|
medValue=null,
|
||||||
|
q3Value=null,
|
||||||
|
meanFlag=0,
|
||||||
|
sumFlag=0,
|
||||||
|
minFlag=0,
|
||||||
|
maxFlag=0,
|
||||||
|
q1Flag=0,
|
||||||
|
medFlag=0,
|
||||||
|
q3Flag=0,
|
||||||
|
theList=[],
|
||||||
|
opsThisCol=[],
|
||||||
|
decThisCol=[],
|
||||||
|
labThisCol=[],
|
||||||
|
oTypeThisCol=[],
|
||||||
|
mThisCol=-1;
|
||||||
|
|
||||||
|
for(var k=0; k<colIndex.length; k++){
|
||||||
|
if(colIndex[k] === ucolIndex[ucol]){
|
||||||
|
mThisCol++;
|
||||||
|
opsThisCol[mThisCol]=str.lower(operation[k]);
|
||||||
|
decThisCol[mThisCol]=decimalPrecision[k];
|
||||||
|
labThisCol[mThisCol]=labelId[k];
|
||||||
|
oTypeThisCol = outputType !== undefined &&
|
||||||
|
str.lower(typeof outputType)==='object' ?
|
||||||
|
outputType[k] : null;
|
||||||
|
|
||||||
|
switch(opsThisCol[mThisCol]){
|
||||||
|
case 'mean':
|
||||||
|
meanFlag=1;
|
||||||
|
break;
|
||||||
|
case 'sum':
|
||||||
|
sumFlag=1;
|
||||||
|
break;
|
||||||
|
case 'min':
|
||||||
|
minFlag=1;
|
||||||
|
break;
|
||||||
|
case 'max':
|
||||||
|
maxFlag=1;
|
||||||
|
break;
|
||||||
|
case 'median':
|
||||||
|
medFlag=1;
|
||||||
|
break;
|
||||||
|
case 'q1':
|
||||||
|
q1Flag=1;
|
||||||
|
break;
|
||||||
|
case 'q3':
|
||||||
|
q3Flag=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var j=0; j<colvalues[ucol].length; j++){
|
||||||
|
//sort the list for calculation of median and quartiles
|
||||||
|
if((q1Flag==1)|| (q3Flag==1) || (medFlag==1)){
|
||||||
|
if (j<colvalues[ucol].length -1){
|
||||||
|
for(k=j+1; k<colvalues[ucol].length; k++) {
|
||||||
|
if(eval(colvalues[ucol][k]) <
|
||||||
|
eval(colvalues[ucol][j])){
|
||||||
|
temp = colvalues[ucol][j];
|
||||||
|
colvalues[ucol][j] = colvalues[ucol][k];
|
||||||
|
colvalues[ucol][k] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cvalue = parseFloat(colvalues[ucol][j]);
|
||||||
|
theList[j] = parseFloat(cvalue);
|
||||||
|
|
||||||
|
if(!isNaN(cvalue)){
|
||||||
|
nbvalues++;
|
||||||
|
if(sumFlag===1 || meanFlag===1){
|
||||||
|
sumValue += parseFloat( cvalue );
|
||||||
|
}
|
||||||
|
if(minFlag===1){
|
||||||
|
if(minValue===null){
|
||||||
|
minValue = parseFloat( cvalue );
|
||||||
|
} else{
|
||||||
|
minValue = parseFloat( cvalue ) < minValue ?
|
||||||
|
parseFloat( cvalue ): minValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(maxFlag===1){
|
||||||
|
if (maxValue===null){
|
||||||
|
maxValue = parseFloat( cvalue );
|
||||||
|
} else {
|
||||||
|
maxValue = parseFloat( cvalue ) > maxValue ?
|
||||||
|
parseFloat( cvalue ): maxValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//for j
|
||||||
|
if(meanFlag===1){
|
||||||
|
meanValue = sumValue/nbvalues;
|
||||||
|
}
|
||||||
|
if(medFlag===1){
|
||||||
|
var aux = 0;
|
||||||
|
if(nbvalues%2 === 1){
|
||||||
|
aux = Math.floor(nbvalues/2);
|
||||||
|
medValue = theList[aux];
|
||||||
|
} else{
|
||||||
|
medValue =
|
||||||
|
(theList[nbvalues/2] + theList[((nbvalues/2)-1)])/2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var posa;
|
||||||
|
if(q1Flag===1){
|
||||||
|
posa=0.0;
|
||||||
|
posa = Math.floor(nbvalues/4);
|
||||||
|
if(4*posa == nbvalues){
|
||||||
|
q1Value = (theList[posa-1] + theList[posa])/2;
|
||||||
|
} else {
|
||||||
|
q1Value = theList[posa];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (q3Flag===1){
|
||||||
|
posa=0.0;
|
||||||
|
var posb=0.0;
|
||||||
|
posa = Math.floor(nbvalues/4);
|
||||||
|
if (4*posa === nbvalues){
|
||||||
|
posb = 3*posa;
|
||||||
|
q3Value = (theList[posb] + theList[posb-1])/2;
|
||||||
|
} else {
|
||||||
|
q3Value = theList[nbvalues-posa-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i=0; i<=mThisCol; i++){
|
||||||
|
switch( opsThisCol[i] ){
|
||||||
|
case 'mean':
|
||||||
|
result=meanValue;
|
||||||
|
break;
|
||||||
|
case 'sum':
|
||||||
|
result=sumValue;
|
||||||
|
break;
|
||||||
|
case 'min':
|
||||||
|
result=minValue;
|
||||||
|
break;
|
||||||
|
case 'max':
|
||||||
|
result=maxValue;
|
||||||
|
break;
|
||||||
|
case 'median':
|
||||||
|
result=medValue;
|
||||||
|
break;
|
||||||
|
case 'q1':
|
||||||
|
result=q1Value;
|
||||||
|
break;
|
||||||
|
case 'q3':
|
||||||
|
result=q3Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var precision = !isNaN(decThisCol[i]) ? decThisCol[i] : 2;
|
||||||
|
|
||||||
|
//if outputType is defined
|
||||||
|
if(oTypeThisCol && result){
|
||||||
|
result = result.toFixed( precision );
|
||||||
|
|
||||||
|
if(dom.id(labThisCol[i])){
|
||||||
|
switch( str.lower(oTypeThisCol) ){
|
||||||
|
case 'innerhtml':
|
||||||
|
if (isNaN(result) || !isFinite(result) ||
|
||||||
|
nbvalues===0){
|
||||||
|
dom.id(labThisCol[i]).innerHTML = '.';
|
||||||
|
} else{
|
||||||
|
dom.id(labThisCol[i]).innerHTML = result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'setvalue':
|
||||||
|
dom.id( labThisCol[i] ).value = result;
|
||||||
|
break;
|
||||||
|
case 'createtextnode':
|
||||||
|
var oldnode = dom.id(labThisCol[i])
|
||||||
|
.firstChild;
|
||||||
|
var txtnode = dom.text(result);
|
||||||
|
dom.id(labThisCol[i])
|
||||||
|
.replaceChild(txtnode, oldnode);
|
||||||
|
break;
|
||||||
|
}//switch
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try{
|
||||||
|
if(isNaN(result) || !isFinite(result) ||
|
||||||
|
nbvalues===0){
|
||||||
|
dom.id(labThisCol[i]).innerHTML = '.';
|
||||||
|
} else {
|
||||||
|
dom.id(labThisCol[i]).innerHTML =
|
||||||
|
result.toFixed(precision);
|
||||||
|
}
|
||||||
|
} catch(e) {}//catch
|
||||||
|
}//else
|
||||||
|
}//for i
|
||||||
|
|
||||||
|
// row(s) with result are always visible
|
||||||
|
var totRow = totRowIndex && totRowIndex[ucol] ?
|
||||||
|
row[totRowIndex[ucol]] : null;
|
||||||
|
if(totRow){
|
||||||
|
totRow.style.display = '';
|
||||||
|
}
|
||||||
|
}//for ucol
|
||||||
|
}//if typeof
|
||||||
|
|
||||||
|
if(this.tf.onAfterOperation){
|
||||||
|
this.tf.onAfterOperation.call(null, this.tf);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return ColOps;
|
||||||
|
});
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>TableFilter basic test</title>
|
<title>TableFilter alternate rows tests</title>
|
||||||
<link rel="stylesheet" href="libs/qunit/qunit.css">
|
<link rel="stylesheet" href="libs/qunit/qunit.css">
|
||||||
<link rel="stylesheet" href="../dist/filtergrid.css">
|
<link rel="stylesheet" href="../dist/filtergrid.css">
|
||||||
<script src="libs/qunit/qunit.js"></script>
|
<script src="libs/qunit/qunit.js"></script>
|
||||||
|
|
|
@ -10,8 +10,8 @@ requirejs(['test-config', '../src/core'], function(config, TableFilter){
|
||||||
});
|
});
|
||||||
tf.init();
|
tf.init();
|
||||||
|
|
||||||
module("Sanity checks");
|
module('Sanity checks');
|
||||||
test("AlternateRows component", function() {
|
test('AlternateRows component', function() {
|
||||||
deepEqual(tf.Cpt.alternateRows instanceof AlternateRows, true, 'AlternateRows constructor');
|
deepEqual(tf.Cpt.alternateRows instanceof AlternateRows, true, 'AlternateRows constructor');
|
||||||
notEqual(tf.Cpt.alternateRows, null, 'AlternateRows instanciated');
|
notEqual(tf.Cpt.alternateRows, null, 'AlternateRows instanciated');
|
||||||
});
|
});
|
||||||
|
|
91
test/test-col-ops.html
Normal file
91
test/test-col-ops.html
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>TableFilter column operations tests</title>
|
||||||
|
<link rel="stylesheet" href="libs/qunit/qunit.css">
|
||||||
|
<link rel="stylesheet" href="../dist/filtergrid.css">
|
||||||
|
<script src="libs/qunit/qunit.js"></script>
|
||||||
|
<script>
|
||||||
|
// Defer Qunit so RequireJS can work its magic and resolve all modules.
|
||||||
|
QUnit.config.autostart = false;
|
||||||
|
QUnit.config.autoload = false;
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table id="demo" cellpadding="0" cellspacing="0">
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td>Tot:</td>
|
||||||
|
<td></td>
|
||||||
|
<td id="sum1"></td>
|
||||||
|
<td id="sum2"></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>From</th>
|
||||||
|
<th>Destination</th>
|
||||||
|
<th>Road Distance (km)</th>
|
||||||
|
<th>By Air (hrs)</th>
|
||||||
|
<th width="15%">By Rail (hrs)</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Sydney</strong></td>
|
||||||
|
<td>Adelaide</td>
|
||||||
|
<td>1412</td>
|
||||||
|
<td>1.4</td>
|
||||||
|
<td>25.3</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Sydney</strong></td>
|
||||||
|
<td>Brisbane</td>
|
||||||
|
<td>982</td>
|
||||||
|
<td>1.5</td>
|
||||||
|
<td>16</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Sydney</strong></td>
|
||||||
|
<td>Canberra</td>
|
||||||
|
<td>286</td>
|
||||||
|
<td>.6</td>
|
||||||
|
<td>4.3</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Sydney</strong></td>
|
||||||
|
<td>Melbourne</td>
|
||||||
|
<td>872</td>
|
||||||
|
<td>1.1</td>
|
||||||
|
<td>10.5</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Adelaide</strong></td>
|
||||||
|
<td>Perth</td>
|
||||||
|
<td>2781</td>
|
||||||
|
<td>3.1</td>
|
||||||
|
<td>38</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Adelaide</strong></td>
|
||||||
|
<td>Alice Springs</td>
|
||||||
|
<td>1533</td>
|
||||||
|
<td>2</td>
|
||||||
|
<td>20.25</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Adelaide</strong></td>
|
||||||
|
<td>Brisbane</td>
|
||||||
|
<td>2045</td>
|
||||||
|
<td>2.15</td>
|
||||||
|
<td>40</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<script data-main="test-col-ops" src="../libs/requirejs/require.js"></script>
|
||||||
|
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<div id="qunit-fixture"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
33
test/test-col-ops.js
Normal file
33
test/test-col-ops.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
requirejs(['test-config', '../src/core'], function(config, TableFilter){
|
||||||
|
|
||||||
|
QUnit.start();
|
||||||
|
|
||||||
|
var dom = require('dom'),
|
||||||
|
ColOps = require('modules/colOps');
|
||||||
|
|
||||||
|
var table = document.getElementById('demo');
|
||||||
|
var totRowIndex = table.getElementsByTagName('tr').length;
|
||||||
|
|
||||||
|
var tf = new TableFilter('demo', {
|
||||||
|
rows_always_visible: [totRowIndex],
|
||||||
|
col_operation: {
|
||||||
|
id: ['sum1', 'sum2'],
|
||||||
|
col: [2, 3],
|
||||||
|
operation: ['sum', 'mean'],
|
||||||
|
write_method: ['innerhtml', 'innerhtml'],
|
||||||
|
exclude_row: [totRowIndex],
|
||||||
|
decimal_precision: [0, 2],
|
||||||
|
tot_row_index: [totRowIndex, totRowIndex]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tf.init();
|
||||||
|
|
||||||
|
module('Sanity checks');
|
||||||
|
test('Column Operations component', function() {
|
||||||
|
deepEqual(tf.Cpt.colOps instanceof ColOps, true, 'ColOps constructor');
|
||||||
|
notEqual(tf.Cpt.colOps, null, 'ColOps instanciated');
|
||||||
|
equal(dom.id('sum1').innerHTML, 9911, 'Sum result');
|
||||||
|
equal(dom.id('sum2').innerHTML, 1.69, 'Mean result');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -10,8 +10,8 @@ requirejs(['test-config', '../src/core'], function(config, TableFilter){
|
||||||
});
|
});
|
||||||
tf.init();
|
tf.init();
|
||||||
|
|
||||||
module("Sanity checks");
|
module('Sanity checks');
|
||||||
test("Loader component", function() {
|
test('Loader component', function() {
|
||||||
deepEqual(tf.Cpt.loader instanceof Loader, true, 'Loader constructor');
|
deepEqual(tf.Cpt.loader instanceof Loader, true, 'Loader constructor');
|
||||||
notEqual(tf.Cpt.loader, null, 'Loader instanciated');
|
notEqual(tf.Cpt.loader, null, 'Loader instanciated');
|
||||||
notEqual(dom.id(tf.prfxLoader+tf.id), null, 'Loader DOM container');
|
notEqual(dom.id(tf.prfxLoader+tf.id), null, 'Loader DOM container');
|
||||||
|
|
Loading…
Reference in a new issue