/** @class YAHOO.ext.grid.DefaultSelectionModel * @extends YAHOO.ext.util.Observable * The default SelectionModel used by {@link YAHOO.ext.grid.Grid}. It supports multiple selections and keyboard selection/navigation.

@constructor */ YAHOO.ext.grid.DefaultSelectionModel = function(){ this.selectedRows = []; this.selectedRowIds = []; this.lastSelectedRow = null; this.onRowSelect = new YAHOO.util.CustomEvent('SelectionTable.rowSelected'); this.onSelectionChange = new YAHOO.util.CustomEvent('SelectionTable.selectionChanged'); this.events = { /** * @event selectionchange * Fires when the selection changes * @param {SelectionModel} this * @param {Array} rows Array of row elements that are selected * @param {String} ids Array of ids that are selected */ 'selectionchange' : this.onSelectionChange, /** * @event rowselect * Fires when a row is selected or deselected * @param {SelectionModel} this * @param {HTMLElement} row The row element * @param {Boolean} selected true if the row was selected, false if deselected */ 'rowselect' : this.onRowSelect }; this.locked = false; }; YAHOO.ext.grid.DefaultSelectionModel.prototype = { /** @ignore Called by the grid automatically. Do not call directly. */ init : function(grid){ this.grid = grid; this.initEvents(); }, /** * Lock the selections */ lock : function(){ this.locked = true; }, /** * Unlock the selections */ unlock : function(){ this.locked = false; }, /** * Returns true if the selections are locked * @return {Boolean} */ isLocked : function(){ return this.locked; }, /** @ignore */ initEvents : function(){ if(this.grid.trackMouseOver){ this.grid.addListener("mouseover", this.handleOver, this, true); this.grid.addListener("mouseout", this.handleOut, this, true); } this.grid.addListener("rowclick", this.rowClick, this, true); this.grid.addListener("keydown", this.keyDown, this, true); }, 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, bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener, /** @ignore Syncs selectedRows with the correct row by looking it up by id. Used after a sort moves data around. */ syncSelectionsToIds : function(){ if(this.getCount() > 0){ var ids = this.selectedRowIds.concat(); this.clearSelections(); this.selectRowsById(ids, true); } }, /** * Set the selected rows by their ID(s). IDs must match what is returned by the DataModel getRowId(index). * @param {String/Array} id The id(s) to select * @param {Boolean} keepExisting (optional) True to retain existing selections */ selectRowsById : function(id, keepExisting){ var rows = this.grid.getRowsById(id); if (!(rows instanceof Array)){ this.selectRow(rows, keepExisting); return; } this.selectRows(rows, keepExisting); }, /** * Gets the number of selected rows. * @return {Number} */ getCount : function(){ return this.selectedRows.length; }, /** * Selects the first row in the grid. */ selectFirstRow : function(){ for(var j = 0; j < this.grid.rows.length; j++){ if(this.isSelectable(this.grid.rows[j])){ this.focusRow(this.grid.rows[j]); this.setRowState(this.grid.rows[j], true); return; } } }, /** * Selects the row immediately following the last selected row. * @param {Boolean} keepExisting (optional) True to retain existing selections */ selectNext : function(keepExisting){ if(this.lastSelectedRow){ for(var j = (this.lastSelectedRow.rowIndex+1); j < this.grid.rows.length; j++){ var row = this.grid.rows[j]; if(this.isSelectable(row)){ this.focusRow(row); this.setRowState(row, true, keepExisting); return; } } } }, /** * Selects the row that precedes the last selected row. * @param {Boolean} keepExisting (optional) True to retain existing selections */ selectPrevious : function(keepExisting){ if(this.lastSelectedRow){ for(var j = (this.lastSelectedRow.rowIndex-1); j >= 0; j--){ var row = this.grid.rows[j]; if(this.isSelectable(row)){ this.focusRow(row); this.setRowState(row, true, keepExisting); return; } } } }, /** * Returns the selected rows. * @return {Array} Array of DOM row elements */ getSelectedRows : function(){ return this.selectedRows; }, /** * Returns the selected row ids. * @return {Array} Array of String ids */ getSelectedRowIds : function(){ return this.selectedRowIds; }, /** * Clears all selections. */ clearSelections : function(){ if(this.isLocked()) return; var oldSelections = this.selectedRows.concat(); for(var j = 0; j < oldSelections.length; j++){ this.setRowState(oldSelections[j], false); } this.selectedRows = []; this.selectedRowIds = []; }, /** * Selects all rows. */ selectAll : function(){ if(this.isLocked()) return; this.selectedRows = []; this.selectedRowIds = []; for(var j = 0, len = this.grid.rows.length; j < len; j++){ this.setRowState(this.grid.rows[j], true, true); } }, /** * Returns True if there is a selection. * @return {Boolean} */ hasSelection : function(){ return this.selectedRows.length > 0; }, /** * Returns True if the specified row is selected. * @param {HTMLElement} row The row to check * @return {Boolean} */ isSelected : function(row){ return row && (row.selected === true || row.getAttribute('selected') == 'true'); }, /** * Returns True if the specified row is selectable. * @param {HTMLElement} row The row to check * @return {Boolean} */ isSelectable : function(row){ return row && row.getAttribute('selectable') != 'false'; }, /** @ignore */ rowClick : function(grid, rowIndex, e){ if(this.isLocked()) return; var row = grid.getRow(rowIndex); if(this.isSelectable(row)){ if(e.shiftKey && this.lastSelectedRow){ var lastIndex = this.lastSelectedRow.rowIndex; this.selectRange(this.lastSelectedRow, row, e.ctrlKey); this.lastSelectedRow = this.grid.el.dom.rows[lastIndex]; }else{ this.focusRow(row); var rowState = e.ctrlKey ? !this.isSelected(row) : true; this.setRowState(row, rowState, e.hasModifier()); } } }, /** * Deprecated. Tries to focus the row and scroll it into view - Use grid.scrollTo or grid.getView().focusRow() instead. * @deprecated * @param {HTMLElement} row The row to focus */ focusRow : function(row){ this.grid.view.focusRow(row); }, /** * Selects a row. * @param {Number/HTMLElement} row The row or index of the row to select * @param {Boolean} keepExisting (optional) True to retain existing selections */ selectRow : function(row, keepExisting){ this.setRowState(this.getRow(row), true, keepExisting); }, /** * Selects multiple rows. * @param {Array} rows Array of the rows or indexes of the row to select * @param {Boolean} keepExisting (optional) True to retain existing selections */ selectRows : function(rows, keepExisting){ if(!keepExisting){ this.clearSelections(); } for(var i = 0; i < rows.length; i++){ this.selectRow(rows[i], true); } }, /** * Deselects a row. * @param {Number/HTMLElement} row The row or index of the row to deselect */ deselectRow : function(row){ this.setRowState(this.getRow(row), false); }, /** @ignore */ getRow : function(row){ if(typeof row == 'number'){ row = this.grid.rows[row]; } return row; }, /** * Selects a range of rows. All rows in between startRow and endRow are also selected. * @param {Number/HTMLElement} startRow The row or index of the first row in the range * @param {Number/HTMLElement} endRow The row or index of the last row in the range * @param {Boolean} keepExisting (optional) True to retain existing selections */ selectRange : function(startRow, endRow, keepExisting){ startRow = this.getRow(startRow); endRow = this.getRow(endRow); this.setRangeState(startRow, endRow, true, keepExisting); }, /** * Deselects a range of rows. All rows in between startRow and endRow are also deselected. * @param {Number/HTMLElement} startRow The row or index of the first row in the range * @param {Number/HTMLElement} endRow The row or index of the last row in the range */ deselectRange : function(startRow, endRow){ startRow = this.getRow(startRow); endRow = this.getRow(endRow); this.setRangeState(startRow, endRow, false, true); }, /** @ignore */ setRowStateFromChild : function(childEl, selected, keepExisting){ var row = this.grid.getRowFromChild(childEl); this.setRowState(row, selected, keepExisting); }, /** @ignore */ setRangeState : function(startRow, endRow, selected, keepExisting){ if(this.isLocked()) return; if(!keepExisting){ this.clearSelections(); } var curRow = startRow; while(curRow.rowIndex != endRow.rowIndex){ this.setRowState(curRow, selected, true); curRow = (startRow.rowIndex < endRow.rowIndex ? this.grid.getRowAfter(curRow) : this.grid.getRowBefore(curRow)) } this.setRowState(endRow, selected, true); }, /** @ignore */ setRowState : function(row, selected, keepExisting){ if(this.isLocked()) return; if(this.isSelectable(row)){ if(selected){ if(!keepExisting){ this.clearSelections(); } this.setRowClass(row, 'selected'); row.selected = true; this.selectedRows.push(row); this.selectedRowIds.push(this.grid.dataModel.getRowId(row.rowIndex)); this.lastSelectedRow = row; }else{ this.setRowClass(row, ''); row.selected = false; this._removeSelected(row); } this.fireEvent('rowselect', this, row, selected); this.fireEvent('selectionchange', this, this.selectedRows, this.selectedRowIds); } }, /** @ignore */ handleOver : function(e){ var row = this.grid.getRowFromChild(e.getTarget()); if(this.isSelectable(row) && !this.isSelected(row)){ this.setRowClass(row, 'over'); } }, /** @ignore */ handleOut : function(e){ var row = this.grid.getRowFromChild(e.getTarget()); if(this.isSelectable(row) && !this.isSelected(row)){ this.setRowClass(row, ''); } }, /** @ignore */ keyDown : function(e){ if(e.browserEvent.keyCode == e.DOWN){ this.selectNext(e.shiftKey); e.preventDefault(); }else if(e.browserEvent.keyCode == e.UP){ this.selectPrevious(e.shiftKey); e.preventDefault(); } }, /** @ignore */ setRowClass : function(row, cssClass){ if(this.isSelectable(row)){ if(cssClass == 'selected'){ YAHOO.util.Dom.removeClass(row, 'ygrid-row-over'); YAHOO.util.Dom.addClass(row, 'ygrid-row-selected'); }else if(cssClass == 'over'){ YAHOO.util.Dom.removeClass(row, 'ygrid-row-selected'); YAHOO.util.Dom.addClass(row, 'ygrid-row-over'); }else if(cssClass == ''){ YAHOO.util.Dom.removeClass(row, 'ygrid-row-selected'); YAHOO.util.Dom.removeClass(row, 'ygrid-row-over'); } } }, /** @ignore */ _removeSelected : function(row){ var sr = this.selectedRows; for (var i = 0; i < sr.length; i++) { if (sr[i] === row){ this.selectedRows.splice(i, 1); this.selectedRowIds.splice(i, 1); return; } } } }; /** @class YAHOO.ext.grid.SingleSelectionModel @extends YAHOO.ext.grid.DefaultSelectionModel Allows only one row to be selected at a time. @constructor * Create new SingleSelectionModel */ YAHOO.ext.grid.SingleSelectionModel = function(){ YAHOO.ext.grid.SingleSelectionModel.superclass.constructor.call(this); }; YAHOO.extendX(YAHOO.ext.grid.SingleSelectionModel, YAHOO.ext.grid.DefaultSelectionModel); /** @ignore */ YAHOO.ext.grid.SingleSelectionModel.prototype.setRowState = function(row, selected){ YAHOO.ext.grid.SingleSelectionModel.superclass.setRowState.call(this, row, selected, false); }; YAHOO.ext.grid.DisableSelectionModel = function(){ YAHOO.ext.grid.DisableSelectionModel.superclass.constructor.call(this); }; YAHOO.extendX(YAHOO.ext.grid.DisableSelectionModel, YAHOO.ext.grid.DefaultSelectionModel); YAHOO.ext.grid.DisableSelectionModel.prototype.initEvents = function(){ };