Skip to content

Instantly share code, notes, and snippets.

@cibernox
Last active August 29, 2015 13:58
Show Gist options
  • Save cibernox/9950325 to your computer and use it in GitHub Desktop.
Save cibernox/9950325 to your computer and use it in GitHub Desktop.
First approach to a filterPropertyBetween CP
(function(exports){
exports.computed = {};
/**
* Returns an arrayComputed property that filters the elements in the `dependentKey`
* that have its `propertyKey` between (inclusive) the values in `startKey` and `endKey`.
* It reacts to additions to changes in the `dependentKey`, `startKey` and `endKey`.
*
* Right now it assumes that the array in the dependentKey is sorted and preserves
* that sorting.
*
* TODO: React to removed items in the property key
* TODO: Tests.
*
* @param {String} dependentKey The name of the property with the collection to be filtered
* @param {String} propertyKey The name of the property to be between the bounds (inclusive)
* @param {String} startKey The name of the property with the start of the range.
* @param {String} endKey The name of the property with the end of the range.
* @return {Array}
*/
exports.computed.filterPropertyBetween = function(dependentKey, propertyKey, startKey, endKey){
var get = Ember.get;
// Remove elements of the beginning of the array.
var shiftItems = function(sourceArray, items, rangeStart, rangeEnd){
var result = Ember.A(), item, i, value;
for (i = 0; i < items.length; i++){
item = items.objectAt(i);
value = get(item, propertyKey);
if (value >= rangeStart) break;
if (value <= rangeEnd) result.push(item);
}
items.removeObjects(result);
};
// Add elements at the beginning of the array
var unshiftItems = function(sourceArray, items, rangeStart, rangeEnd){
var firstAlreadyIncludedIndex = sourceArray.length,
result = Ember.A(),
item, i, value;
if (items[0]){
firstAlreadyIncludedIndex = sourceArray.indexOf(items[0]);
}
for (i = firstAlreadyIncludedIndex - 1; i >= 0; i--){
item = sourceArray[i];
value = get(item, propertyKey);
if (value < rangeStart) break;
if (value < rangeEnd) result.insertAt(0, item);
}
items.unshiftObjects(result);
};
// Remove elements at the end of the array
var popItems = function(sourceArray, items, rangeStart, rangeEnd){
var result = Ember.A(), item, i, value;
for (i = items.length -1; i >= 0; i--){
item = items[i];
value = get(item, propertyKey);
if (value <= rangeEnd) break;
if (value >= rangeStart) result.insertAt(0, item);
}
items.removeObjects(result);
};
// Add elements at the end of the array
var pushItems = function(sourceArray, items, rangeStart, rangeEnd){
var lastAlreadyIncludedIndex = sourceArray.indexOf(items.get('lastObject')),
length = sourceArray.length,
result = Ember.A(),
item, i, value;
for (i = lastAlreadyIncludedIndex + 1; i < length; i++){
item = sourceArray[i];
value = get(item, propertyKey);
if (value > rangeEnd) break;
if (value > rangeStart) result.push(item);
}
items.pushObjects(result);
};
var initFn = function(array, changeMeta, instanceMeta){
instanceMeta[startKey] = this.get(startKey);
instanceMeta[endKey] = this.get(endKey);
var rangeStartChanged = function(){
var newRangeStart = get(this, startKey),
newRangeEnd = get(this, endKey);
if (newRangeStart > instanceMeta[startKey]){
shiftItems(get(this, dependentKey), array, newRangeStart, newRangeEnd);
} else {
unshiftItems(get(this, dependentKey), array, newRangeStart, newRangeEnd);
}
instanceMeta[startKey] = newRangeStart;
};
var rangeEndChanged = function(){
var newRangeStart = get(this, startKey),
newRangeEnd = get(this, endKey);
if (newRangeEnd < instanceMeta[endKey]){
popItems(get(this, dependentKey), array, newRangeStart, newRangeEnd);
} else {
pushItems(get(this, dependentKey), array, newRangeStart, newRangeEnd);
}
instanceMeta[endKey] = newRangeEnd;
};
Ember.addObserver(this, startKey, function(object){
Ember.run.once(object, rangeStartChanged);
});
Ember.addObserver(this, endKey, function(object){
Ember.run.once(object, rangeEndChanged);
});
};
return Ember.arrayComputed(dependentKey + '.@each.' + propertyKey, {
initialize: initFn,
addedItem: function(array, item, changeMeta, instanceMeta) {
var performedAt = item.get(propertyKey),
rangeStart = this.get(startKey),
rangeEnd = this.get(endKey);
if (performedAt >= rangeStart && performedAt <= rangeEnd) {
array.insertAt(Math.min(changeMeta.index, array.length), item);
}
return array;
}
});
};
})(App)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment