/**
* jQuery grider
* Versión 0.7
* @author: Boris Barroso Camberos
* @email: boriscyber@gmail.com
* @license MIT
* http://www.opensource.org/licenses/mit-license.php
*/
(function($) {
$.fn.extend({
grider: function(config) {
return this.each(function() {
new $.Grider(this, config);
});
}
});
/**
* Transforms a grid that contains data, and allows to do calculations con form elements
* in a simple way. Example:
*
*
*
Price
*
Quantity
*
Discount
*
Subtotal
*
*
*
*
*
*
*
*
*
* And then you execute $('#grid').grider();
*
* @attr col: Defines the col name, it is a unique identifier for that col in the table
*
* @attr summary: Defines the type of calculation it will be done on the column,
* operations that can be done are "sum", "avg", "max", "min" and "count"
*
* @attr formula: Calculates the formula with the columns you defined, right now it does simple calculations,
* the formula is evaluated eval(formula), to calculate
*
* Configurations for the config variable
* @param boolean config['initCalc'] Defines if formula should make calculations when it initializes, in case that you already did calculations server side
*
* @param boolean config['addRow'] Defines if the add row link will appear
* @param string config['addRowText'] Text that will display to add rows
* @param boolean config['delRow'] Defines if it will appear the delete link to delete a row
* @param string config['delRowText'] Text that will be displayed for deleting a row
* @param boolean config['countRow'] Indicates if it will do count the rows, necessary for adding and deleting rows
* @param integer config['countRowCol'] Defines the column in which the count will be displayed, defauls = 0
* @param boolean config['countRowAdd'] Indicates if it will be able to add Row
* @param boolean config['rails'] accepts the use of rails nested attributes
*/
$.Grider = function(table, config) {
/**
* Defaults
*/
var defaults = Grider.defaults;
var config;
if(config) {
for(var k in defaults) {
if(typeof(defaults[k]) == "boolean" && typeof(config[k]) == "boolean" ) {
config[k] = config[k];
}else{
config[k] = config[k] || defaults[k];
}
}
}else{
config = defaults;
}
var cols = {};
// Identifies if there is a summary column
var summaryRow = false;
var formulaSet = false; // Indicates if the formula was added
config = config || {};
setGrider(table);
/**
* This function prepares all to set the table
* @param DOM t Table
*/
function setGrider(t) {
$(table).find('tr:first').addClass('noedit');
// Allow to count rows
if(config['countRow']) {
if(config['countRowAdd']) {
var className = $(table).find("th:first").attr("class");
className = className != "" ? ' class="' + className + '"': "";
$(table).find('tr.noedit:first').prepend('
'+ config.countRowText +'
');
$(table).find('tr:not(.noedit)').each(function(index, elem){
var ind = index+1;
$(elem).prepend('
'+ind+'
');
});
}
}
var l = $(table).find("tr:not(.noedit):first td").length;
for(var i = 0; i < l; i++) {
setColumn(t.rows[0].cells[i], i);
}
// Types of columns
setColType();
// Setting formulas and summaries
for(var i = 0; i < l; i++) {
setFormula(t.rows[0].cells[i]);
setSummary(t.rows[0].cells[i]);
}
// Calculation of formulas for the first Time
if(formulaSet && config.initCalc) {
var rows = $(table).find('tr:not(.noedit)');
rows.each(function(index, elem) {
var pos = index + 1;
for(var k in cols) {
if(cols[k].formula) {
calculateFormula(cols[k].name, pos);
}
}
});
}
for(var k in cols){
if(cols[k].summary) {
calculateSummary(k);
}
};
// Allow to add rows
if(config['addRow']) {
$(table).append(config['addRowText']);
$(table).find("caption a").click(function() {
addRow();
});
}
// Allow to delete rows
if(config['delRow']) {
$(table).find('tr:not(.noedit)').each(function(index,elem){
$(elem).append(config['delRowText']);
});
$(table).find('a.delete').live("click", function(){
delRow(this);
return true;
});
}
// Add events to the elements in the table, elements that are related to a summary or formula
setEvents();
// Allows to add rows using tab when cursor on a delete link
if(config.addRowWithTab)
addRowWithTab();
}
/**
* Allows to add a new row, the new row is added at the endof the editable rows
*/
function addRowWithTab() {
$(table).find("tr:not(.noedit):last a.delete").live("keydown",function(e) {
if(e.keyCode == 9) {
addRow();
}
});
}
/**
* Determines the type of element that is contained in the TD
*/
function setColType() {
var row = $(table).find('tr:not(.noedit):first')[0]; // Finds the first row tha is editable
for(var k in cols) {
var cell = $(row).find('td:eq(' + cols[k].pos + ')')[0];
var node = $(cell).find('select')[0] || $(cell).find('input:not(:submit)')[0] || $(cell).find('select')[0];
try {
type = node.nodeName.toLowerCase();
}catch(e){ type = false }
if(type) {
switch(type) {
case 'input':
cols[k]['type'] = 'input:'+ node.type;
break;
case 'select':
cols[k]['type'] = 'select';
break;
case 'textarea':
cols[k]['type'] = 'textarea';
break;
default:
cols[k]['type'] = 'input:text';
break;
}
}else{
// Allows to use jQuery selectors
cols[k]['type'] = '';
}
}
}
/**
* Allows to define columns with its names
* @param DOM cell TD
* @param integer pos Column number, starts on 0
*/
function setColumn(cell, pos) {
var col = $(cell).attr('col');
if(col) {
cols[col] = {
pos: pos,
name: col
};
}
}
/**
* Alows columns to calculate summaries, like avg (average), sum, max, count
* @param DOM cell
*/
function setSummary(cell) {
var summary = $(cell).attr('summary');
var summaryCell = false;
var col = $(cell).attr('col');
if(summary == 'sum' || summary == 'avg' || summary == 'max' || summary == 'min' || summary == 'count') {
cols[col]['summary'] = summary;
summaryCell = true;
}
// Add the summary row
if(!summaryRow && summaryCell) {
var html = '