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.AbstractSelectionModel',
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, keepExisting) {
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, keepExisting, 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.deselectAll(true);
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) {
321 if (me.doDeselect(me.getSelection(), suppressEvent) === false) {
324 // TODO - coalesce the selectionchange event in deselect w/the one below...
328 selected.add(record);
332 for (; i < len; i++) {
334 if (keepExisting && me.isSelected(record)) {
337 me.lastSelected = record;
339 me.onSelectChange(record, true, suppressEvent, commit);
341 me.setLastFocused(record, suppressEvent);
342 // fire selchange if there was a change and there is no suppressEvent flag
343 me.maybeFireSelectionChange(change && !suppressEvent);
346 // records can be an index, a record or an array of records
347 doDeselect: function(records, suppressEvent) {
349 selected = me.selected,
359 if (typeof records === "number") {
360 records = [me.store.getAt(records)];
361 } else if (!Ext.isArray(records)) {
367 selected.remove(record);
370 len = records.length;
372 for (; i < len; i++) {
374 if (me.isSelected(record)) {
375 if (me.lastSelected == record) {
376 me.lastSelected = selected.last();
379 me.onSelectChange(record, false, suppressEvent, commit);
383 // fire selchange if there was a change and there is no suppressEvent flag
384 me.maybeFireSelectionChange(accepted > 0 && !suppressEvent);
385 return accepted === attempted;
388 doSingleSelect: function(record, suppressEvent) {
391 selected = me.selected;
397 // should we also check beforeselect?
398 if (me.isSelected(record)) {
403 me.bulkChange = true;
404 if (selected.getCount() > 0 && me.doDeselect(me.lastSelected, suppressEvent) === false) {
405 delete me.bulkChange;
408 delete me.bulkChange;
410 selected.add(record);
411 me.lastSelected = record;
415 me.onSelectChange(record, true, suppressEvent, commit);
418 if (!suppressEvent) {
419 me.setLastFocused(record);
421 me.maybeFireSelectionChange(!suppressEvent);
425 <span id='Ext-selection-Model-method-setLastFocused'> /**
426 </span> * @param {Ext.data.Model} record
427 * Set a record as the last focused record. This does NOT mean
428 * that the record has been selected.
430 setLastFocused: function(record, supressFocus) {
432 recordBeforeLast = me.lastFocused;
433 me.lastFocused = record;
434 me.onLastFocusChanged(recordBeforeLast, record, supressFocus);
437 <span id='Ext-selection-Model-method-isFocused'> /**
438 </span> * Determines if this record is currently focused.
439 * @param Ext.data.Record record
441 isFocused: function(record) {
442 return record === this.getLastFocused();
446 // fire selection change as long as true is not passed
447 // into maybeFireSelectionChange
448 maybeFireSelectionChange: function(fireEvent) {
450 if (fireEvent && !me.bulkChange) {
451 me.fireEvent('selectionchange', me, me.getSelection());
455 <span id='Ext-selection-Model-method-getLastSelected'> /**
456 </span> * Returns the last selected record.
458 getLastSelected: function() {
459 return this.lastSelected;
462 getLastFocused: function() {
463 return this.lastFocused;
466 <span id='Ext-selection-Model-method-getSelection'> /**
467 </span> * Returns an array of the currently selected records.
468 * @return {Array} The selected records
470 getSelection: function() {
471 return this.selected.getRange();
474 <span id='Ext-selection-Model-method-getSelectionMode'> /**
475 </span> * Returns the current selectionMode. SINGLE, MULTI or SIMPLE.
476 * @return {String} The selectionMode
478 getSelectionMode: function() {
479 return this.selectionMode;
482 <span id='Ext-selection-Model-method-setSelectionMode'> /**
483 </span> * Sets the current selectionMode. SINGLE, MULTI or SIMPLE.
485 setSelectionMode: function(selMode) {
486 selMode = selMode ? selMode.toUpperCase() : 'SINGLE';
487 // set to mode specified unless it doesnt exist, in that case
489 this.selectionMode = this.modes[selMode] ? selMode : 'SINGLE';
492 <span id='Ext-selection-Model-method-isLocked'> /**
493 </span> * Returns true if the selections are locked.
496 isLocked: function() {
500 <span id='Ext-selection-Model-method-setLocked'> /**
501 </span> * Locks the current selection and disables any changes from
502 * happening to the selection.
503 * @param {Boolean} locked
505 setLocked: function(locked) {
506 this.locked = !!locked;
509 <span id='Ext-selection-Model-method-isSelected'> /**
510 </span> * Returns <tt>true</tt> if the specified row is selected.
511 * @param {Record/Number} record The record or index of the record to check
514 isSelected: function(record) {
515 record = Ext.isNumber(record) ? this.store.getAt(record) : record;
516 return this.selected.indexOf(record) !== -1;
519 <span id='Ext-selection-Model-method-hasSelection'> /**
520 </span> * Returns true if there are any a selected records.
523 hasSelection: function() {
524 return this.selected.getCount() > 0;
527 refresh: function() {
530 oldSelections = me.getSelection(),
531 len = oldSelections.length,
535 lastFocused = this.getLastFocused();
537 // check to make sure that there are no records
538 // missing after the refresh was triggered, prune
539 // them from what is to be selected if so
540 for (; i < len; i++) {
541 selection = oldSelections[i];
542 if (!this.pruneRemoved || me.store.indexOf(selection) !== -1) {
543 toBeSelected.push(selection);
547 // there was a change from the old selected and
549 if (me.selected.getCount() != toBeSelected.length) {
553 me.clearSelections();
555 if (me.store.indexOf(lastFocused) !== -1) {
556 // restore the last focus but supress restoring focus
557 this.setLastFocused(lastFocused, true);
560 if (toBeSelected.length) {
561 // perform the selection again
562 me.doSelect(toBeSelected, false, true);
565 me.maybeFireSelectionChange(change);
568 <span id='Ext-selection-Model-method-clearSelections'> /**
569 </span> * A fast reset of the selections without firing events, updating the ui, etc.
570 * For private usage only.
573 clearSelections: function() {
574 // reset the entire selection to nothing
575 this.selected.clear();
576 this.lastSelected = null;
577 this.setLastFocused(null);
580 // when a record is added to a store
581 onStoreAdd: function() {
585 // when a store is cleared remove all selections
586 // (if there were any)
587 onStoreClear: function() {
588 if (this.selected.getCount > 0) {
589 this.clearSelections();
590 this.maybeFireSelectionChange(true);
594 // prune records from the SelectionModel if
595 // they were selected at the time they were
597 onStoreRemove: function(store, record) {
599 selected = me.selected;
601 if (me.locked || !me.pruneRemoved) {
605 if (selected.remove(record)) {
606 if (me.lastSelected == record) {
607 me.lastSelected = null;
609 if (me.getLastFocused() == record) {
610 me.setLastFocused(null);
612 me.maybeFireSelectionChange(true);
616 <span id='Ext-selection-Model-method-getCount'> /**
617 </span> * Gets the count of selected records.
618 * @return {Number} The number of selected records
620 getCount: function() {
621 return this.selected.getCount();
625 destroy: function() {
629 // if records are updated
630 onStoreUpdate: function() {
635 onSelectChange: function(record, isSelected, suppressEvent) {
640 onLastFocusChanged: function(oldFocused, newFocused) {
645 onEditorKey: function(field, e) {
650 bindComponent: function(cmp) {