TableKit
Introduction
TableKit is a collection of HTML table enhancements using the Prototype framework. TableKit currently implements row striping, column sorting, column resizing and cell editing using Ajax.
Demo: Sortable/Resizable/Editable
Click the table header cells to sort the column, resize the column by dragging the right border of a header cell, click a cell in the table body to edit the value.
Urgency | Date | Time | Title | Status | Requested By | Cost | Size |
---|---|---|---|---|---|---|---|
Urgency | Date | Time | Title | Status | Requested By | Cost | Size |
5 | 24/10/2005 10:47:41 AM | 10:47:41 AM | Keyboard is Broken | In Progress | Tom | $200.00 | 30KB |
5 | 24/10/2005 10:49:41 AM | 10:49:41 AM | Keyboard is Broken | In Progress | Tom | $200.00 | 30 KB |
3 | 24/10/2005 10:49:41 PM | 10:49:41 PM | Windows is crashing | New | Bill | $300.00 | 30MB |
4 | 17/02/2006 | 12:43:16 PM | Help, I'm on fire! | New | John | $250.00 | 30KB |
3 | 06/07/2006xxx | 03:04:34 PM | The ring came off my pudding can | Assigned | Tom | $200.50 | 30GB |
2 | 06/07/2006 | 15:06:10 | Should I open this email? | Assigned | Tom | $50.35 | 30TB |
1 | 06/07/2006 | 04:12:16 PM | I can't print | Assigned | Bill | $2005.30 | 30KB |
2 | 31/12/2006 | 09:35:47 AM | The internet is broken | Assigned | Jill | $600.00 | 32KB |
3 | 17/07/2006 | 04:21:24 PM | Blank Screen | Assigned | Xavier | $100.30 | 10GB |
4 | 24/10/2005 01:09:00 AM | 01:09:00 AM | My cup holder is not working | Closed | Mark | $100.40 | 20 MB |
5 | 24/10/2005 12:47:41 AM | 12:47:41 AM | Keyboard is Broken | In Progress | Tom | $200.00 | 30KB |
5 | 24/10/2005 01:49:41 PM | 01:49:41 PM | Keyboard is Broken | Closed | Tom | $200.00 | 30 KB |
3 | 24/10/2005 12:49:41 PM | 12:49:41 PM | Windows is crashing | New | Bill | $300.00 | 30MB |
4 | 17/02/2006 | 12:43:16 PM | Help, I'm on fire! | New | John | $250.00 | 30KB |
3 | 06/07/2006 | 03:04:34 PM | The ring came off my pudding can | Assigned | Tom | $200.50 | 30GB |
2 | 06/07/2006 | 15:06:10 | Should I open this email? | Closed | Tom | $50.35 | 30TB |
1 | 06/07/2006 | 04:12:16 PM | I can't print | Assigned | Bill | $2005.30 | 30KB |
2 | 31/12/2006 | 09:35:47 AM | The internet is broken | Assigned | Jill | $600.00 | 32KB |
3 | 17/07/2006 | 04:21:24 PM | Blank Screen | Assigned | Xavier | $100.30 | 10GB |
4 | 26/07/2006 | 03:09:00 PM | My cup holder is not working | In Progress | Mark | $100.40 | 20 MB |
Documentation
TableKit Basics
Installation
Reference the script in your HTML: Prototype and tablekit.js are required of course; Fastinit is optional.
<script type="text/javascript" src="scriptaculous/lib/prototype.js"></script>
<script type="text/javascript" src="fastinit.js"></script>
<script type="text/javascript" src="tablekit.js"></script>
Simple Usage
The easiest way to use TableKit is reference the script in your HTML and give you tables appropriate classes:
<table class="sortable resizable editable">
- 'sortable' to activate column sorting (and row striping)
- 'resizable' to activate column resizing
- 'editable' to activate cell editing. You must also set the Ajax URI for cell editing, for example:
TableKit.options.editAjaxURI = '/echo/';
When a table is initialised, if it doesn't have an id
attribute one will be assigned in the form tablekit-table-nn
where nn is an incremented number
Options
These are the options used globally for all tables unless otherwise speified.
Option : Default
autoLoad : true
: If you don't want the script to load automatically set this to falsestripe : true
: enables row stripingsortable : true
: enables column sortingresizable : true
: enables column resizingeditable : true
: enables cell editingrowEvenClass : 'roweven'
: css class used for row stripingrowOddClass : 'rowodd'
: css class used for row stripingsortableSelector : ['table.sortable']
: selector for finding tables to make sortablecolumnClass : 'sortcol'
: css class for each sortable column header celldescendingClass : 'sortdesc'
: css class for sortable column header cell when sorted descendingascendingClass : 'sortasc'
: css class for sortable column header cell when sorted ascendingnoSortClass : 'nosort'
: css class for sortable column header cell to disable sorting for that columndefaultSortDirection : 1
: initial sort direction for all columns, 1 means ascending, -1 means desceding.sortFirstAscendingClass : 'sortfirstasc'
: css class for sortable column header cell to trigger initial ascendant sorting for that columnsortFirstDecendingClass : 'sortfirstdesc'
: css class for sortable column header cell to trigger initial decendant sorting for that columnresizableSelector : ['table.resizable']
: selector for finding tables to make resizableminWidth : 10
: minimum width in pixels of a resizable columnshowHandle : true
: shows the resize handle, with this set to false cell no handle is visible and resize is immediate with mousemoveresizeOnHandleClass : 'resize-handle-active'
: css class applied to header cell when the mouse pointer is in the resize handle zone (right hand cell border)editableSelector : ['table.editable']
: selector for finding tables to make editableformClassName : 'editable-cell-form'
: css class given to the form when a cell is made editablenoEditClass : 'noedit'
: css class used on a header cell to indicate column is not editable, or on an individual body cell to indicate that cell is not editable.editAjaxURI : '/'
: form data is POSTed to this URI from the editable cell formseditAjaxOptions : {}
: options for the Prototype Ajax.Updater used in editable cells
Options can be modified directly, for example
TableKit.options.rowEvenClass = 'even';
If you supply options using the initialisation methods below, those options will be used for that table only, using the table's id
attribute. This way you can specify different options for different tables.
Usage Styles
TableKit supports several usage styles when initialising. You can use table class names as described above or one of the following options.
By Selector
You can change the selector used for automatic initialisation
TableKit.options.sortableSelector = ['table.data-table'];
By Manual Initialisation
You can initialise a specific table using the init()
function
TableKit.Sortable.init(table, {options});
By Object Creation
You can create a TableKit
option.
var table = new TableKit(table, {options});
A TableKit object has only a few methods that only need to be called if you need to, otherwise all the functionality works automatically
table.sort(column, order) // sort a particular column
table.resizeColumn(column, w) // resize a particular column
table.editCell(row, column) // edit a specific cell
TableKit.Sortable
Activation
If the table has a thead then the last row of the thead (the one closest to the body) will be used as the header row to add the sorting 'onclick' event listeners - one to each header cell. If there is no thead the first table row will be used. Only rows in the table body are sorted, all other cells (in the thead or tfoot) are ignored.
Sorting Types
The table will attempt to automatically detect the sorting type for your columns (text, number, date...etc) by analysing the first cell. If you don't want it to do that you can specify the exact sorting by adding a class to your header cell for example class="number". Available ones are:
"date-iso" // e.g. 2005-03-26T19:51:34Z
"date" // e.g. Mon, 18 Dec 1995 17:28:35 GMT
"date-au" // e.g. 25/12/2006 05:30:00 PM
"date-eu" // e.g. 25-12-2006
"date-us" // e.g. 12/25/2006 05:30:00 PM
"time" // e.g. 05:30:00 PM
"currency" // e.g. $55.00 - detects: $ £ ¥ € ¤
"datasize" // e.g. 30MB - detects: B, KB, MB, GB, TB
"number"
"casesensitivetext"
"text"
A special notes about dates: By default the script's automatic sort type detection will favour Australian dates, dd/mm/yyyy. If you want it to favour US dates, mm/dd/yyyy, then either add the class "date-us" to the header cell on the date column or read Advanced Sorting Types below.
CSS Hooks
No Sort columns
If you don't want a column to be sorted then give the header cell a class of "nosort".
Sort First Column
If you want a column to be sorted when the page loads then add a class to the header cell of that column; "sortfirstasc" for ascending and "sortfirstdesc" for descending.
Other CSS Hooks
Header cells will be given the class "sortcol", and when sorted they will be given the class "sortasc" for ascending and "sortdesc" for descending.
API
You can initialise a specific table by using:
TableKit.Sortable.init(table, {options});
where table is a table element reference or ID and options are options matching the TableKit global options, you wish to apply to this table only.
To sort a specific table column (for example if you want to use an external control) you can call the sort function manually.
TableKit.Sortable.sort(table, index, order);
- table = null or a table reference or a table ID, if table is null then index must equal a cell element reference or a cell ID
- index = a number or cell element reference or a cell ID : if index is a number then table cannot be null
- order = sort direction (optional) 1 (ascending) or -1 (descending)
Advanced Sorting Types
a collection of TableKit.Sortable.Type
objects handles data type detection and sorting. Each one has a name. The sort function will attempt to match a sort type to a column by first reading the column header cell's id
, then all the class names and finally will try automatic detection.
Automatic Detection
The TableKit.Sortable.detectors
property is an array of sort type names. Each TableKit.Sortable.Type
is queried to see if the first column cell's contents matches the sort type. The default list is:
TableKit.Sortable.detectors = $w('date-iso date date-eu date-au time currency datasize number casesensitivetext text');
You can change it according to your requirements.
Custom Sorting Types
You can create a custom sort type by creating one or more TableKit.Sortable.Type
objects and adding them using the TableKit.Sortable.addSortType()
function. That function can take any number of objects as arguments. For example:
TableKit.Sortable.addSortType(
new TableKit.Sortable.Type('type1', {options}),
new TableKit.Sortable.Type('type2', {options})
The first argument of a new type object is its name, the second is an array of options that control how the sort type detects and compares. Here's an example:
TableKit.Sortable.addSortType(
new TableKit.Sortable.Type('number', {
pattern : /^[-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?/,
normal : function(v) {
// This will grab the first thing that looks like a number from a string, so you can use it to order a column of various srings containing numbers.
v = parseFloat(v.replace(/^.*?([-+]?[\d]*\.?[\d]+(?:[eE][-+]?[\d]+)?).*$/,"$1"));
return isNaN(v) ? 0 : v;
}
})
);
pattern
: a regular expression to use in astring.test()
operation for automatic data type detectionnormal
: a function used to normalise values for comparison. Before comparing two cells both cells' values are put through this function
If the default comparison function is not adequate you can specifiy your own by adding compare: function(a,b){}
to the options. This function that takes 2 arguments, the 2 values being compared, and returns either 1, 0 or -1. 1 if a is greater than b, -1 if b is greater than a and 0 if they are equal. The default comparison function looks like this:
TableKit.Sortable.Type.prototype.compare = function(a,b){
return TableKit.Sortable.Type.compare(this.normal(a), this.normal(b));
}
TableKit.Sortable.Type.compare = function(a,b) {
return a < b ? -1 : a == b ? 0 : 1;
}
Here's an example of custom sort type usage from the demo. I've added a sort type called 'status' to sort the Status column appropriately. I've given the header cell of that column an id
of 'status' so that it will use my custom sort type.
TableKit.Sortable.addSortType(
new TableKit.Sortable.Type('status', {
pattern : /^[New|Assigned|In Progress|Closed]$/,
normal : function(v) {
switch(v) {
case 'New':
return 0;
break;
case 'Assigned':
return 1;
break;
case 'In Progress':
return 2;
break;
case 'Closed':
return 3;
break;
default:
return 4;
}
}
}
));
TableKit.Rows
When sorting a table, body rows will also be given the alternating classes "rowodd" and "roweven" on load and after each sort as an added bonus.API
If you just want to stripe a table you can use:
TableKit.Rows.stripe(table)
where table is a table element reference or ID
TableKit.Resizable
Activation
The table header cells are used to trigger column resizing. When the mouse pointer moves close to the right edge of the cell, the cell is given the class 'resize-handle-active' and a 'mousedown' event listener is enabled. If the mousedown event occurs a drag handle is created and the user can drag it left and right. When the mouse button is released the column's width is adjusted accordingly.
Because we are resizing a HTML table the columns may not resize exactly as intended as opposed to a proper data grid. Browsers tend to recalibrate all table columns according to the maximum width of the table, which by default is 100% and the contents of the cells.
CSS Hooks
When appripriate the cell is given the class 'resize-handle-active', which can be used to set the cursor style (as it is in the demo). The resize handle itself is a div
element with a class of 'resize-handle'. This can be used to style the resize handle.
API
You can initialise a specific table by using:
TableKit.Resizable.init(table, {options});
where table is a table element reference or ID and options are options matching the TableKit global options, you wish to apply to this table only.
To resize a specific table column (for example if you want to use an external control) you can call the resize function manually.
TableKit.Resizable.resize(table, index, w);
- table = null or a table reference or a table ID, if table is null then index must equal a cell element reference or a cell ID
- index = a number or cell element reference or a cell ID : if index is a number then table cannot be null
- w = width (number of pixels to resize to)
TableKit.Editable
Activation
Once the table is initialised, a mouse click on a table body cell, will activate a HTML form allowing the user to edit the new value via a Prototype Ajax.Updater.
API
You can initialise a specific table by using:
TableKit.Editable.init(table, {options});
where table is a table element reference or ID and options are options matching the TableKit global options, you wish to apply to this table only.
To edit a specific table cell (for example if you want to use an external control) you can call the edit function manually.
TableKit.Editable.editCell(table, index, cindex);
- table = null or a table reference or a table ID, if table is null then index must equal a cell element reference or a cell ID
- index = a number or element reference or ID: if index is a number, then it must be the row index number, table cannot be null and cindex must be supplied too. If it is not a number then it is treated as the cell element reference.
- cindex = a number (the cell index)
Cell Editors
A collection of TableKit.Editable.CellEditor
objects handles cell editing. Each CellEditor has a name and this name is matched to the id
or class name of the column header cell to find the appropriate editor, otherwise a standard text input is used.
Adding cell editors is easy:
TableKit.Editable.textInput(name,attributes); // creates a standard text input (the default)
TableKit.Editable.multiLineInput(name,attributes); // creates a text area
TableKit.Editable.selectInput(name,attributes,selectOptions); // creates a select element
name
: the name to associate this editor with a table columnattributes
: HTML attributes to apply to the input elementselectOptions
: an array of options for the select element, e.g.[['text', 'value'],['option 1', '1'],['option 2', '2']]
The demo is setup this way:
TableKit.Editable.selectInput('urgency', {}, [
['1','1'],
['2','2'],
['3','3'],
['4','4'],
['5','5']
]);
TableKit.Editable.multiLineInput('title');
The demo has a select editor for the Urgency column and a textarea for the Title column.
Updating the Cell
Each cell editor uses a Prototype Ajax Updater. The POST body is generated from the following:
'&row=n&cell=n&id=id&field=field&value=xxxxxx'
&row=n
: The row index of the edited cell&cell=n
: The cell index of the edited cell&id=id
: Theid
attribute of the row, it may be useful to set this to the record ID you are editing&field=field
: Theid
attribute of the header cell of the column of the edited cell, it may be useful to set this to the field name you are editing&value=xxxxxx
: The rest of the POST body is the serialised form. The default name of the field is 'value'.
This information is POSTed to the URI specified in TableKit.options.editAjaxURI
by default. If you initialise a table with options you can specify a different URI for each table. You can also specify a different URI in custom cell editors (see below)
Similarly the Ajax Updater uses the options from TableKit.options.editAjaxOptions
Custom Cell Editors
To make your own cell editor simply make a new TableKit.Editable.CellEditor
object and add it to the collection using the TableKit.Editable.addCellEditor
function. For example:
TableKit.Editable.addCellEditor(
new TableKit.Editable.CellEditor('yourname', {
element : 'select',
attributes : {name : 'favourite_food', title : 'Please select your favourite food from the list'},
selectOptions : [['Cheese','Cheese'],['Llama','Llama'],['Staot','Staot'],['Halibut','Halibut']]
})
);
The available options are:
Option : Default
element : 'input'
: the HTML element used for the formattributes : {name : 'value', type : 'text'}
: the attributes to apply to the elementselectOptions : []
: if the element is aselect
, these are the optionsshowSubmit : true
: show a sumit buttonsubmitText : 'OK'
: the text on the submit buttonshowCancel : true
: show a cancel linkcancelText : 'Cancel'
: the text of the cancel linkajaxURI : null
: the URI the form body is POSTed to for this editor onlyajaxOptions : null
: the options for the Prototype Ajax Updater object for this editor only
Custom Cell Editor Objects
Of course you can write your own cell editor objects from scratch. A cell editor object is really just an object with one property name
and one method edit
customEditorObject = function(name) {
this.name = name;
}
customEditorObject.prototype.edit = function(cell){ //do something }
The edit
function is called when a body cell is clicked on. The function should handle setting up the form and handling the submit event. It can be added to the collection using the standard TableKit.Editable.addCellEditor
function