4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-selection-Model'>/**
19 </span> * @class Ext.selection.Model
20 * @extends Ext.util.Observable
22 * Tracks what records are currently selected in a databound widget.
24 * This is an abstract class and is not meant to be directly used.
26 * DataBound UI widgets such as GridPanel, TreePanel, and ListView
27 * should subclass AbstractStoreSelectionModel and provide a way
28 * to binding to the component.
30 * The abstract methods onSelectChange and onLastFocusChanged should
31 * be implemented in these subclasses to update the UI widget.
33 Ext.define('Ext.selection.Model', {
34 extend: 'Ext.util.Observable',
35 alternateClassName: 'Ext.AbstractStoreSelectionModel',
36 requires: ['Ext.data.StoreManager'],
39 <span id='Ext-selection-Model-cfg-mode'> /**
40 </span> * @cfg {String} mode
42 * Valid values are SINGLE, SIMPLE, and MULTI. Defaults to 'SINGLE'
45 <span id='Ext-selection-Model-cfg-allowDeselect'> /**
46 </span> * @cfg {Boolean} allowDeselect
47 * Allow users to deselect a record in a DataView, List or Grid. Only applicable when the SelectionModel's mode is 'SINGLE'. Defaults to false.
51 <span id='Ext-selection-Model-property-selected'> /**
52 </span> * @property selected
53 * READ-ONLY A MixedCollection that maintains all of the currently selected
59 <span id='Ext-selection-Model-property-pruneRemoved'> /**
60 </span> * Prune records when they are removed from the store from the selection.
61 * This is a private flag. For an example of its usage, take a look at
62 * Ext.selection.TreeModel.
67 constructor: function(cfg) {
74 <span id='Ext-selection-Model-event-selectionchange'> /**
75 </span> * @event selectionchange
76 * Fired after a selection change has occurred
77 * @param {Ext.selection.Model} this
78 * @param {Array} selected The selected records
89 // sets this.selectionMode
90 me.setSelectionMode(cfg.mode || me.mode);
92 // maintains the currently selected records.
93 me.selected = Ext.create('Ext.util.MixedCollection');
95 me.callParent(arguments);
98 // binds the store to the selModel.
99 bind : function(store, initial){
102 if(!initial && me.store){
103 if(store !== me.store && me.store.autoDestroy){
106 me.store.un("add", me.onStoreAdd, me);
107 me.store.un("clear", me.onStoreClear, me);
108 me.store.un("remove", me.onStoreRemove, me);
109 me.store.un("update", me.onStoreUpdate, me);
113 store = Ext.data.StoreManager.lookup(store);
116 clear: me.onStoreClear,
117 remove: me.onStoreRemove,
118 update: me.onStoreUpdate,
123 if(store && !initial) {
128 <span id='Ext-selection-Model-method-selectAll'> /**
129 </span> * Select all records in the view.
130 * @param {Boolean} suppressEvent True to suppress any selects event
132 selectAll: function(suppressEvent) {
134 selections = me.store.getRange(),
136 len = selections.length,
137 start = me.getSelection().length;
139 me.bulkChange = true;
140 for (; i < len; i++) {
141 me.doSelect(selections[i], true, suppressEvent);
143 delete me.bulkChange;
144 // fire selection change only if the number of selections differs
145 me.maybeFireSelectionChange(me.getSelection().length !== start);
148 <span id='Ext-selection-Model-method-deselectAll'> /**
149 </span> * Deselect all records in the view.
150 * @param {Boolean} suppressEvent True to suppress any deselect events
152 deselectAll: function(suppressEvent) {
154 selections = me.getSelection(),
156 len = selections.length,
157 start = me.getSelection().length;
159 me.bulkChange = true;
160 for (; i < len; i++) {
161 me.doDeselect(selections[i], suppressEvent);
163 delete me.bulkChange;
164 // fire selection change only if the number of selections differs
165 me.maybeFireSelectionChange(me.getSelection().length !== start);
168 // Provides differentiation of logic between MULTI, SIMPLE and SINGLE
169 // selection modes. Requires that an event be passed so that we can know
170 // if user held ctrl or shift.
171 selectWithEvent: function(record, e) {
174 switch (me.selectionMode) {
176 if (e.ctrlKey && me.isSelected(record)) {
177 me.doDeselect(record, false);
178 } else if (e.shiftKey && me.lastFocused) {
179 me.selectRange(me.lastFocused, record, e.ctrlKey);
180 } else if (e.ctrlKey) {
181 me.doSelect(record, true, false);
182 } else if (me.isSelected(record) && !e.shiftKey && !e.ctrlKey && me.selected.getCount() > 1) {
183 me.doSelect(record, false, false);
185 me.doSelect(record, false);
189 if (me.isSelected(record)) {
190 me.doDeselect(record);
192 me.doSelect(record, true);
196 // if allowDeselect is on and this record isSelected, deselect it
197 if (me.allowDeselect && me.isSelected(record)) {
198 me.doDeselect(record);
199 // select the record and do NOT maintain existing selections
201 me.doSelect(record, false);
207 <span id='Ext-selection-Model-method-selectRange'> /**
208 </span> * Selects a range of rows if the selection model {@link #isLocked is not locked}.
209 * All rows in between startRow and endRow are also selected.
210 * @param {Ext.data.Model/Number} startRow The record or index of the first row in the range
211 * @param {Ext.data.Model/Number} endRow The record or index of the last row in the range
212 * @param {Boolean} keepExisting (optional) True to retain existing selections
214 selectRange : function(startRow, endRow, keepExisting, dir){
228 me.clearSelections();
231 if (!Ext.isNumber(startRow)) {
232 startRow = store.indexOf(startRow);
234 if (!Ext.isNumber(endRow)) {
235 endRow = store.indexOf(endRow);
239 if (startRow > endRow){
245 for (i = startRow; i <= endRow; i++) {
246 if (me.isSelected(store.getAt(i))) {
254 dontDeselect = (dir == 'up') ? startRow : endRow;
257 for (i = startRow; i <= endRow; i++){
258 if (selectedCount == (endRow - startRow + 1)) {
259 if (i != dontDeselect) {
260 me.doDeselect(i, true);
263 records.push(store.getAt(i));
266 me.doMultiSelect(records, true);
269 <span id='Ext-selection-Model-method-select'> /**
270 </span> * Selects a record instance by record instance or index.
271 * @param {Ext.data.Model/Index} records An array of records or an index
272 * @param {Boolean} keepExisting
273 * @param {Boolean} suppressEvent Set to false to not fire a select event
275 select: function(records, keepExisting, suppressEvent) {
276 this.doSelect(records, keepExisting, suppressEvent);
279 <span id='Ext-selection-Model-method-deselect'> /**
280 </span> * Deselects a record instance by record instance or index.
281 * @param {Ext.data.Model/Index} records An array of records or an index
282 * @param {Boolean} suppressEvent Set to false to not fire a deselect event
284 deselect: function(records, suppressEvent) {
285 this.doDeselect(records, suppressEvent);
288 doSelect: function(records, keepExisting, suppressEvent) {
295 if (typeof records === "number") {
296 records = [me.store.getAt(records)];
298 if (me.selectionMode == "SINGLE" && records) {
299 record = records.length ? records[0] : records;
300 me.doSingleSelect(record, suppressEvent);
302 me.doMultiSelect(records, keepExisting, suppressEvent);
306 doMultiSelect: function(records, keepExisting, suppressEvent) {
308 selected = me.selected,
318 records = !Ext.isArray(records) ? [records] : records;
319 len = records.length;
320 if (!keepExisting && selected.getCount() > 0) {
322 me.doDeselect(me.getSelection(), suppressEvent);
325 for (; i < len; i++) {
327 if (keepExisting && me.isSelected(record)) {
331 me.lastSelected = record;
332 selected.add(record);
334 me.onSelectChange(record, true, suppressEvent);
336 me.setLastFocused(record, suppressEvent);
337 // fire selchange if there was a change and there is no suppressEvent flag
338 me.maybeFireSelectionChange(change && !suppressEvent);
341 // records can be an index, a record or an array of records
342 doDeselect: function(records, suppressEvent) {
344 selected = me.selected,
353 if (typeof records === "number") {
354 records = [me.store.getAt(records)];
357 records = !Ext.isArray(records) ? [records] : records;
358 len = records.length;
359 for (; i < len; i++) {
361 if (selected.remove(record)) {
362 if (me.lastSelected == record) {
363 me.lastSelected = selected.last();
365 me.onSelectChange(record, false, suppressEvent);
369 // fire selchange if there was a change and there is no suppressEvent flag
370 me.maybeFireSelectionChange(change && !suppressEvent);
373 doSingleSelect: function(record, suppressEvent) {
375 selected = me.selected;
381 // should we also check beforeselect?
382 if (me.isSelected(record)) {
385 if (selected.getCount() > 0) {
386 me.doDeselect(me.lastSelected, suppressEvent);
388 selected.add(record);
389 me.lastSelected = record;
390 me.onSelectChange(record, true, suppressEvent);
391 if (!suppressEvent) {
392 me.setLastFocused(record);
394 me.maybeFireSelectionChange(!suppressEvent);
397 <span id='Ext-selection-Model-method-setLastFocused'> /**
398 </span> * @param {Ext.data.Model} record
399 * Set a record as the last focused record. This does NOT mean
400 * that the record has been selected.
402 setLastFocused: function(record, supressFocus) {
404 recordBeforeLast = me.lastFocused;
405 me.lastFocused = record;
406 me.onLastFocusChanged(recordBeforeLast, record, supressFocus);
409 <span id='Ext-selection-Model-method-isFocused'> /**
410 </span> * Determines if this record is currently focused.
411 * @param Ext.data.Record record
413 isFocused: function(record) {
414 return record === this.getLastFocused();
418 // fire selection change as long as true is not passed
419 // into maybeFireSelectionChange
420 maybeFireSelectionChange: function(fireEvent) {
422 if (fireEvent && !me.bulkChange) {
423 me.fireEvent('selectionchange', me, me.getSelection());
427 <span id='Ext-selection-Model-method-getLastSelected'> /**
428 </span> * Returns the last selected record.
430 getLastSelected: function() {
431 return this.lastSelected;
434 getLastFocused: function() {
435 return this.lastFocused;
438 <span id='Ext-selection-Model-method-getSelection'> /**
439 </span> * Returns an array of the currently selected records.
441 getSelection: function() {
442 return this.selected.getRange();
445 <span id='Ext-selection-Model-method-getSelectionMode'> /**
446 </span> * Returns the current selectionMode. SINGLE, MULTI or SIMPLE.
448 getSelectionMode: function() {
449 return this.selectionMode;
452 <span id='Ext-selection-Model-method-setSelectionMode'> /**
453 </span> * Sets the current selectionMode. SINGLE, MULTI or SIMPLE.
455 setSelectionMode: function(selMode) {
456 selMode = selMode ? selMode.toUpperCase() : 'SINGLE';
457 // set to mode specified unless it doesnt exist, in that case
459 this.selectionMode = this.modes[selMode] ? selMode : 'SINGLE';
462 <span id='Ext-selection-Model-method-isLocked'> /**
463 </span> * Returns true if the selections are locked.
466 isLocked: function() {
470 <span id='Ext-selection-Model-method-setLocked'> /**
471 </span> * Locks the current selection and disables any changes from
472 * happening to the selection.
473 * @param {Boolean} locked
475 setLocked: function(locked) {
476 this.locked = !!locked;
479 <span id='Ext-selection-Model-method-isSelected'> /**
480 </span> * Returns <tt>true</tt> if the specified row is selected.
481 * @param {Record/Number} record The record or index of the record to check
484 isSelected: function(record) {
485 record = Ext.isNumber(record) ? this.store.getAt(record) : record;
486 return this.selected.indexOf(record) !== -1;
489 <span id='Ext-selection-Model-method-hasSelection'> /**
490 </span> * Returns true if there is a selected record.
493 hasSelection: function() {
494 return this.selected.getCount() > 0;
497 refresh: function() {
500 oldSelections = me.getSelection(),
501 len = oldSelections.length,
505 lastFocused = this.getLastFocused();
507 // check to make sure that there are no records
508 // missing after the refresh was triggered, prune
509 // them from what is to be selected if so
510 for (; i < len; i++) {
511 selection = oldSelections[i];
512 if (!this.pruneRemoved || me.store.indexOf(selection) !== -1) {
513 toBeSelected.push(selection);
517 // there was a change from the old selected and
519 if (me.selected.getCount() != toBeSelected.length) {
523 me.clearSelections();
525 if (me.store.indexOf(lastFocused) !== -1) {
526 // restore the last focus but supress restoring focus
527 this.setLastFocused(lastFocused, true);
530 if (toBeSelected.length) {
531 // perform the selection again
532 me.doSelect(toBeSelected, false, true);
535 me.maybeFireSelectionChange(change);
538 <span id='Ext-selection-Model-method-clearSelections'> /**
539 </span> * A fast reset of the selections without firing events, updating the ui, etc.
540 * For private usage only.
543 clearSelections: function() {
544 // reset the entire selection to nothing
547 me.lastSelected = null;
548 me.setLastFocused(null);
551 // when a record is added to a store
552 onStoreAdd: function() {
556 // when a store is cleared remove all selections
557 // (if there were any)
558 onStoreClear: function() {
560 selected = this.selected;
562 if (selected.getCount > 0) {
564 me.lastSelected = null;
565 me.setLastFocused(null);
566 me.maybeFireSelectionChange(true);
570 // prune records from the SelectionModel if
571 // they were selected at the time they were
573 onStoreRemove: function(store, record) {
575 selected = me.selected;
577 if (me.locked || !me.pruneRemoved) {
581 if (selected.remove(record)) {
582 if (me.lastSelected == record) {
583 me.lastSelected = null;
585 if (me.getLastFocused() == record) {
586 me.setLastFocused(null);
588 me.maybeFireSelectionChange(true);
592 getCount: function() {
593 return this.selected.getCount();
597 destroy: function() {
601 // if records are updated
602 onStoreUpdate: function() {
607 onSelectChange: function(record, isSelected, suppressEvent) {
612 onLastFocusChanged: function(oldFocused, newFocused) {
617 onEditorKey: function(field, e) {
622 bindComponent: function(cmp) {