w2grid = function(options) {

        // public properties
        this.name         = null;
        this.box          = null;     // HTML element that hold this element
        this.header       = '';
        this.url          = '';
        this.routeData    = {};       // data for dynamic routes
        this.columns      = [];       // { field, caption, size, attr, render, hidden, gridMinWidth, editable }
        this.columnGroups = [];       // { span: int, caption: 'string', master: true/false }
        this.records      = [];       // { recid: int(requied), field1: 'value1', ... fieldN: 'valueN', style: 'string', editable: true/false, summary: true/false, changes: object }
        this.summary      = [];       // arry of summary records, same structure as records array
        this.searches     = [];       // { type, caption, field, inTag, outTag, hidden }
        this.searchData   = [];
        this.sortData     = [];
        this.postData     = {};
        this.toolbar      = {};       // if not empty object; then it is toolbar object

        this.show = {
            header          : false,
            toolbar         : false,
            footer          : false,
            columnHeaders   : true,
            lineNumbers     : false,
            expandColumn    : false,
            selectColumn    : false,
            emptyRecords    : true,
            toolbarReload   : true,
            toolbarColumns  : true,
            toolbarSearch   : true,
            toolbarAdd      : false,
            toolbarEdit     : false,
            toolbarDelete   : false,
            toolbarSave     : false,
            selectionBorder : true,
            recordTitles    : true,
            skipRecords     : true
        };

        this.autoLoad       = true;     // for infinite scroll
        this.fixedBody      = true;     // if false; then grid grows with data
        this.recordHeight   = 24;
        this.keyboard       = true;
        this.selectType     = 'row';    // can be row|cell
        this.multiSearch    = true;
        this.multiSelect    = true;
        this.multiSort      = true;
        this.reorderColumns = false;
        this.reorderRows    = false;
        this.markSearch     = true;

        this.total   = 0;     // server total
        this.limit   = 100;
        this.offset  = 0;     // how many records to skip (for infinite scroll) when pulling from server
        this.style   = '';
        this.ranges  = [];
        this.menu    = [];
        this.method  = null;         // if defined, then overwrited ajax method
        this.recid   = null;
        this.parser  = null;

        // events
        this.onAdd              = null;
        this.onEdit             = null;
        this.onRequest          = null;        // called on any server event
        this.onLoad             = null;
        this.onDelete           = null;
        this.onDeleted          = null;
        this.onSubmit           = null;
        this.onSave             = null;
        this.onSelect           = null;
        this.onUnselect         = null;
        this.onClick            = null;
        this.onDblClick         = null;
        this.onContextMenu      = null;
        this.onMenuClick        = null;        // when context menu item selected
        this.onColumnClick      = null;
        this.onColumnResize     = null;
        this.onSort             = null;
        this.onSearch           = null;
        this.onChange           = null;        // called when editable record is changed
        this.onRestore          = null;        // called when editable record is restored
        this.onExpand           = null;
        this.onCollapse         = null;
        this.onError            = null;
        this.onKeydown          = null;
        this.onToolbar          = null;     // all events from toolbar
        this.onColumnOnOff      = null;
        this.onCopy             = null;
        this.onPaste            = null;
        this.onSelectionExtend  = null;
        this.onEditField        = null;
        this.onRender           = null;
        this.onRefresh          = null;
        this.onReload           = null;
        this.onResize           = null;
        this.onDestroy          = null;
        this.onStateSave        = null;
        this.onStateRestore     = null;

        // internal
        this.last = {
            field     : 'all',
            caption   : w2utils.lang('All Fields'),
            logic     : 'OR',
            search    : '',
            searchIds : [],
            selection : {
                indexes : [],
                columns : {}
            },
            multi       : false,
            scrollTop   : 0,
            scrollLeft  : 0,
            sortData    : null,
            sortCount   : 0,
            xhr         : null,
            range_start : null,
            range_end   : null,
            sel_ind     : null,
            sel_col     : null,
            sel_type    : null,
            edit_col    : null
        };

        $.extend(true, this, w2obj.grid, options);
    }
*********************************************************************
  Library: Web 2.0 UI for jQuery (using prototypical inheritance)
  - Following objects defined
       - w2grid        - grid widget
       - $().w2grid    - jQuery wrapper
  - Dependencies: jQuery, w2utils, w2toolbar, w2fields, w2alert, w2confirm

== NICE TO HAVE ==
  - frozen columns
  - add colspans
  - allow this.total to be unknown (-1)
  - column autosize based on largest content
  - easy bubbles in the grid
  - More than 2 layers of header groups
  - reorder columns/records
  - hidden searches could not be clearned by the user
  - problem with .set() and arrays, array get extended too, but should be replaced
  - move events into prototype
  - add grid.focus()
  - add showExtra, KickIn Infinite scroll when so many records
  - after edit stay on the same record option
  - allow render: function to be filters

**********************************************************************