--- /dev/null
+/**
+ * @class Ext.selection.CheckboxModel
+ * @extends Ext.selection.RowModel
+ *
+ * A selection model that renders a column of checkboxes that can be toggled to
+ * select or deselect rows. The default mode for this selection model is MULTI.
+ *
+ * The selection model will inject a header for the checkboxes in the first view
+ * and according to the 'injectCheckbox' configuration.
+ */
+Ext.define('Ext.selection.CheckboxModel', {
+ extend: 'Ext.selection.RowModel',
+
+ /**
+ * @cfg {String} mode
+ * Modes of selection.
+ * Valid values are SINGLE, SIMPLE, and MULTI. Defaults to 'MULTI'
+ */
+ mode: 'MULTI',
+
+ /**
+ * @cfg {Mixed} injectCheckbox
+ * Instructs the SelectionModel whether or not to inject the checkbox header
+ * automatically or not. (Note: By not placing the checkbox in manually, the
+ * grid view will need to be rendered 2x on initial render.)
+ * Supported values are a Number index, false and the strings 'first' and 'last'.
+ * Default is 0.
+ */
+ injectCheckbox: 0,
+
+ /**
+ * @cfg {Boolean} checkOnly <tt>true</tt> if rows can only be selected by clicking on the
+ * checkbox column (defaults to <tt>false</tt>).
+ */
+ checkOnly: false,
+
+ // private
+ checkerOnCls: Ext.baseCSSPrefix + 'grid-hd-checker-on',
+
+ bindComponent: function() {
+ this.sortable = false;
+ this.callParent(arguments);
+
+ var view = this.views[0],
+ headerCt = view.headerCt;
+
+ if (this.injectCheckbox !== false) {
+ if (this.injectCheckbox == 'first') {
+ this.injectCheckbox = 0;
+ } else if (this.injectCheckbox == 'last') {
+ this.injectCheckbox = headerCt.getColumnCount();
+ }
+ headerCt.add(this.injectCheckbox, this.getHeaderConfig());
+ }
+ headerCt.on('headerclick', this.onHeaderClick, this);
+ },
+
+ /**
+ * Toggle the ui header between checked and unchecked state.
+ * @param {Boolean} isChecked
+ * @private
+ */
+ toggleUiHeader: function(isChecked) {
+ var view = this.views[0],
+ headerCt = view.headerCt,
+ checkHd = headerCt.child('gridcolumn[isCheckerHd]');
+
+ if (checkHd) {
+ if (isChecked) {
+ checkHd.el.addCls(this.checkerOnCls);
+ } else {
+ checkHd.el.removeCls(this.checkerOnCls);
+ }
+ }
+ },
+
+ /**
+ * Toggle between selecting all and deselecting all when clicking on
+ * a checkbox header.
+ */
+ onHeaderClick: function(headerCt, header, e) {
+ if (header.isCheckerHd) {
+ e.stopEvent();
+ var isChecked = header.el.hasCls(Ext.baseCSSPrefix + 'grid-hd-checker-on');
+ if (isChecked) {
+ // We have to supress the event or it will scrollTo the change
+ this.deselectAll(true);
+ } else {
+ // We have to supress the event or it will scrollTo the change
+ this.selectAll(true);
+ }
+ }
+ },
+
+ /**
+ * Retrieve a configuration to be used in a HeaderContainer.
+ * This should be used when injectCheckbox is set to false.
+ */
+ getHeaderConfig: function() {
+ return {
+ isCheckerHd: true,
+ text : ' ',
+ width: 24,
+ sortable: false,
+ fixed: true,
+ hideable: false,
+ menuDisabled: true,
+ dataIndex: '',
+ cls: Ext.baseCSSPrefix + 'column-header-checkbox ',
+ renderer: Ext.Function.bind(this.renderer, this)
+ };
+ },
+
+ /**
+ * Generates the HTML to be rendered in the injected checkbox column for each row.
+ * Creates the standard checkbox markup by default; can be overridden to provide custom rendering.
+ * See {@link Ext.grid.column.Column#renderer} for description of allowed parameters.
+ */
+ renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
+ metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
+ return '<div class="' + Ext.baseCSSPrefix + 'grid-row-checker"> </div>';
+ },
+
+ // override
+ onRowMouseDown: function(view, record, item, index, e) {
+ view.el.focus();
+ var me = this,
+ checker = e.getTarget('.' + Ext.baseCSSPrefix + 'grid-row-checker');
+
+ // checkOnly set, but we didn't click on a checker.
+ if (me.checkOnly && !checker) {
+ return;
+ }
+
+ if (checker) {
+ var mode = me.getSelectionMode();
+ // dont change the mode if its single otherwise
+ // we would get multiple selection
+ if (mode !== 'SINGLE') {
+ me.setSelectionMode('SIMPLE');
+ }
+ me.selectWithEvent(record, e);
+ me.setSelectionMode(mode);
+ } else {
+ me.selectWithEvent(record, e);
+ }
+ },
+
+ /**
+ * Synchronize header checker value as selection changes.
+ * @private
+ */
+ onSelectChange: function(record, isSelected) {
+ this.callParent([record, isSelected]);
+ // check to see if all records are selected
+ var hdSelectStatus = this.selected.getCount() === this.store.getCount();
+ this.toggleUiHeader(hdSelectStatus);
+ }
+});