<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-util-Filter'>/**
|
</span> * Represents a filter that can be applied to a {@link Ext.util.MixedCollection MixedCollection}. Can either simply
|
* filter on a property/value pair or pass in a filter function with custom logic. Filters are always used in the
|
* context of MixedCollections, though {@link Ext.data.Store Store}s frequently create them when filtering and searching
|
* on their records. Example usage:
|
*
|
* //set up a fictional MixedCollection containing a few people to filter on
|
* var allNames = new Ext.util.MixedCollection();
|
* allNames.addAll([
|
* {id: 1, name: 'Ed', age: 25},
|
* {id: 2, name: 'Jamie', age: 37},
|
* {id: 3, name: 'Abe', age: 32},
|
* {id: 4, name: 'Aaron', age: 26},
|
* {id: 5, name: 'David', age: 32}
|
* ]);
|
*
|
* var ageFilter = new Ext.util.Filter({
|
* property: 'age',
|
* value : 32
|
* });
|
*
|
* var longNameFilter = new Ext.util.Filter({
|
* filterFn: function(item) {
|
* return item.name.length > 4;
|
* }
|
* });
|
*
|
* //a new MixedCollection with the 3 names longer than 4 characters
|
* var longNames = allNames.filter(longNameFilter);
|
*
|
* //a new MixedCollection with the 2 people of age 32:
|
* var youngFolk = allNames.filter(ageFilter);
|
*
|
*/
|
Ext.define('Ext.util.Filter', {
|
|
<span id='Ext-util-Filter-cfg-property'> /**
|
</span> * @cfg {String} property
|
* The property to filter on. Required unless a {@link #filterFn} is passed
|
*/
|
<span id='Ext-util-Filter-cfg-value'> /**
|
</span> * @cfg {Mixed} value
|
* The value to filter on. Required unless a {@link #filterFn} is passed.
|
*/
|
|
<span id='Ext-util-Filter-cfg-filterFn'> /**
|
</span> * @cfg {Function} filterFn
|
* A custom filter function which is passed each item in the {@link Ext.util.MixedCollection} in turn. Should return
|
* `true` to accept each item or `false` to reject it.
|
*/
|
|
<span id='Ext-util-Filter-cfg-id'> /**
|
</span> * @cfg {String} [id]
|
* An identifier by which this Filter is indexed in a {@link Ext.data.Store#property-filters Store's filters collection}
|
*
|
* Identified Filters may be individually removed from a Store's filter set by using {@link Ext.data.Store#removeFilter}.
|
*
|
* Anonymous Filters may be removed en masse by passing `null` to {@link Ext.data.Store#removeFilter}.
|
*/
|
id: null,
|
|
<span id='Ext-util-Filter-cfg-anyMatch'> /**
|
</span> * @cfg {Boolean} anyMatch
|
* True to allow any match - no regex start/end line anchors will be added.
|
*/
|
anyMatch: false,
|
|
<span id='Ext-util-Filter-cfg-exactMatch'> /**
|
</span> * @cfg {Boolean} exactMatch
|
* True to force exact match (^ and $ characters added to the regex). Ignored if anyMatch is true.
|
*/
|
exactMatch: false,
|
|
<span id='Ext-util-Filter-cfg-caseSensitive'> /**
|
</span> * @cfg {Boolean} caseSensitive
|
* True to make the regex case sensitive (adds 'i' switch to regex).
|
*/
|
caseSensitive: false,
|
|
<span id='Ext-util-Filter-property-disabled'> /**
|
</span> * @property {Boolean} disabled
|
* Setting this property to `true` disables this individual Filter so that it no longer contributes to a {@link Ext.data.Store#property-filters Store's filter set}
|
*
|
* When disabled, the next time the store is filtered, the Filter plays no part in filtering and records eliminated by it may rejoin the dataset.
|
*
|
*/
|
disabled: false,
|
|
<span id='Ext-util-Filter-cfg-operator'> /**
|
</span> * @cfg {String} [operator]
|
* The operator to use to compare the {@link #cfg-property} to this Filter's {@link #cfg-value}
|
*
|
* Possible values are:
|
* * <
|
* * <=
|
* * =
|
* * >=
|
* * >
|
* * !=
|
*/
|
operator: null,
|
|
<span id='Ext-util-Filter-cfg-root'> /**
|
</span> * @cfg {String} root
|
* Optional root property. This is mostly useful when filtering a Store, in which case we set the root to 'data' to
|
* make the filter pull the {@link #property} out of the data object of each item
|
*/
|
|
statics: {
|
<span id='Ext-util-Filter-method-createFilterFn'> /**
|
</span> * Creates a single filter function which encapsulates the passed Filter array.
|
* @param {Ext.util.Filter[]} filters The filter set for which to create a filter function
|
* @return {Function} a function, which when passed a candidate object returns `true` if
|
* the candidate passes all the specified Filters.
|
*/
|
createFilterFn: function(filters) {
|
return filters && filters.length ? function(candidate) {
|
var isMatch = true,
|
length = filters.length,
|
i, filter;
|
|
for (i = 0; isMatch && i < length; i++) {
|
filter = filters[i];
|
|
// Disabling a filter stops it from contributing to the overall filter function.
|
if (!filter.disabled) {
|
isMatch = isMatch && filter.filterFn.call(filter.scope || filter, candidate);
|
}
|
}
|
return isMatch;
|
} : function() {
|
return true;
|
};
|
}
|
},
|
|
<span id='Ext-util-Filter-property-operatorFns'> operatorFns: {
|
</span> "<": function(candidate) {
|
return Ext.coerce(this.getRoot(candidate)[this.property], this.value) < this.value;
|
},
|
"<=": function(candidate) {
|
return Ext.coerce(this.getRoot(candidate)[this.property], this.value) <= this.value;
|
},
|
"=": function(candidate) {
|
return Ext.coerce(this.getRoot(candidate)[this.property], this.value) == this.value;
|
},
|
">=": function(candidate) {
|
return Ext.coerce(this.getRoot(candidate)[this.property], this.value) >= this.value;
|
},
|
">": function(candidate) {
|
return Ext.coerce(this.getRoot(candidate)[this.property], this.value) > this.value;
|
},
|
"!=": function(candidate) {
|
return Ext.coerce(this.getRoot(candidate)[this.property], this.value) != this.value;
|
}
|
},
|
|
<span id='Ext-util-Filter-method-constructor'> /**
|
</span> * Creates new Filter.
|
* @param {Object} [config] Config object
|
*/
|
constructor: function(config) {
|
var me = this;
|
me.initialConfig = config;
|
Ext.apply(me, config);
|
|
//we're aliasing filter to filterFn mostly for API cleanliness reasons, despite the fact it dirties the code here.
|
//Ext.util.Sorter takes a sorterFn property but allows .sort to be called - we do the same here
|
me.filter = me.filter || me.filterFn;
|
|
if (me.filter === undefined) {
|
me.setValue(config.value);
|
}
|
},
|
|
<span id='Ext-util-Filter-method-setValue'> /**
|
</span> * Changes the value that this filter tests its configured (@link #cfg-property} with.
|
* @param {Mixed} value The new value to compare the property with.
|
*/
|
setValue: function(value) {
|
var me = this;
|
me.value = value;
|
if (me.property === undefined || me.value === undefined) {
|
// Commented this out temporarily because it stops us using string ids in models. TODO: Remove this once
|
// Model has been updated to allow string ids
|
|
// Ext.Error.raise("A Filter requires either a property or a filterFn to be set");
|
} else {
|
me.filter = me.createFilterFn();
|
}
|
|
me.filterFn = me.filter;
|
},
|
|
<span id='Ext-util-Filter-method-setFilterFn'> /**
|
</span> * Changes the filtering function which this Filter uses to choose items to include.
|
*
|
* This replaces any configured {@link #cfg-filterFn} and overrides any {@link #cfg-property} and {@link #cfg-value) settings.
|
* @param {Function} filterFn A function which returns `true` or `false` to either include or exclude the passed object.
|
* @param {Object} filterFn.value The value for consideration to be included or excluded.
|
*
|
*/
|
setFilterFn: function(filterFn) {
|
this.filterFn = this.filter = filterFn;
|
},
|
|
<span id='Ext-util-Filter-method-createFilterFn'> /**
|
</span> * @private
|
* Creates a filter function for the configured property/value/anyMatch/caseSensitive options for this Filter
|
*/
|
createFilterFn: function() {
|
var me = this,
|
matcher = me.createValueMatcher(),
|
property = me.property;
|
|
if (me.operator) {
|
return me.operatorFns[me.operator];
|
} else {
|
return function(item) {
|
var value = me.getRoot(item)[property];
|
return matcher === null ? value === null : matcher.test(value);
|
};
|
}
|
},
|
|
<span id='Ext-util-Filter-method-getRoot'> /**
|
</span> * @private
|
* Returns the root property of the given item, based on the configured {@link #root} property
|
* @param {Object} item The item
|
* @return {Object} The root property of the object
|
*/
|
getRoot: function(item) {
|
var root = this.root;
|
return root === undefined ? item : item[root];
|
},
|
|
<span id='Ext-util-Filter-method-createValueMatcher'> /**
|
</span> * @private
|
* Returns a regular expression based on the given value and matching options
|
*/
|
createValueMatcher : function() {
|
var me = this,
|
value = me.value,
|
anyMatch = me.anyMatch,
|
exactMatch = me.exactMatch,
|
caseSensitive = me.caseSensitive,
|
escapeRe = Ext.String.escapeRegex;
|
|
if (value === null) {
|
return value;
|
}
|
|
if (!value.exec) { // not a regex
|
value = String(value);
|
|
if (anyMatch === true) {
|
value = escapeRe(value);
|
} else {
|
value = '^' + escapeRe(value);
|
if (exactMatch === true) {
|
value += '$';
|
}
|
}
|
value = new RegExp(value, caseSensitive ? '' : 'i');
|
}
|
|
return value;
|
},
|
|
<span id='Ext-util-Filter-method-serialize'> serialize: function() {
|
</span> var me = this,
|
result = Ext.apply({}, me.initialConfig);
|
|
result.value = me.value;
|
return result;
|
}
|
}, function() {
|
// Operator type '==' is the same as operator type '='
|
this.prototype.operatorFns['=='] = this.prototype.operatorFns['='];
|
});</pre>
|
</body>
|
</html>
|