# Grid.js

    /**
     * @class YAHOO.ext.grid.Grid
     * @extends YAHOO.ext.util.Observable
     * This class represents the primary interface of a component based grid control.
     * <br><br>Usage:<pre><code>
     var grid = new YAHOO.ext.grid.Grid('my-container-id', dataModel, columnModel);
     // set any options
     grid.render();
     // or using a config
     var grid = new YAHOO.ext.grid.Grid('my-container-id', {
         dataModel: myDataModel,
         colModel: myColModel,
         selModel: mySelectionModel,
         autoSizeColumns: true,
         monitorWindowResize: false,
         trackMouseOver: true
     }).render();
     * </code></pre>
     * <b>Common Problems:</b><br/>
     * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
     * element will correct this<br/>
     * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
     * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
     * are unpredictable.<br/>
     * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
     * grid to calculate dimensions/offsets.<br/>
     * @requires YAHOO.util.Dom
     * @requires YAHOO.util.Event
     * @requires YAHOO.util.CustomEvent
     * @requires YAHOO.ext.Element
     * @requires YAHOO.ext.util.Browser
     * @requires YAHOO.ext.util.CSS
     * @requires YAHOO.ext.SplitBar
     * @requires YAHOO.ext.EventObject
     * @constructor
     * @param {String/HTMLElement/YAHOO.ext.Element} container The element into which this grid will be rendered -
     * The container MUST have some type of size defined for the grid to fill. The container will be
     * automatically set to position relative if it isn't already.
     * @param {Object} config A config object that sets properties on this grid OR the data model to bind to
     * @param {Object} colModel (optional) The column model with info about this grid's columns
     * @param {Object} selectionModel (optional) The selection model for this grid (defaults to DefaultSelectionModel)
     */
    YAHOO.ext.grid.Grid = function(container, config, colModel, selectionModel){
    	/** @private */
    	this.container = YAHOO.ext.Element.get(container);
    	this.container.update('');
    	this.container.setStyle('overflow', 'hidden');
    	this.id = this.container.id;
    	this.rows = [];
        this.rowCount = 0;
        this.fieldId = null;
        var dataModel = config; // for legacy pre config support
        this.dataModel = dataModel;
        this.colModel = colModel;
        this.selModel = selectionModel;
    	this.activeEditor = null;
    	this.editingCell = null;

    	/** The minimum width a column can be resized to. (Defaults to 25)
    	 * @type Number */
    	this.minColumnWidth = 25;

    	/** True to automatically resize the columns to fit their content <b>on initial render</b>
    	 * @type Boolean */
    	this.autoSizeColumns = false;

    	/** True to measure headers with column data when auto sizing columns
    	 * @type Boolean */
    	this.autoSizeHeaders = false;

    	/**
    	 * True to autoSize the grid when the window resizes - defaults to true
    	 */
    	this.monitorWindowResize = true;

    	/** If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
    	 * rows measured to get a columns size - defaults to 0 (all rows).
    	 * @type Number */
    	this.maxRowsToMeasure = 0;

    	/** True to highlight rows when the mouse is over (default is false)
    	 * @type Boolean */
    	this.trackMouseOver = false;

    	/** True to enable drag and drop of rows
    	 * @type Boolean */
    	this.enableDragDrop = false;

    	/** True to stripe the rows (default is true)
    	 * @type Boolean */
    	this.stripeRows = true;
    	/** True to fit the height of the grid container to the height of the data (defaults to false)
    	 * @type Boolean */
    	this.autoHeight = false;

    	/** True to fit the width of the grid container to the width of the columns (defaults to false)
    	 * @type Boolean */
    	this.autoWidth = false;

    	/**
    	 * The view used by the grid. This can be set before a call to render().
    	 * Defaults to a YAHOO.ext.grid.GridView or PagedGridView depending on the data model.
    	 * @type Object
    	 */
    	this.view = null;

    	/** A regular expression defining tagNames
         * allowed to have text selection (Defaults to <code>/INPUT|TEXTAREA|SELECT/i</code>) */
        this.allowTextSelectionPattern = /INPUT|TEXTAREA|SELECT/i;

    	if(typeof config == 'object' && !config.getRowCount){// must be config object
    	    YAHOO.ext.util.Config.apply(this, config);
    	}

    	/** @private */
    	this.setValueDelegate = this.setCellValue.createDelegate(this);

    	/** @private */
    	this.events = {
    	    // raw events
    	    /**
    	     * @event click
    	     * The raw click event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'click' : true,
    	    /**
    	     * @event dblclick
    	     * The raw dblclick event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'dblclick' : true,
    	    /**
    	     * @event mousedown
    	     * The raw mousedown event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'mousedown' : true,
    	    /**
    	     * @event mouseup
    	     * The raw mouseup event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'mouseup' : true,
    	    /**
    	     * @event mouseover
    	     * The raw mouseover event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'mouseover' : true,
    	    /**
    	     * @event mouseout
    	     * The raw mouseout event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'mouseout' : true,
    	    /**
    	     * @event keypress
    	     * The raw keypress event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'keypress' : true,
    	    /**
    	     * @event keydown
    	     * The raw keydown event for the entire grid.
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'keydown' : true,

    	    // custom events

    	    /**
    	     * @event cellclick
    	     * Fires when a cell is clicked
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {Number} columnIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'cellclick' : true,
    	    /**
    	     * @event celldblclick
    	     * Fires when a cell is double clicked
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {Number} columnIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'celldblclick' : true,
    	    /**
    	     * @event rowclick
    	     * Fires when a row is clicked
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'rowclick' : true,
    	    /**
    	     * @event rowdblclick
    	     * Fires when a row is double clicked
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'rowdblclick' : true,
    	    /**
    	     * @event headerclick
    	     * Fires when a header is clicked
    	     * @param {Grid} this
    	     * @param {Number} columnIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'headerclick' : true,
    	    /**
    	     * @event rowcontextmenu
    	     * Fires when a row is right clicked
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'rowcontextmenu' : true,
    	    /**
    	     * @event headercontextmenu
    	     * Fires when a header is right clicked
    	     * @param {Grid} this
    	     * @param {Number} columnIndex
    	     * @param {YAHOO.ext.EventObject} e
    	     */
    	    'headercontextmenu' : true,
    	    /**
    	     * @event beforeedit
    	     * Fires before a cell is edited
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {Number} columnIndex
    	     */
    	    'beforeedit' : true,
    	    /**
    	     * @event afteredit
    	     * Fires after a cell is edited
    	     * @param {Grid} this
    	     * @param {Number} rowIndex
    	     * @param {Number} columnIndex
    	     */
    	    'afteredit' : true,
    	    /**
    	     * @event bodyscroll
    	     * Fires when the body element is scrolled
    	     * @param {Number} scrollLeft
    	     * @param {Number} scrollTop
    	     */
    	    'bodyscroll' : true,
    	    /**
    	     * @event columnresize
    	     * Fires when the user resizes a column
    	     * @param {Number} columnIndex
    	     * @param {Number} newSize
    	     */
    	    'columnresize' : true,
    	    /**
    	     * @event startdrag
    	     * Fires when row(s) start being dragged
    	     * @param {Grid} this
    	     * @param {YAHOO.ext.GridDD} dd The drag drop object
    	     * @param {event} e The raw browser event
    	     */
    	    'startdrag' : true,
    	    /**
    	     * @event enddrag
    	     * Fires when a drag operation is complete
    	     * @param {Grid} this
    	     * @param {YAHOO.ext.GridDD} dd The drag drop object
    	     * @param {event} e The raw browser event
    	     */
    	    'enddrag' : true,
    	    /**
    	     * @event dragdrop
    	     * Fires when dragged row(s) are dropped on a valid DD target
    	     * @param {Grid} this
    	     * @param {YAHOO.ext.GridDD} dd The drag drop object
    	     * @param {String} targetId The target drag drop object
    	     * @param {event} e The raw browser event
    	     */
    	    'dragdrop' : true,
    	    /**
    	     * @event dragover
    	     * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
    	     * @param {Grid} this
    	     * @param {YAHOO.ext.GridDD} dd The drag drop object
    	     * @param {String} targetId The target drag drop object
    	     * @param {event} e The raw browser event
    	     */
    	    'dragover' : true,
    	    /**
    	     * @event dragenter
    	     *  Fires when the dragged row(s) first cross another DD target while being dragged
    	     * @param {Grid} this
    	     * @param {YAHOO.ext.GridDD} dd The drag drop object
    	     * @param {String} targetId The target drag drop object
    	     * @param {event} e The raw browser event
    	     */
    	    'dragenter' : true,
    	    /**
    	     * @event dragout
    	     * Fires when the dragged row(s) leave another DD target while being dragged
    	     * @param {Grid} this
    	     * @param {YAHOO.ext.GridDD} dd The drag drop object
    	     * @param {String} targetId The target drag drop object
    	     * @param {event} e The raw browser event
    	     */
    	    'dragout' : true
    	};
    };

    YAHOO.ext.grid.Grid.prototype = {
        /**
         * Called once after all setup has been completed and the grid is ready to be rendered.
         * @return {YAHOO.ext.grid.Grid} this
         */
        render : function(){
            if((!this.container.dom.offsetHeight || this.container.dom.offsetHeight < 20)
                    || this.container.getStyle('height') == 'auto'){
        	    this.autoHeight = true;
        	}
        	if((!this.container.dom.offsetWidth || this.container.dom.offsetWidth < 20)){
        	    this.autoWidth = true;
        	}
        	if(!this.view){
        	    if(this.dataModel.isPaged()){
        		    this.view = new YAHOO.ext.grid.PagedGridView();
        	    }else{
        	        this.view = new YAHOO.ext.grid.GridView();
        	    }
        	}
        	this.view.init(this);
            this.el = getEl(this.view.render(), true);
            var c = this.container;
            c.mon("click", this.onClick, this, true);
            c.mon("dblclick", this.onDblClick, this, true);
            c.mon("contextmenu", this.onContextMenu, this, true);
            c.mon("selectstart", this.cancelTextSelection, this, true);
            c.mon("mousedown", this.cancelTextSelection, this, true);
            c.mon("mousedown", this.onMouseDown, this, true);
            c.mon("mouseup", this.onMouseUp, this, true);
            if(this.trackMouseOver){
                this.el.mon("mouseover", this.onMouseOver, this, true);
                this.el.mon("mouseout", this.onMouseOut, this, true);
            }
            c.mon("keypress", this.onKeyPress, this, true);
            c.mon("keydown", this.onKeyDown, this, true);
            this.init();
            return this;
        },

        init : function(){
            this.rows = this.el.dom.rows;
            if(!this.disableSelection){
    	        if(!this.selModel){
    	            this.selModel = new YAHOO.ext.grid.DefaultSelectionModel(this);
    	        }
    	        this.selModel.init(this);
    	        this.selModel.onSelectionChange.subscribe(this.updateField, this, true);
            }else{
                this.selModel = new YAHOO.ext.grid.DisableSelectionModel(this);
                this.selModel.init(this);
            }

            if(this.enableDragDrop){
                this.dd = new YAHOO.ext.grid.GridDD(this, this.container.dom);
            }
         },

        /**
         * Resets the grid for use with a new configuration and/or data and column models. After calling this function
         * you will need to call render() again. Any listeners for this grid will be retained.
         * Warning: any listeners manually attached (not through the grid) to the grid's container
         * element will be removed.
         * @param {Object} config Standard config object with properties to set on this grid
         * @return {YAHOO.ext.grid.Grid} this
         */
        reset : function(config){
            this.destroy(false, true);
            YAHOO.ext.util.Config.apply(this, config);
            return this;
        },

        /**
         * Destroy this grid.
         * @param {Boolean} removeEl True to remove the element
         */
        destroy : function(removeEl, keepListeners){
            var c = this.container;
            c.removeAllListeners();
            this.view.destroy();
            YAHOO.ext.EventManager.removeResizeListener(this.view.onWindowResize, this.view);
            this.view = null;
            this.colModel.purgeListeners();
            if(!keepListeners){
                this.purgeListeners();
            }
            c.update('');
            if(removeEl === true){
                c.remove();
            }
        },

        /**
         * Replace the current data model with a new one (experimental)
         * @param {DataModel} dm The new data model
         * @pram {Boolean} rerender true to render the grid rows from scratch
         */
        setDataModel : function(dm, rerender){
            this.view.unplugDataModel(this.dataModel);
            this.dataModel = dm;
            this.view.plugDataModel(dm);
            if(rerender){
                dm.fireEvent('datachanged');
            }
        },

        onMouseDown : function(e){
            this.fireEvent('mousedown', e);
        },

        onMouseUp : function(e){
            this.fireEvent('mouseup', e);
        },

        onMouseOver : function(e){
            this.fireEvent('mouseover', e);
        },

        onMouseOut : function(e){
            this.fireEvent('mouseout', e);
        },

        onKeyPress : function(e){
            this.fireEvent('keypress', e);
        },

        onKeyDown : function(e){
            this.fireEvent('keydown', e);
        },

        fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
        on : YAHOO.ext.util.Observable.prototype.on,
        addListener : YAHOO.ext.util.Observable.prototype.addListener,
        delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
        removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
        purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,

        onClick : function(e){
            this.fireEvent('click', e);
            var target = e.getTarget();
            var row = this.getRowFromChild(target);
            var cell = this.getCellFromChild(target);
            var header = this.getHeaderFromChild(target);
            if(row){
                this.fireEvent('rowclick', this, row.rowIndex, e);
            }
            if(cell){
                this.fireEvent('cellclick', this, row.rowIndex, cell.columnIndex, e);
            }
            if(header){
                this.fireEvent('headerclick', this, header.columnIndex, e);
            }
        },

        onContextMenu : function(e){
            var target = e.getTarget();
            var row = this.getRowFromChild(target);
            var header = this.getHeaderFromChild(target);
            if(row){
                this.fireEvent('rowcontextmenu', this, row.rowIndex, e);
            }
            if(header){
                this.fireEvent('headercontextmenu', this, header.columnIndex, e);
            }
            e.preventDefault();
        },

        onDblClick : function(e){
            this.fireEvent('dblclick', e);
            var target = e.getTarget();
            var row = this.getRowFromChild(target);
            var cell = this.getCellFromChild(target);
            if(row){
                this.fireEvent('rowdblclick', this, row.rowIndex, e);
            }
            if(cell){
                this.fireEvent('celldblclick', this, row.rowIndex, cell.columnIndex, e);
            }
        },

        /**
         * Starts editing the specified for the specified row/column
         * @param {Number} rowIndex
         * @param {Number} colIndex
         */
        startEditing : function(rowIndex, colIndex){
            var row = this.rows[rowIndex];
            var cell = row.childNodes[colIndex];
            this.stopEditing();
            setTimeout(this.doEdit.createDelegate(this, [row, cell]), 10);
        },

        /**
         * Stops any active editing
         */
        stopEditing : function(){
            if(this.activeEditor){
                this.activeEditor.stopEditing();
            }
        },

        /** @ignore */
        doEdit : function(row, cell){
            if(!row || !cell) return;
            var cm = this.colModel;
            var dm = this.dataModel;
            var colIndex = cell.columnIndex;
            var rowIndex = row.rowIndex;
            if(cm.isCellEditable(colIndex, rowIndex)){
               var ed = cm.getCellEditor(colIndex, rowIndex);
               if(ed){
                   if(this.activeEditor){
                       this.activeEditor.stopEditing();
                   }
                   this.fireEvent('beforeedit', this, rowIndex, colIndex);
                   this.activeEditor = ed;
                   this.editingCell = cell;
                   this.view.ensureVisible(row, true);
                   try{
                       cell.focus();
                   }catch(e){}
                   ed.init(this, this.el.dom.parentNode, this.setValueDelegate);
                   var value = dm.getValueAt(rowIndex, cm.getDataIndex(colIndex));
                   // set timeout so firefox stops editing before starting a new edit
                   setTimeout(ed.startEditing.createDelegate(ed, [value, row, cell]), 1);
               }
            }
        },

        setCellValue : function(value, rowIndex, colIndex){
             this.dataModel.setValueAt(value, rowIndex, this.colModel.getDataIndex(colIndex));
             this.fireEvent('afteredit', this, rowIndex, colIndex);
        },

        /** @ignore Called when text selection starts or mousedown to prevent default */
        cancelTextSelection : function(e){
            var target = e.getTarget();
            if(target && target != this.el.dom.parentNode && !this.allowTextSelectionPattern.test(target.tagName)){
                e.preventDefault();
            }
        },

        /**
         * Causes the grid to manually recalculate it's dimensions. Generally this is done automatically,
         * but if manual update is required this method will initiate it.
         */
        autoSize : function(){
            this.view.updateWrapHeight();
            this.view.adjustForScroll();
        },

        /**
         * Scrolls the grid to the specified row
         * @param {Number/HTMLElement} row The row object or index of the row
         */
        scrollTo : function(row){
            if(typeof row == 'number'){
                row = this.rows[row];
            }
            this.view.ensureVisible(row, true);
        },

        /** @private */
        getEditingCell : function(){
            return this.editingCell;
        },

        /**
         * Binds this grid to the field with the specified id. Initially reads and parses the comma
         * delimited ids in the field and selects those items. All selections made in the grid
         * will be persisted to the field by their ids comma delimited.
         * @param {String} The id of the field to bind to
         */
        bindToField : function(fieldId){
            this.fieldId = fieldId;
            this.readField();
        },

        /** @private */
        updateField : function(){
            if(this.fieldId){
                var field = YAHOO.util.Dom.get(this.fieldId);
                field.value = this.getSelectedRowIds().join(',');
            }
        },

        /**
         * Causes the grid to read and select the ids from the bound field - See {@link #bindToField}.
         */
        readField : function(){
            if(this.fieldId){
                var field = YAHOO.util.Dom.get(this.fieldId);
                var values = field.value.split(',');
                var rows = this.getRowsById(values);
                this.selModel.selectRows(rows, false);
            }
        },

    	/**
    	 * Returns the table row at the specified index
    	 * @param {Number} index
    	 * @return {HTMLElement}
    	 */
        getRow : function(index){
            return this.rows[index];
        },

    	/**
    	 * Returns the rows that have the specified id(s). The id value for a row is provided
    	 * by the DataModel. See {@link YAHOO.ext.grid.DefaultDataModel#getRowId}.
    	 * @param {String/Array} An id to find or an array of ids
    	 * @return {HtmlElement/Array} If one id was passed in, it returns one result.
    	 * If an array of ids was specified, it returns an Array of HTMLElements
    	 */
        getRowsById : function(id){
            var dm = this.dataModel;
            if(!(id instanceof Array)){
                for(var i = 0; i < this.rows.length; i++){
                    if(dm.getRowId(i) == id){
                        return this.rows[i];
                    }
                }
                return null;
            }
            var found = [];
            var re = "^(?:";
            for(var i = 0; i < id.length; i++){
                re += id[i];
                if(i != id.length-1) re += "|";
            }
            var regex = new RegExp(re + ")$");
            for(var i = 0; i < this.rows.length; i++){
                if(regex.test(dm.getRowId(i))){
                    found.push(this.rows[i]);
                }
            }
            return found;
        },

        /**
    	 * Returns the row that comes after the specified row - text nodes are skipped.
    	 * @param {HTMLElement} row
    	 * @return {HTMLElement}
    	 */
        getRowAfter : function(row){
            return this.getSibling('next', row);
        },

        /**
    	 * Returns the row that comes before the specified row - text nodes are skipped.
    	 * @param {HTMLElement} row
    	 * @return {HTMLElement}
    	 */
        getRowBefore : function(row){
            return this.getSibling('previous', row);
        },

        /**
    	 * Returns the cell that comes after the specified cell - text nodes are skipped.
    	 * @param {HTMLElement} cell
    	 * @param {Boolean} includeHidden
    	 * @return {HTMLElement}
    	 */
        getCellAfter : function(cell, includeHidden){
            var next = this.getSibling('next', cell);
            if(next && !includeHidden && this.colModel.isHidden(next.columnIndex)){
                return this.getCellAfter(next);
            }
            return next;
        },

        /**
    	 * Returns the cell that comes before the specified cell - text nodes are skipped.
    	 * @param {HTMLElement} cell
    	 * @param {Boolean} includeHidden
    	 * @return {HTMLElement}
    	 */
        getCellBefore : function(cell, includeHidden){
            var prev = this.getSibling('previous', cell);
            if(prev && !includeHidden && this.colModel.isHidden(prev.columnIndex)){
                return this.getCellBefore(prev);
            }
            return prev;
        },

        /**
    	 * Returns the last cell for the row - text nodes and hidden columns are skipped.
    	 * @param {HTMLElement} row
    	 * @param {Boolean} includeHidden
    	 * @return {HTMLElement}
    	 */
        getLastCell : function(row, includeHidden){
            var cell = this.getElement('previous', row.lastChild);
            if(cell && !includeHidden && this.colModel.isHidden(cell.columnIndex)){
                return this.getCellBefore(cell);
            }
            return cell;
        },

        /**
    	 * Returns the first cell for the row - text nodes and hidden columns are skipped.
    	 * @param {HTMLElement} row
    	 * @param {Boolean} includeHidden
    	 * @return {HTMLElement}
    	 */
        getFirstCell : function(row, includeHidden){
            var cell = this.getElement('next', row.firstChild);
            if(cell && !includeHidden && this.colModel.isHidden(cell.columnIndex)){
                return this.getCellAfter(cell);
            }
            return cell;
        },

        /**
         * @private
         * Gets siblings, skipping text nodes
         * @param {String} type The direction to walk: 'next' or 'previous'
         * @param {HTMLElement} node
    	 */
        getSibling : function(type, node){
            if(!node) return null;
            type += 'Sibling';
            var n = node[type];
            while(n && n.nodeType != 1){
                n = n[type];
            }
            return n;
        },

        /**
         * Returns node if node is an HTMLElement else walks the siblings in direction looking for
         * a node that is an element
         * @param {String} direction The direction to walk: 'next' or 'previous'
         * @private
         */
        getElement : function(direction, node){
            if(!node || node.nodeType == 1) return node;
            else return this.getSibling(direction, node);
        },

        /**
         * @private
         */
        getElementFromChild : function(childEl, parentClass){
            if(!childEl || (YAHOO.util.Dom.hasClass(childEl, parentClass))){
    		    return childEl;
    	    }
    	    var p = childEl.parentNode;
    	    var b = document.body;
    	    while(p && p != b){
                if(YAHOO.util.Dom.hasClass(p, parentClass)){
                	return p;
                }
                p = p.parentNode;
            }
    	    return null;
        },

        /**
    	 * Returns the row that contains the specified child element.
    	 * @param {HTMLElement} childEl
    	 * @return {HTMLElement}
    	 */
        getRowFromChild : function(childEl){
            return this.getElementFromChild(childEl, 'ygrid-row');
        },

        /**
    	 * Returns the cell that contains the specified child element.
    	 * @param {HTMLElement} childEl
    	 * @return {HTMLElement}
    	 */
        getCellFromChild : function(childEl){
            return this.getElementFromChild(childEl, 'ygrid-col');
        },

        /**
         * Returns the header element that contains the specified child element.
         * @param {HTMLElement}  childEl
    	 * @return {HTMLElement}
    	 */
         getHeaderFromChild : function(childEl){
            return this.getElementFromChild(childEl, 'ygrid-hd');
        },

        /**
         * Convenience method for getSelectionModel().getSelectedRows() -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRows}</small> for more details.
         * @return {Array}
         */
        getSelectedRows : function(){
            return this.selModel.getSelectedRows();
        },

        /**
         * Convenience method for getSelectionModel().getSelectedRows()[0] -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRows}</small> for more details.
         * @return {HTMLElement}
         */
        getSelectedRow : function(){
            if(this.selModel.hasSelection()){
                return this.selModel.getSelectedRows()[0];
            }
            return null;
        },

        /**
         * Get the selected row indexes
         * @return {Array} Array of indexes
         */
        getSelectedRowIndexes : function(){
            var a = [];
            var rows = this.selModel.getSelectedRows();
            for(var i = 0; i < rows.length; i++) {
            	a[i] = rows[i].rowIndex;
            }
            return a;
        },

        /**
         * Gets the first selected row or -1 if none are selected
         * @return {Number}
         */
        getSelectedRowIndex : function(){
            if(this.selModel.hasSelection()){
               return this.selModel.getSelectedRows()[0].rowIndex;
            }
            return -1;
        },

        /**
         * Convenience method for getSelectionModel().getSelectedRowIds()[0] -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRowIds}</small> for more details.
         * @return {String}
         */
        getSelectedRowId : function(){
            if(this.selModel.hasSelection()){
               return this.selModel.getSelectedRowIds()[0];
            }
            return null;
        },

        /**
         * Convenience method for getSelectionModel().getSelectedRowIds() -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRowIds}</small> for more details.
         * @return {Array}
         */
        getSelectedRowIds : function(){
            return this.selModel.getSelectedRowIds();
        },

        /**
         * Convenience method for getSelectionModel().clearSelections() -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#clearSelections}</small> for more details.
         */
        clearSelections : function(){
            this.selModel.clearSelections();
        },

        /**
         * Convenience method for getSelectionModel().selectAll() -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#selectAll}</small> for more details.
         */
        selectAll : function(){
            this.selModel.selectAll();
        },

        /**
         * Convenience method for getSelectionModel().getCount() -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getCount}</small> for more details.
         * @return {Number}
         */
        getSelectionCount : function(){
            return this.selModel.getCount();
        },

        /**
         * Convenience method for getSelectionModel().hasSelection() -
         * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#hasSelection}</small> for more details.
         * @return {Boolean}
         */
        hasSelection : function(){
            return this.selModel.hasSelection();
        },

        /**
         * Returns the grid's SelectionModel.
         * @return {SelectionModel}
         */
        getSelectionModel : function(){
            if(!this.selModel){
                this.selModel = new DefaultSelectionModel();
            }
            return this.selModel;
        },

        /**
         * Returns the grid's DataModel.
         * @return {DataModel}
         */
        getDataModel : function(){
            return this.dataModel;
        },

        /**
         * Returns the grid's ColumnModel.
         * @return {ColumnModel}
         */
        getColumnModel : function(){
            return this.colModel;
        },

        /**
         * Returns the grid's GridView object.
         * @return {GridView}
         */
        getView : function(){
            return this.view;
        },
        /**
         * Called to get grid's drag proxy text, by default returns this.ddText.
         * @return {String}
         */
        getDragDropText : function(){
            return this.ddText.replace('%0', this.selModel.getCount());
        }
    };
    /**
     * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
     * %0 is replaced with the number of selected rows.
     * @type String
     */
    YAHOO.ext.grid.Grid.prototype.ddText = "%0 selected row(s)";

yui-ext - Copyright © 2006 Jack Slocum. | Yahoo! UI - Copyright © 2006 Yahoo! Inc.
All rights reserved.