diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 78a098547c..8b0a4ff495 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -380,7 +380,9 @@ var args = Array.prototype.slice.call(arguments, 1); var len = array.length; var ret = array.push.apply(array, args); - this._notifySplice(array, path, len, args.length, []); + if (args.length) { + this._notifySplice(array, path, len, args.length, []); + } return ret; }, @@ -399,10 +401,12 @@ */ pop: function(path) { var array = this.get(path); + var hadLength = Boolean(array.length); var args = Array.prototype.slice.call(arguments, 1); - var rem = array.slice(-1); var ret = array.pop.apply(array, args); - this._notifySplice(array, path, array.length, 0, rem); + if (hadLength) { + this._notifySplice(array, path, array.length, 0, [ret]); + } return ret; }, @@ -425,9 +429,21 @@ */ splice: function(path, start, deleteCount) { var array = this.get(path); + // Normalize fancy native splice handling of crazy start values + if (start < 0) { + start = array.length - Math.floor(Math.abs(start)); + } else { + start = Math.floor(start); + } + if (!start || !isFinite(start)) { + start = 0; + } var args = Array.prototype.slice.call(arguments, 1); var ret = array.splice.apply(array, args); - this._notifySplice(array, path, start, args.length - 2, ret); + var addedCount = Math.max(args.length - 2, 0); + if (addedCount || ret.length) { + this._notifySplice(array, path, start, addedCount, ret); + } return ret; }, @@ -446,9 +462,12 @@ */ shift: function(path) { var array = this.get(path); + var hadLength = Boolean(array.length); var args = Array.prototype.slice.call(arguments, 1); var ret = array.shift.apply(array, args); - this._notifySplice(array, path, 0, 0, [ret]); + if (hadLength) { + this._notifySplice(array, path, 0, 0, [ret]); + } return ret; }, @@ -470,7 +489,9 @@ var array = this.get(path); var args = Array.prototype.slice.call(arguments, 1); var ret = array.unshift.apply(array, args); - this._notifySplice(array, path, 0, args.length, []); + if (args.length) { + this._notifySplice(array, path, 0, args.length, []); + } return ret; } diff --git a/test/unit/notify-path.html b/test/unit/notify-path.html index a89c09171a..b422747625 100644 --- a/test/unit/notify-path.html +++ b/test/unit/notify-path.html @@ -901,6 +901,265 @@ assert.equal(el.get('array.prop'), 'foo'); }); + var nop = function() {}; + + test('push array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + Polymer.Collection.get(el.array); + var key = el.array.length; + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 3); + assert.strictEqual(change.indexSplices[0].addedCount, 2); + assert.strictEqual(change.indexSplices[0].removed.length, 0); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].index, 3); + assert.strictEqual(change.keySplices[0].added.length, 2); + assert.strictEqual(change.keySplices[0].added[0], key); + assert.strictEqual(change.keySplices[0].added[1], key+1); + assert.strictEqual(change.keySplices[0].removed.length, 0); + }; + var ret = el.push('array', 'new1', 'new2'); + assert.strictEqual(ret, 5); + assert.strictEqual(el.array.length, 5); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'orig2'); + assert.strictEqual(el.array[2], 'orig3'); + assert.strictEqual(el.array[3], 'new1'); + assert.strictEqual(el.array[4], 'new2'); + }); + + test('pop array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + Polymer.Collection.get(el.array); + var key = el.array.length-1; + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 2); + assert.strictEqual(change.indexSplices[0].addedCount, 0); + assert.strictEqual(change.indexSplices[0].removed.length, 1); + assert.strictEqual(change.indexSplices[0].removed[0], 'orig3'); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].index, 2); + assert.strictEqual(change.keySplices[0].added.length, 0); + assert.strictEqual(change.keySplices[0].removed.length, 1); + assert.strictEqual(change.keySplices[0].removed[0], key); + }; + var ret = el.pop('array'); + assert.strictEqual(ret, 'orig3'); + assert.strictEqual(el.array.length, 2); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'orig2'); + }); + + test('unshift array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + Polymer.Collection.get(el.array); + var key = el.array.length; + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 0); + assert.strictEqual(change.indexSplices[0].addedCount, 2); + assert.strictEqual(change.indexSplices[0].removed.length, 0); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].index, 0); + assert.strictEqual(change.keySplices[0].added.length, 2); + assert.strictEqual(change.keySplices[0].added[0], key); + assert.strictEqual(change.keySplices[0].added[1], key+1); + assert.strictEqual(change.keySplices[0].removed.length, 0); + }; + var ret = el.unshift('array', 'new1', 'new2'); + assert.strictEqual(ret, 5); + assert.strictEqual(el.array.length, 5); + assert.strictEqual(el.array[0], 'new1'); + assert.strictEqual(el.array[1], 'new2'); + assert.strictEqual(el.array[2], 'orig1'); + assert.strictEqual(el.array[3], 'orig2'); + assert.strictEqual(el.array[4], 'orig3'); + }); + + test('shift array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 0); + assert.strictEqual(change.indexSplices[0].addedCount, 0); + assert.strictEqual(change.indexSplices[0].removed.length, 1); + assert.strictEqual(change.indexSplices[0].removed[0], 'orig1'); + assert.strictEqual(change.keySplices[0].index, 0); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].added.length, 0); + assert.strictEqual(change.keySplices[0].removed.length, 1); + assert.strictEqual(change.keySplices[0].removed[0], 0); + }; + var ret = el.shift('array'); + assert.strictEqual(ret, 'orig1'); + assert.strictEqual(el.array.length, 2); + assert.strictEqual(el.array[0], 'orig2'); + assert.strictEqual(el.array[1], 'orig3'); + }); + + test('splice array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + var key = el.array.length; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 1); + assert.strictEqual(change.indexSplices[0].addedCount, 2); + assert.strictEqual(change.indexSplices[0].removed.length, 1); + assert.strictEqual(change.indexSplices[0].removed[0], 'orig2'); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].index, 1); + assert.strictEqual(change.keySplices[0].added.length, 2); + assert.strictEqual(change.keySplices[0].added[0], key); + assert.strictEqual(change.keySplices[0].added[1], key+1); + assert.strictEqual(change.keySplices[0].removed.length, 1); + assert.strictEqual(change.keySplices[0].removed[0], 1); + }; + var ret = el.splice('array', 1, 1, 'new1', 'new2'); + assert.deepEqual(ret, ['orig2']); + assert.strictEqual(el.array.length, 4); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'new1'); + assert.strictEqual(el.array[2], 'new2'); + assert.strictEqual(el.array[3], 'orig3'); + }); + + test('corner: no-op push array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + throw new Error("should not notify"); + }; + var ret = el.push('array'); + assert.deepEqual(ret, 3); + assert.strictEqual(el.array.length, 3); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'orig2'); + assert.strictEqual(el.array[2], 'orig3'); + }); + + test('corner: no-op pop array', function() { + el.arrayChanged = nop; + el.array = []; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + throw new Error("should not notify"); + }; + var ret = el.pop('array'); + assert.strictEqual(ret, undefined); + assert.strictEqual(el.array.length, 0); + }); + + test('corner: no-op unshift array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + Polymer.Collection.get(el.array); + var key = el.array.length; + el.arrayChanged = function(change) { + throw new Error("should not notify"); + }; + var ret = el.unshift('array'); + assert.deepEqual(ret, 3); + assert.strictEqual(el.array.length, 3); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'orig2'); + assert.strictEqual(el.array[2], 'orig3'); + }); + + test('corner: no-op shift array', function() { + el.arrayChanged = nop; + el.array = []; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + throw new Error("should not notify"); + }; + var ret = el.shift('array'); + assert.strictEqual(ret, undefined); + assert.strictEqual(ret, undefined); + assert.strictEqual(el.array.length, 0); + }); + + test('corner: no-op splice array', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + var key = el.array.length; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + throw new Error("should not notify"); + }; + var ret = el.splice('array'); + assert.deepEqual(ret, []); + assert.strictEqual(el.array.length, 3); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'orig2'); + assert.strictEqual(el.array[2], 'orig3'); + }); + + test('corner: splice array: string args', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + var key = el.array.length; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 1); + assert.strictEqual(change.indexSplices[0].addedCount, 2); + assert.strictEqual(change.indexSplices[0].removed.length, 1); + assert.strictEqual(change.indexSplices[0].removed[0], 'orig2'); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].index, 1); + assert.strictEqual(change.keySplices[0].added.length, 2); + assert.strictEqual(change.keySplices[0].added[0], key); + assert.strictEqual(change.keySplices[0].added[1], key+1); + assert.strictEqual(change.keySplices[0].removed.length, 1); + assert.strictEqual(change.keySplices[0].removed[0], 1); + }; + var ret = el.splice('array', '1', '1', 'new1', 'new2'); + assert.deepEqual(ret, ['orig2']); + assert.strictEqual(el.array.length, 4); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'new1'); + assert.strictEqual(el.array[2], 'new2'); + assert.strictEqual(el.array[3], 'orig3'); + }); + + test('corner: splice array: negative start', function() { + el.arrayChanged = nop; + el.array = ['orig1', 'orig2', 'orig3']; + var key = el.array.length; + Polymer.Collection.get(el.array); + el.arrayChanged = function(change) { + assert.strictEqual(change.indexSplices.length, 1); + assert.strictEqual(change.indexSplices[0].index, 1); + assert.strictEqual(change.indexSplices[0].addedCount, 2); + assert.strictEqual(change.indexSplices[0].removed.length, 1); + assert.strictEqual(change.indexSplices[0].removed[0], 'orig2'); + assert.strictEqual(change.keySplices.length, 1); + assert.strictEqual(change.keySplices[0].index, 1); + assert.strictEqual(change.keySplices[0].added.length, 2); + assert.strictEqual(change.keySplices[0].added[0], key); + assert.strictEqual(change.keySplices[0].added[1], key+1); + assert.strictEqual(change.keySplices[0].removed.length, 1); + assert.strictEqual(change.keySplices[0].removed[0], 1); + }; + var ret = el.splice('array', '-2', '1', 'new1', 'new2'); + assert.deepEqual(ret, ['orig2']); + assert.strictEqual(el.array.length, 4); + assert.strictEqual(el.array[0], 'orig1'); + assert.strictEqual(el.array[1], 'new1'); + assert.strictEqual(el.array[2], 'new2'); + assert.strictEqual(el.array[3], 'orig3'); + }); + });