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-util-AbstractMixedCollection'>/**
19 </span> * @class Ext.util.AbstractMixedCollection
21 Ext.define('Ext.util.AbstractMixedCollection', {
22 requires: ['Ext.util.Filter'],
25 observable: 'Ext.util.Observable'
28 constructor: function(allowFunctions, keyFn) {
37 <span id='Ext-util-AbstractMixedCollection-event-clear'> /**
38 </span> * @event clear
39 * Fires when the collection is cleared.
43 <span id='Ext-util-AbstractMixedCollection-event-add'> /**
45 * Fires when an item is added to the collection.
46 * @param {Number} index The index at which the item was added.
47 * @param {Object} o The item added.
48 * @param {String} key The key associated with the added item.
52 <span id='Ext-util-AbstractMixedCollection-event-replace'> /**
53 </span> * @event replace
54 * Fires when an item is replaced in the collection.
55 * @param {String} key he key associated with the new added.
56 * @param {Object} old The item being replaced.
57 * @param {Object} new The new item.
61 <span id='Ext-util-AbstractMixedCollection-event-remove'> /**
62 </span> * @event remove
63 * Fires when an item is removed from the collection.
64 * @param {Object} o The item being removed.
65 * @param {String} key (optional) The key associated with the removed item.
70 me.allowFunctions = allowFunctions === true;
76 me.mixins.observable.constructor.call(me);
79 <span id='Ext-util-AbstractMixedCollection-cfg-allowFunctions'> /**
80 </span> * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
81 * function should add function references to the collection. Defaults to
82 * <tt>false</tt>.
84 allowFunctions : false,
86 <span id='Ext-util-AbstractMixedCollection-method-add'> /**
87 </span> * Adds an item to the collection. Fires the {@link #add} event when complete.
88 * @param {String} key <p>The key to associate with the item, or the new item.</p>
89 * <p>If a {@link #getKey} implementation was specified for this MixedCollection,
90 * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
91 * the MixedCollection will be able to <i>derive</i> the key for the new item.
92 * In this case just pass the new item in this parameter.</p>
93 * @param {Object} o The item to add.
94 * @return {Object} The item added.
96 add : function(key, obj){
102 if (arguments.length == 1) {
104 myKey = me.getKey(myObj);
106 if (typeof myKey != 'undefined' && myKey !== null) {
108 if (typeof old != 'undefined') {
109 return me.replace(myKey, myObj);
111 me.map[myKey] = myObj;
114 me.items.push(myObj);
116 me.fireEvent('add', me.length - 1, myObj, myKey);
120 <span id='Ext-util-AbstractMixedCollection-method-getKey'> /**
121 </span> * MixedCollection has a generic way to fetch keys if you implement getKey. The default implementation
122 * simply returns <b><code>item.id</code></b> but you can provide your own implementation
123 * to return a different value as in the following examples:<pre><code>
125 var mc = new Ext.util.MixedCollection();
126 mc.add(someEl.dom.id, someEl);
127 mc.add(otherEl.dom.id, otherEl);
131 var mc = new Ext.util.MixedCollection();
132 mc.getKey = function(el){
138 // or via the constructor
139 var mc = new Ext.util.MixedCollection(false, function(el){
144 * </code></pre>
145 * @param {Object} item The item for which to find the key.
146 * @return {Object} The key for the passed item.
148 getKey : function(o){
152 <span id='Ext-util-AbstractMixedCollection-method-replace'> /**
153 </span> * Replaces an item in the collection. Fires the {@link #replace} event when complete.
154 * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
155 * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
156 * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
157 * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
158 * with one having the same key value, then just pass the replacement item in this parameter.</p>
159 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
161 * @return {Object} The new item.
163 replace : function(key, o){
168 if (arguments.length == 1) {
173 if (typeof key == 'undefined' || key === null || typeof old == 'undefined') {
174 return me.add(key, o);
176 index = me.indexOfKey(key);
179 me.fireEvent('replace', key, old, o);
183 <span id='Ext-util-AbstractMixedCollection-method-addAll'> /**
184 </span> * Adds all elements of an Array or an Object to the collection.
185 * @param {Object/Array} objs An Object containing properties which will be added
186 * to the collection, or an Array of values, each of which are added to the collection.
187 * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>
188 * has been set to <tt>true</tt>.
190 addAll : function(objs){
197 if (arguments.length > 1 || Ext.isArray(objs)) {
198 args = arguments.length > 1 ? arguments : objs;
199 for (len = args.length; i < len; i++) {
204 if (objs.hasOwnProperty(key)) {
205 if (me.allowFunctions || typeof objs[key] != 'function') {
206 me.add(key, objs[key]);
213 <span id='Ext-util-AbstractMixedCollection-method-each'> /**
214 </span> * Executes the specified function once for every item in the collection, passing the following arguments:
215 * <div class="mdetail-params"><ul>
216 * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
217 * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
218 * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
219 * </ul></div>
220 * The function should return a boolean value. Returning false from the function will stop the iteration.
221 * @param {Function} fn The function to execute for each item.
222 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current item in the iteration.
224 each : function(fn, scope){
225 var items = [].concat(this.items), // each safe for removal
230 for (; i < len; i++) {
232 if (fn.call(scope || item, item, i, len) === false) {
238 <span id='Ext-util-AbstractMixedCollection-method-eachKey'> /**
239 </span> * Executes the specified function once for every key in the collection, passing each
240 * key, and its associated item as the first two parameters.
241 * @param {Function} fn The function to execute for each item.
242 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
244 eachKey : function(fn, scope){
245 var keys = this.keys,
250 for (; i < len; i++) {
251 fn.call(scope || window, keys[i], items[i], i, len);
255 <span id='Ext-util-AbstractMixedCollection-method-findBy'> /**
256 </span> * Returns the first item in the collection which elicits a true return value from the
257 * passed selection function.
258 * @param {Function} fn The selection function to execute for each item.
259 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
260 * @return {Object} The first item in the collection which returned true from the selection function.
262 findBy : function(fn, scope) {
263 var keys = this.keys,
268 for (; i < len; i++) {
269 if (fn.call(scope || window, items[i], keys[i])) {
276 //<deprecated since="0.99">
278 if (Ext.isDefined(Ext.global.console)) {
279 Ext.global.console.warn('Ext.util.MixedCollection: find has been deprecated. Use findBy instead.');
281 return this.findBy.apply(this, arguments);
283 //</deprecated>
285 <span id='Ext-util-AbstractMixedCollection-method-insert'> /**
286 </span> * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
287 * @param {Number} index The index to insert the item at.
288 * @param {String} key The key to associate with the new item, or the item itself.
289 * @param {Object} o (optional) If the second parameter was a key, the new item.
290 * @return {Object} The item inserted.
292 insert : function(index, key, obj){
297 if (arguments.length == 2) {
299 myKey = me.getKey(myObj);
301 if (me.containsKey(myKey)) {
303 me.removeAtKey(myKey);
306 if (index >= me.length) {
307 return me.add(myKey, myObj);
310 me.items.splice(index, 0, myObj);
311 if (typeof myKey != 'undefined' && myKey !== null) {
312 me.map[myKey] = myObj;
314 me.keys.splice(index, 0, myKey);
315 me.fireEvent('add', index, myObj, myKey);
319 <span id='Ext-util-AbstractMixedCollection-method-remove'> /**
320 </span> * Remove an item from the collection.
321 * @param {Object} o The item to remove.
322 * @return {Object} The item removed or false if no item was removed.
324 remove : function(o){
325 return this.removeAt(this.indexOf(o));
328 <span id='Ext-util-AbstractMixedCollection-method-removeAll'> /**
329 </span> * Remove all items in the passed array from the collection.
330 * @param {Array} items An array of items to be removed.
331 * @return {Ext.util.MixedCollection} this object
333 removeAll : function(items){
334 Ext.each(items || [], function(item) {
341 <span id='Ext-util-AbstractMixedCollection-method-removeAt'> /**
342 </span> * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
343 * @param {Number} index The index within the collection of the item to remove.
344 * @return {Object} The item removed or false if no item was removed.
346 removeAt : function(index){
351 if (index < me.length && index >= 0) {
354 me.items.splice(index, 1);
355 key = me.keys[index];
356 if (typeof key != 'undefined') {
359 me.keys.splice(index, 1);
360 me.fireEvent('remove', o, key);
366 <span id='Ext-util-AbstractMixedCollection-method-removeAtKey'> /**
367 </span> * Removed an item associated with the passed key fom the collection.
368 * @param {String} key The key of the item to remove.
369 * @return {Object} The item removed or false if no item was removed.
371 removeAtKey : function(key){
372 return this.removeAt(this.indexOfKey(key));
375 <span id='Ext-util-AbstractMixedCollection-method-getCount'> /**
376 </span> * Returns the number of items in the collection.
377 * @return {Number} the number of items in the collection.
379 getCount : function(){
383 <span id='Ext-util-AbstractMixedCollection-method-indexOf'> /**
384 </span> * Returns index within the collection of the passed Object.
385 * @param {Object} o The item to find the index of.
386 * @return {Number} index of the item. Returns -1 if not found.
388 indexOf : function(o){
389 return Ext.Array.indexOf(this.items, o);
392 <span id='Ext-util-AbstractMixedCollection-method-indexOfKey'> /**
393 </span> * Returns index within the collection of the passed key.
394 * @param {String} key The key to find the index of.
395 * @return {Number} index of the key.
397 indexOfKey : function(key){
398 return Ext.Array.indexOf(this.keys, key);
401 <span id='Ext-util-AbstractMixedCollection-method-get'> /**
402 </span> * Returns the item associated with the passed key OR index.
403 * Key has priority over index. This is the equivalent
404 * of calling {@link #key} first, then if nothing matched calling {@link #getAt}.
405 * @param {String/Number} key The key or index of the item.
406 * @return {Object} If the item is found, returns the item. If the item was not found, returns <tt>undefined</tt>.
407 * If an item was found, but is a Class, returns <tt>null</tt>.
409 get : function(key) {
412 item = mk !== undefined ? mk : (typeof key == 'number') ? me.items[key] : undefined;
413 return typeof item != 'function' || me.allowFunctions ? item : null; // for prototype!
416 <span id='Ext-util-AbstractMixedCollection-method-getAt'> /**
417 </span> * Returns the item at the specified index.
418 * @param {Number} index The index of the item.
419 * @return {Object} The item at the specified index.
421 getAt : function(index) {
422 return this.items[index];
425 <span id='Ext-util-AbstractMixedCollection-method-getByKey'> /**
426 </span> * Returns the item associated with the passed key.
427 * @param {String/Number} key The key of the item.
428 * @return {Object} The item associated with the passed key.
430 getByKey : function(key) {
431 return this.map[key];
434 <span id='Ext-util-AbstractMixedCollection-method-contains'> /**
435 </span> * Returns true if the collection contains the passed Object as an item.
436 * @param {Object} o The Object to look for in the collection.
437 * @return {Boolean} True if the collection contains the Object as an item.
439 contains : function(o){
440 return Ext.Array.contains(this.items, o);
443 <span id='Ext-util-AbstractMixedCollection-method-containsKey'> /**
444 </span> * Returns true if the collection contains the passed Object as a key.
445 * @param {String} key The key to look for in the collection.
446 * @return {Boolean} True if the collection contains the Object as a key.
448 containsKey : function(key){
449 return typeof this.map[key] != 'undefined';
452 <span id='Ext-util-AbstractMixedCollection-method-clear'> /**
453 </span> * Removes all items from the collection. Fires the {@link #clear} event when complete.
462 me.fireEvent('clear');
465 <span id='Ext-util-AbstractMixedCollection-method-first'> /**
466 </span> * Returns the first item in the collection.
467 * @return {Object} the first item in the collection..
470 return this.items[0];
473 <span id='Ext-util-AbstractMixedCollection-method-last'> /**
474 </span> * Returns the last item in the collection.
475 * @return {Object} the last item in the collection..
478 return this.items[this.length - 1];
481 <span id='Ext-util-AbstractMixedCollection-method-sum'> /**
482 </span> * Collects all of the values of the given property and returns their sum
483 * @param {String} property The property to sum by
484 * @param {String} root Optional 'root' property to extract the first argument from. This is used mainly when
485 * summing fields in records, where the fields are all stored inside the 'data' object
486 * @param {Number} start (optional) The record index to start at (defaults to <tt>0</tt>)
487 * @param {Number} end (optional) The record index to end at (defaults to <tt>-1</tt>)
488 * @return {Number} The total
490 sum: function(property, root, start, end) {
491 var values = this.extractValues(property, root),
492 length = values.length,
497 end = (end || end === 0) ? end : length - 1;
499 for (i = start; i <= end; i++) {
506 <span id='Ext-util-AbstractMixedCollection-method-collect'> /**
507 </span> * Collects unique values of a particular property in this MixedCollection
508 * @param {String} property The property to collect on
509 * @param {String} root Optional 'root' property to extract the first argument from. This is used mainly when
510 * summing fields in records, where the fields are all stored inside the 'data' object
511 * @param {Boolean} allowBlank (optional) Pass true to allow null, undefined or empty string values
512 * @return {Array} The unique values
514 collect: function(property, root, allowNull) {
515 var values = this.extractValues(property, root),
516 length = values.length,
521 for (i = 0; i < length; i++) {
523 strValue = String(value);
525 if ((allowNull || !Ext.isEmpty(value)) && !hits[strValue]) {
526 hits[strValue] = true;
534 <span id='Ext-util-AbstractMixedCollection-method-extractValues'> /**
536 * Extracts all of the given property values from the items in the MC. Mainly used as a supporting method for
537 * functions like sum and collect.
538 * @param {String} property The property to extract
539 * @param {String} root Optional 'root' property to extract the first argument from. This is used mainly when
540 * extracting field data from Model instances, where the fields are stored inside the 'data' object
541 * @return {Array} The extracted values
543 extractValues: function(property, root) {
544 var values = this.items;
547 values = Ext.Array.pluck(values, root);
550 return Ext.Array.pluck(values, property);
553 <span id='Ext-util-AbstractMixedCollection-method-getRange'> /**
554 </span> * Returns a range of items in this collection
555 * @param {Number} startIndex (optional) The starting index. Defaults to 0.
556 * @param {Number} endIndex (optional) The ending index. Defaults to the last item.
557 * @return {Array} An array of items
559 getRange : function(start, end){
565 if (items.length < 1) {
570 end = Math.min(typeof end == 'undefined' ? me.length - 1 : end, me.length - 1);
571 if (start <= end) {
572 for (i = start; i <= end; i++) {
573 range[range.length] = items[i];
576 for (i = start; i >= end; i--) {
577 range[range.length] = items[i];
583 <span id='Ext-util-AbstractMixedCollection-method-filter'> /**
584 </span> * <p>Filters the objects in this collection by a set of {@link Ext.util.Filter Filter}s, or by a single
585 * property/value pair with optional parameters for substring matching and case sensitivity. See
586 * {@link Ext.util.Filter Filter} for an example of using Filter objects (preferred). Alternatively,
587 * MixedCollection can be easily filtered by property like this:</p>
588 <pre><code>
589 //create a simple store with a few people defined
590 var people = new Ext.util.MixedCollection();
592 {id: 1, age: 25, name: 'Ed'},
593 {id: 2, age: 24, name: 'Tommy'},
594 {id: 3, age: 24, name: 'Arne'},
595 {id: 4, age: 26, name: 'Aaron'}
598 //a new MixedCollection containing only the items where age == 24
599 var middleAged = people.filter('age', 24);
600 </code></pre>
603 * @param {Array/String} property A property on your objects, or an array of {@link Ext.util.Filter Filter} objects
604 * @param {String/RegExp} value Either string that the property values
605 * should start with or a RegExp to test against the property
606 * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
607 * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).
608 * @return {MixedCollection} The new filtered collection
610 filter : function(property, value, anyMatch, caseSensitive) {
614 //support for the simple case of filtering by property/value
615 if (Ext.isString(property)) {
616 filters.push(Ext.create('Ext.util.Filter', {
620 caseSensitive: caseSensitive
622 } else if (Ext.isArray(property) || property instanceof Ext.util.Filter) {
623 filters = filters.concat(property);
626 //at this point we have an array of zero or more Ext.util.Filter objects to filter with,
627 //so here we construct a function that combines these filters by ANDing them together
628 filterFn = function(record) {
630 length = filters.length,
633 for (i = 0; i < length; i++) {
634 var filter = filters[i],
635 fn = filter.filterFn,
636 scope = filter.scope;
638 isMatch = isMatch && fn.call(scope, record);
644 return this.filterBy(filterFn);
647 <span id='Ext-util-AbstractMixedCollection-method-filterBy'> /**
648 </span> * Filter by a function. Returns a <i>new</i> collection that has been filtered.
649 * The passed function will be called with each object in the collection.
650 * If the function returns true, the value is included otherwise it is filtered.
651 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
652 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
653 * @return {MixedCollection} The new filtered collection
655 filterBy : function(fn, scope) {
657 newMC = new this.self(),
660 length = items.length,
663 newMC.getKey = me.getKey;
665 for (i = 0; i < length; i++) {
666 if (fn.call(scope || me, items[i], keys[i])) {
667 newMC.add(keys[i], items[i]);
674 <span id='Ext-util-AbstractMixedCollection-method-findIndex'> /**
675 </span> * Finds the index of the first matching object in this collection by a specific property/value.
676 * @param {String} property The name of a property on your objects.
677 * @param {String/RegExp} value A string that the property values
678 * should start with or a RegExp to test against the property.
679 * @param {Number} start (optional) The index to start searching at (defaults to 0).
680 * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.
681 * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.
682 * @return {Number} The matched index or -1
684 findIndex : function(property, value, start, anyMatch, caseSensitive){
685 if(Ext.isEmpty(value, false)){
688 value = this.createValueMatcher(value, anyMatch, caseSensitive);
689 return this.findIndexBy(function(o){
690 return o && value.test(o[property]);
694 <span id='Ext-util-AbstractMixedCollection-method-findIndexBy'> /**
695 </span> * Find the index of the first matching object in this collection by a function.
696 * If the function returns <i>true</i> it is considered a match.
697 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
698 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
699 * @param {Number} start (optional) The index to start searching at (defaults to 0).
700 * @return {Number} The matched index or -1
702 findIndexBy : function(fn, scope, start){
709 for (; i < len; i++) {
710 if (fn.call(scope || me, items[i], keys[i])) {
717 <span id='Ext-util-AbstractMixedCollection-method-createValueMatcher'> /**
718 </span> * Returns a regular expression based on the given value and matching options. This is used internally for finding and filtering,
719 * and by Ext.data.Store#filter
721 * @param {String} value The value to create the regex for. This is escaped using Ext.escapeRe
722 * @param {Boolean} anyMatch True to allow any match - no regex start/end line anchors will be added. Defaults to false
723 * @param {Boolean} caseSensitive True to make the regex case sensitive (adds 'i' switch to regex). Defaults to false.
724 * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false. Ignored if anyMatch is true.
726 createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {
727 if (!value.exec) { // not a regex
728 var er = Ext.String.escapeRegex;
729 value = String(value);
731 if (anyMatch === true) {
734 value = '^' + er(value);
735 if (exactMatch === true) {
739 value = new RegExp(value, caseSensitive ? '' : 'i');
744 <span id='Ext-util-AbstractMixedCollection-method-clone'> /**
745 </span> * Creates a shallow copy of this collection
746 * @return {MixedCollection}
750 copy = new this.self(),
756 for(; i < len; i++){
757 copy.add(keys[i], items[i]);
759 copy.getKey = me.getKey;