From 965f490491a2ab3aa2e96889a52e6c97532baa7f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 13 Jul 2015 17:10:19 -0700 Subject: [PATCH] =?UTF-8?q?[BUGFIX=20beta]=20[fixes=20#11736]=20ensure=20a?= =?UTF-8?q?rray=20computed=20macro=E2=80=99s=20have=20correct=20this?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/computed/reduce_computed_macros.js | 18 +++++-- .../computed/reduce_computed_macros_test.js | 54 +++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index eb26a0ae24b..769a5971e69 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -13,7 +13,9 @@ import { isArray } from 'ember-runtime/utils'; function reduceMacro(dependentKey, callback, initialValue) { return computed(`${dependentKey}.[]`, function() { - return get(this, dependentKey).reduce(callback, initialValue); + return get(this, dependentKey).reduce((previousValue, currentValue, index, array) => { + return callback.call(this, previousValue, currentValue, index, array); + }, initialValue); }).readOnly(); } @@ -30,7 +32,7 @@ function arrayMacro(dependentKey, callback) { return computed(dependentKey, function() { var value = get(this, propertyName); if (isArray(value)) { - return Ember.A(callback(value)); + return Ember.A(callback.call(this, value)); } else { return Ember.A(); } @@ -173,7 +175,9 @@ export function min(dependentKey) { @public */ export function map(dependentKey, callback) { - return arrayMacro(dependentKey, value => value.map(callback)); + return arrayMacro(dependentKey, function(value) { + return value.map(callback, this); + }); } /** @@ -251,7 +255,9 @@ export function mapBy(dependentKey, propertyKey) { @public */ export function filter(dependentKey, callback) { - return arrayMacro(dependentKey, value => value.filter(callback)); + return arrayMacro(dependentKey, function(value) { + return value.filter(callback, this); + }); } /** @@ -538,7 +544,9 @@ export function sort(itemsKey, sortDefinition) { } function customSort(itemsKey, comparator) { - return arrayMacro(itemsKey, value => value.slice().sort(comparator)); + return arrayMacro(itemsKey, function(value) { + return value.slice().sort((x, y) => comparator.call(this, x, y)); + }); } // This one needs to dynamically set up and tear down observers on the itemsKey diff --git a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js index c513b46a786..cfc3e86a13f 100644 --- a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js +++ b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js @@ -83,6 +83,22 @@ QUnit.test('it maps simple unshifted properties', function() { deepEqual(obj.get('mapped'), ['A', 'B'], 'properties unshifted in sequence are mapped correctly'); }); +QUnit.test('it has the correct `this`', function() { + obj = EmberObject.extend({ + mapped: map('array', function(item) { + equal(this, obj, 'should have correct context'); + return this.upperCase(item); + }), + upperCase(string) { + return string.toUpperCase(); + } + }).create({ + array: ['a', 'b', 'c'] + }); + + deepEqual(obj.get('mapped'), ['A', 'B', 'C'], 'properties unshifted in sequence are mapped correctly'); +}); + QUnit.test('it passes the index to the callback', function() { var array = ['a', 'b', 'c']; @@ -227,6 +243,22 @@ QUnit.test('it passes the index to the callback', function() { deepEqual(get(obj, 'filtered'), ['b'], 'index is passed to callback correctly'); }); +QUnit.test('it has the correct `this`', function() { + obj = EmberObject.extend({ + filtered: filter('array', function(item, index) { + equal(this, obj); + return this.isOne(index); + }), + isOne(value) { + return value === 1; + } + }).create({ + array: ['a', 'b', 'c'] + }); + + deepEqual(get(obj, 'filtered'), ['b'], 'index is passed to callback correctly'); +}); + QUnit.test('it passes the array to the callback', function() { obj = EmberObject.extend({ filtered: filter('array', (item, index, array) => index === get(array, 'length') - 2) @@ -1096,6 +1128,27 @@ QUnit.module('sort - sort function', { } }); +QUnit.test('sort has correct `this`', function() { + var obj = EmberObject.extend({ + sortedItems: sort('items.@each.fname', function(a, b) { + equal(this, obj, 'expected the object to be `this`'); + return this.sortByLastName(a, b); + }), + sortByLastName(a, b) { + return sortByFnameAsc(a, b); + } + }).create({ + items: Ember.A([ + { fname: 'Jaime', lname: 'Lannister', age: 34 }, + { fname: 'Cersei', lname: 'Lannister', age: 34 }, + { fname: 'Robb', lname: 'Stark', age: 16 }, + { fname: 'Bran', lname: 'Stark', age: 8 } + ]) + }); + + obj.get('sortedItems'); +}); + QUnit.test('sort (with function) is readOnly', function() { QUnit.throws(function() { obj.set('sortedItems', 1); @@ -1157,6 +1210,7 @@ QUnit.test('sorts correctly as only one property changes', function() { deepEqual(obj.get('sortedItems').mapBy('name'), ['A', 'B', 'C', 'D'], 'final'); }); + QUnit.module('sort - concurrency', { setup() { obj = EmberObject.extend({