4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../resources/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
22 Ext.define('Ext.util.AbstractMixedCollection', {
23 requires: ['Ext.util.Filter'],
26 observable: 'Ext.util.Observable'
29 constructor: function(allowFunctions, keyFn) {
38 <span id='Ext-util-AbstractMixedCollection-event-clear'> /**
39 </span> * @event clear
40 * Fires when the collection is cleared.
44 <span id='Ext-util-AbstractMixedCollection-event-add'> /**
46 * Fires when an item is added to the collection.
47 * @param {Number} index The index at which the item was added.
48 * @param {Object} o The item added.
49 * @param {String} key The key associated with the added item.
53 <span id='Ext-util-AbstractMixedCollection-event-replace'> /**
54 </span> * @event replace
55 * Fires when an item is replaced in the collection.
56 * @param {String} key he key associated with the new added.
57 * @param {Object} old The item being replaced.
58 * @param {Object} new The new item.
62 <span id='Ext-util-AbstractMixedCollection-event-remove'> /**
63 </span> * @event remove
64 * Fires when an item is removed from the collection.
65 * @param {Object} o The item being removed.
66 * @param {String} key (optional) The key associated with the removed item.
71 me.allowFunctions = allowFunctions === true;
77 me.mixins.observable.constructor.call(me);
80 <span id='Ext-util-AbstractMixedCollection-cfg-allowFunctions'> /**
81 </span> * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
82 * function should add function references to the collection. Defaults to
83 * <tt>false</tt>.
85 allowFunctions : false,
87 <span id='Ext-util-AbstractMixedCollection-method-add'> /**
88 </span> * Adds an item to the collection. Fires the {@link #add} event when complete.
89 * @param {String} key <p>The key to associate with the item, or the new item.</p>
90 * <p>If a {@link #getKey} implementation was specified for this MixedCollection,
91 * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
92 * the MixedCollection will be able to <i>derive</i> the key for the new item.
93 * In this case just pass the new item in this parameter.</p>
94 * @param {Object} o The item to add.
95 * @return {Object} The item added.
97 add : function(key, obj){
103 if (arguments.length == 1) {
105 myKey = me.getKey(myObj);
107 if (typeof myKey != 'undefined' && myKey !== null) {
109 if (typeof old != 'undefined') {
110 return me.replace(myKey, myObj);
112 me.map[myKey] = myObj;
115 me.items.push(myObj);
117 me.fireEvent('add', me.length - 1, myObj, myKey);
121 <span id='Ext-util-AbstractMixedCollection-method-getKey'> /**
122 </span> * MixedCollection has a generic way to fetch keys if you implement getKey. The default implementation
123 * simply returns <b><code>item.id</code></b> but you can provide your own implementation
124 * to return a different value as in the following examples:<pre><code>
126 var mc = new Ext.util.MixedCollection();
127 mc.add(someEl.dom.id, someEl);
128 mc.add(otherEl.dom.id, otherEl);
132 var mc = new Ext.util.MixedCollection();
133 mc.getKey = function(el){
139 // or via the constructor
140 var mc = new Ext.util.MixedCollection(false, function(el){
145 * </code></pre>
146 * @param {Object} item The item for which to find the key.
147 * @return {Object} The key for the passed item.
149 getKey : function(o){
153 <span id='Ext-util-AbstractMixedCollection-method-replace'> /**
154 </span> * Replaces an item in the collection. Fires the {@link #replace} event when complete.
155 * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
156 * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
157 * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
158 * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
159 * with one having the same key value, then just pass the replacement item in this parameter.</p>
160 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
162 * @return {Object} The new item.
164 replace : function(key, o){
169 if (arguments.length == 1) {
174 if (typeof key == 'undefined' || key === null || typeof old == 'undefined') {
175 return me.add(key, o);
177 index = me.indexOfKey(key);
180 me.fireEvent('replace', key, old, o);
184 <span id='Ext-util-AbstractMixedCollection-method-addAll'> /**
185 </span> * Adds all elements of an Array or an Object to the collection.
186 * @param {Object/Array} objs An Object containing properties which will be added
187 * to the collection, or an Array of values, each of which are added to the collection.
188 * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>
189 * has been set to <tt>true</tt>.
191 addAll : function(objs){
198 if (arguments.length > 1 || Ext.isArray(objs)) {
199 args = arguments.length > 1 ? arguments : objs;
200 for (len = args.length; i < len; i++) {
205 if (objs.hasOwnProperty(key)) {
206 if (me.allowFunctions || typeof objs[key] != 'function') {
207 me.add(key, objs[key]);
214 <span id='Ext-util-AbstractMixedCollection-method-each'> /**
215 </span> * Executes the specified function once for every item in the collection, passing the following arguments:
216 * <div class="mdetail-params"><ul>
217 * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
218 * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
219 * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
220 * </ul></div>
221 * The function should return a boolean value. Returning false from the function will stop the iteration.
222 * @param {Function} fn The function to execute for each item.
223 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current item in the iteration.
225 each : function(fn, scope){
226 var items = [].concat(this.items), // each safe for removal
231 for (; i < len; i++) {
233 if (fn.call(scope || item, item, i, len) === false) {
239 <span id='Ext-util-AbstractMixedCollection-method-eachKey'> /**
240 </span> * Executes the specified function once for every key in the collection, passing each
241 * key, and its associated item as the first two parameters.
242 * @param {Function} fn The function to execute for each item.
243 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
245 eachKey : function(fn, scope){
246 var keys = this.keys,
251 for (; i < len; i++) {
252 fn.call(scope || window, keys[i], items[i], i, len);
256 <span id='Ext-util-AbstractMixedCollection-method-findBy'> /**
257 </span> * Returns the first item in the collection which elicits a true return value from the
258 * passed selection function.
259 * @param {Function} fn The selection function to execute for each item.
260 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
261 * @return {Object} The first item in the collection which returned true from the selection function, or null if none was found
263 findBy : function(fn, scope) {
264 var keys = this.keys,
269 for (; i < len; i++) {
270 if (fn.call(scope || window, items[i], keys[i])) {
277 //<deprecated since="0.99">
279 if (Ext.isDefined(Ext.global.console)) {
280 Ext.global.console.warn('Ext.util.MixedCollection: find has been deprecated. Use findBy instead.');
282 return this.findBy.apply(this, arguments);
284 //</deprecated>
286 <span id='Ext-util-AbstractMixedCollection-method-insert'> /**
287 </span> * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
288 * @param {Number} index The index to insert the item at.
289 * @param {String} key The key to associate with the new item, or the item itself.
290 * @param {Object} o (optional) If the second parameter was a key, the new item.
291 * @return {Object} The item inserted.
293 insert : function(index, key, obj){
298 if (arguments.length == 2) {
300 myKey = me.getKey(myObj);
302 if (me.containsKey(myKey)) {
304 me.removeAtKey(myKey);
307 if (index >= me.length) {
308 return me.add(myKey, myObj);
311 Ext.Array.splice(me.items, index, 0, myObj);
312 if (typeof myKey != 'undefined' && myKey !== null) {
313 me.map[myKey] = myObj;
315 Ext.Array.splice(me.keys, index, 0, myKey);
316 me.fireEvent('add', index, myObj, myKey);
320 <span id='Ext-util-AbstractMixedCollection-method-remove'> /**
321 </span> * Remove an item from the collection.
322 * @param {Object} o The item to remove.
323 * @return {Object} The item removed or false if no item was removed.
325 remove : function(o){
326 return this.removeAt(this.indexOf(o));
329 <span id='Ext-util-AbstractMixedCollection-method-removeAll'> /**
330 </span> * Remove all items in the passed array from the collection.
331 * @param {Array} items An array of items to be removed.
332 * @return {Ext.util.MixedCollection} this object
334 removeAll : function(items){
335 Ext.each(items || [], function(item) {
342 <span id='Ext-util-AbstractMixedCollection-method-removeAt'> /**
343 </span> * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
344 * @param {Number} index The index within the collection of the item to remove.
345 * @return {Object} The item removed or false if no item was removed.
347 removeAt : function(index){
352 if (index < me.length && index >= 0) {
355 Ext.Array.erase(me.items, index, 1);
356 key = me.keys[index];
357 if (typeof key != 'undefined') {
360 Ext.Array.erase(me.keys, index, 1);
361 me.fireEvent('remove', o, key);
367 <span id='Ext-util-AbstractMixedCollection-method-removeAtKey'> /**
368 </span> * Removed an item associated with the passed key fom the collection.
369 * @param {String} key The key of the item to remove.
370 * @return {Object} The item removed or false if no item was removed.
372 removeAtKey : function(key){
373 return this.removeAt(this.indexOfKey(key));
376 <span id='Ext-util-AbstractMixedCollection-method-getCount'> /**
377 </span> * Returns the number of items in the collection.
378 * @return {Number} the number of items in the collection.
380 getCount : function(){
384 <span id='Ext-util-AbstractMixedCollection-method-indexOf'> /**
385 </span> * Returns index within the collection of the passed Object.
386 * @param {Object} o The item to find the index of.
387 * @return {Number} index of the item. Returns -1 if not found.
389 indexOf : function(o){
390 return Ext.Array.indexOf(this.items, o);
393 <span id='Ext-util-AbstractMixedCollection-method-indexOfKey'> /**
394 </span> * Returns index within the collection of the passed key.
395 * @param {String} key The key to find the index of.
396 * @return {Number} index of the key.
398 indexOfKey : function(key){
399 return Ext.Array.indexOf(this.keys, key);
402 <span id='Ext-util-AbstractMixedCollection-method-get'> /**
403 </span> * Returns the item associated with the passed key OR index.
404 * Key has priority over index. This is the equivalent
405 * of calling {@link #getByKey} first, then if nothing matched calling {@link #getAt}.
406 * @param {String/Number} key The key or index of the item.
407 * @return {Object} If the item is found, returns the item. If the item was not found, returns <tt>undefined</tt>.
408 * If an item was found, but is a Class, returns <tt>null</tt>.
410 get : function(key) {
413 item = mk !== undefined ? mk : (typeof key == 'number') ? me.items[key] : undefined;
414 return typeof item != 'function' || me.allowFunctions ? item : null; // for prototype!
417 <span id='Ext-util-AbstractMixedCollection-method-getAt'> /**
418 </span> * Returns the item at the specified index.
419 * @param {Number} index The index of the item.
420 * @return {Object} The item at the specified index.
422 getAt : function(index) {
423 return this.items[index];
426 <span id='Ext-util-AbstractMixedCollection-method-getByKey'> /**
427 </span> * Returns the item associated with the passed key.
428 * @param {String/Number} key The key of the item.
429 * @return {Object} The item associated with the passed key.
431 getByKey : function(key) {
432 return this.map[key];
435 <span id='Ext-util-AbstractMixedCollection-method-contains'> /**
436 </span> * Returns true if the collection contains the passed Object as an item.
437 * @param {Object} o The Object to look for in the collection.
438 * @return {Boolean} True if the collection contains the Object as an item.
440 contains : function(o){
441 return Ext.Array.contains(this.items, o);
444 <span id='Ext-util-AbstractMixedCollection-method-containsKey'> /**
445 </span> * Returns true if the collection contains the passed Object as a key.
446 * @param {String} key The key to look for in the collection.
447 * @return {Boolean} True if the collection contains the Object as a key.
449 containsKey : function(key){
450 return typeof this.map[key] != 'undefined';
453 <span id='Ext-util-AbstractMixedCollection-method-clear'> /**
454 </span> * Removes all items from the collection. Fires the {@link #clear} event when complete.
463 me.fireEvent('clear');
466 <span id='Ext-util-AbstractMixedCollection-method-first'> /**
467 </span> * Returns the first item in the collection.
468 * @return {Object} the first item in the collection..
471 return this.items[0];
474 <span id='Ext-util-AbstractMixedCollection-method-last'> /**
475 </span> * Returns the last item in the collection.
476 * @return {Object} the last item in the collection..
479 return this.items[this.length - 1];
482 <span id='Ext-util-AbstractMixedCollection-method-sum'> /**
483 </span> * Collects all of the values of the given property and returns their sum
484 * @param {String} property The property to sum by
485 * @param {String} [root] 'root' property to extract the first argument from. This is used mainly when
486 * summing fields in records, where the fields are all stored inside the 'data' object
487 * @param {Number} [start=0] The record index to start at
488 * @param {Number} [end=-1] The record index to end at
489 * @return {Number} The total
491 sum: function(property, root, start, end) {
492 var values = this.extractValues(property, root),
493 length = values.length,
498 end = (end || end === 0) ? end : length - 1;
500 for (i = start; i <= end; i++) {
507 <span id='Ext-util-AbstractMixedCollection-method-collect'> /**
508 </span> * Collects unique values of a particular property in this MixedCollection
509 * @param {String} property The property to collect on
510 * @param {String} root (optional) 'root' property to extract the first argument from. This is used mainly when
511 * summing fields in records, where the fields are all stored inside the 'data' object
512 * @param {Boolean} allowBlank (optional) Pass true to allow null, undefined or empty string values
513 * @return {Array} The unique values
515 collect: function(property, root, allowNull) {
516 var values = this.extractValues(property, root),
517 length = values.length,
522 for (i = 0; i < length; i++) {
524 strValue = String(value);
526 if ((allowNull || !Ext.isEmpty(value)) && !hits[strValue]) {
527 hits[strValue] = true;
535 <span id='Ext-util-AbstractMixedCollection-method-extractValues'> /**
537 * Extracts all of the given property values from the items in the MC. Mainly used as a supporting method for
538 * functions like sum and collect.
539 * @param {String} property The property to extract
540 * @param {String} root (optional) 'root' property to extract the first argument from. This is used mainly when
541 * extracting field data from Model instances, where the fields are stored inside the 'data' object
542 * @return {Array} The extracted values
544 extractValues: function(property, root) {
545 var values = this.items;
548 values = Ext.Array.pluck(values, root);
551 return Ext.Array.pluck(values, property);
554 <span id='Ext-util-AbstractMixedCollection-method-getRange'> /**
555 </span> * Returns a range of items in this collection
556 * @param {Number} startIndex (optional) The starting index. Defaults to 0.
557 * @param {Number} endIndex (optional) The ending index. Defaults to the last item.
558 * @return {Array} An array of items
560 getRange : function(start, end){
566 if (items.length < 1) {
571 end = Math.min(typeof end == 'undefined' ? me.length - 1 : end, me.length - 1);
572 if (start <= end) {
573 for (i = start; i <= end; i++) {
574 range[range.length] = items[i];
577 for (i = start; i >= end; i--) {
578 range[range.length] = items[i];
584 <span id='Ext-util-AbstractMixedCollection-method-filter'> /**
585 </span> * <p>Filters the objects in this collection by a set of {@link Ext.util.Filter Filter}s, or by a single
586 * property/value pair with optional parameters for substring matching and case sensitivity. See
587 * {@link Ext.util.Filter Filter} for an example of using Filter objects (preferred). Alternatively,
588 * MixedCollection can be easily filtered by property like this:</p>
589 <pre><code>
590 //create a simple store with a few people defined
591 var people = new Ext.util.MixedCollection();
593 {id: 1, age: 25, name: 'Ed'},
594 {id: 2, age: 24, name: 'Tommy'},
595 {id: 3, age: 24, name: 'Arne'},
596 {id: 4, age: 26, name: 'Aaron'}
599 //a new MixedCollection containing only the items where age == 24
600 var middleAged = people.filter('age', 24);
601 </code></pre>
604 * @param {Ext.util.Filter[]/String} property A property on your objects, or an array of {@link Ext.util.Filter Filter} objects
605 * @param {String/RegExp} value Either string that the property values
606 * should start with or a RegExp to test against the property
607 * @param {Boolean} [anyMatch=false] True to match any part of the string, not just the beginning
608 * @param {Boolean} [caseSensitive=false] True for case sensitive comparison.
609 * @return {Ext.util.MixedCollection} The new filtered collection
611 filter : function(property, value, anyMatch, caseSensitive) {
615 //support for the simple case of filtering by property/value
616 if (Ext.isString(property)) {
617 filters.push(Ext.create('Ext.util.Filter', {
621 caseSensitive: caseSensitive
623 } else if (Ext.isArray(property) || property instanceof Ext.util.Filter) {
624 filters = filters.concat(property);
627 //at this point we have an array of zero or more Ext.util.Filter objects to filter with,
628 //so here we construct a function that combines these filters by ANDing them together
629 filterFn = function(record) {
631 length = filters.length,
634 for (i = 0; i < length; i++) {
635 var filter = filters[i],
636 fn = filter.filterFn,
637 scope = filter.scope;
639 isMatch = isMatch && fn.call(scope, record);
645 return this.filterBy(filterFn);
648 <span id='Ext-util-AbstractMixedCollection-method-filterBy'> /**
649 </span> * Filter by a function. Returns a <i>new</i> collection that has been filtered.
650 * The passed function will be called with each object in the collection.
651 * If the function returns true, the value is included otherwise it is filtered.
652 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
653 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
654 * @return {Ext.util.MixedCollection} The new filtered collection
656 filterBy : function(fn, scope) {
658 newMC = new this.self(),
661 length = items.length,
664 newMC.getKey = me.getKey;
666 for (i = 0; i < length; i++) {
667 if (fn.call(scope || me, items[i], keys[i])) {
668 newMC.add(keys[i], items[i]);
675 <span id='Ext-util-AbstractMixedCollection-method-findIndex'> /**
676 </span> * Finds the index of the first matching object in this collection by a specific property/value.
677 * @param {String} property The name of a property on your objects.
678 * @param {String/RegExp} value A string that the property values
679 * should start with or a RegExp to test against the property.
680 * @param {Number} [start=0] The index to start searching at.
681 * @param {Boolean} [anyMatch=false] True to match any part of the string, not just the beginning.
682 * @param {Boolean} [caseSensitive=false] True for case sensitive comparison.
683 * @return {Number} The matched index or -1
685 findIndex : function(property, value, start, anyMatch, caseSensitive){
686 if(Ext.isEmpty(value, false)){
689 value = this.createValueMatcher(value, anyMatch, caseSensitive);
690 return this.findIndexBy(function(o){
691 return o && value.test(o[property]);
695 <span id='Ext-util-AbstractMixedCollection-method-findIndexBy'> /**
696 </span> * Find the index of the first matching object in this collection by a function.
697 * If the function returns <i>true</i> it is considered a match.
698 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
699 * @param {Object} [scope] The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
700 * @param {Number} [start=0] The index to start searching at.
701 * @return {Number} The matched index or -1
703 findIndexBy : function(fn, scope, start){
710 for (; i < len; i++) {
711 if (fn.call(scope || me, items[i], keys[i])) {
718 <span id='Ext-util-AbstractMixedCollection-method-createValueMatcher'> /**
719 </span> * Returns a regular expression based on the given value and matching options. This is used internally for finding and filtering,
720 * and by Ext.data.Store#filter
722 * @param {String} value The value to create the regex for. This is escaped using Ext.escapeRe
723 * @param {Boolean} anyMatch True to allow any match - no regex start/end line anchors will be added. Defaults to false
724 * @param {Boolean} caseSensitive True to make the regex case sensitive (adds 'i' switch to regex). Defaults to false.
725 * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false. Ignored if anyMatch is true.
727 createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {
728 if (!value.exec) { // not a regex
729 var er = Ext.String.escapeRegex;
730 value = String(value);
732 if (anyMatch === true) {
735 value = '^' + er(value);
736 if (exactMatch === true) {
740 value = new RegExp(value, caseSensitive ? '' : 'i');
745 <span id='Ext-util-AbstractMixedCollection-method-clone'> /**
746 </span> * Creates a shallow copy of this collection
747 * @return {Ext.util.MixedCollection}
751 copy = new this.self(),
757 for(; i < len; i++){
758 copy.add(keys[i], items[i]);
760 copy.getKey = me.getKey;