File: packages/ember-runtime/lib/system/native_array.js
/**
@module ember
@submodule ember-runtime
*/
import Ember, { // Ember.A circular
replace,
get,
Mixin
} from 'ember-metal';
import { ENV } from 'ember-environment';
import EmberArray, {
arrayContentDidChange,
arrayContentWillChange
} from '../mixins/array';
import MutableArray from '../mixins/mutable_array';
import Observable from '../mixins/observable';
import Copyable from '../mixins/copyable';
import { FROZEN_ERROR } from '../mixins/freezable';
import copy from '../copy';
// Add Ember.Array to Array.prototype. Remove methods with native
// implementations and supply some more optimized versions of generic methods
// because they are so common.
/**
The NativeArray mixin contains the properties needed to make the native
Array support Ember.MutableArray and all of its dependent APIs. Unless you
have `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Array` set to
false, this will be applied automatically. Otherwise you can apply the mixin
at anytime by calling `Ember.NativeArray.apply(Array.prototype)`.
@class NativeArray
@namespace Ember
@uses Ember.MutableArray
@uses Ember.Observable
@uses Ember.Copyable
@public
*/
let NativeArray = Mixin.create(MutableArray, Observable, Copyable, {
// because length is a built-in property we need to know to just get the
// original property.
get(key) {
if ('number' === typeof key) {
return this[key];
} else {
return this._super(key);
}
},
objectAt(idx) {
return this[idx];
},
// primitive for array support.
replace(idx, amt, objects) {
if (this.isFrozen) {
throw FROZEN_ERROR;
}
// if we replaced exactly the same number of items, then pass only the
// replaced range. Otherwise, pass the full remaining array length
// since everything has shifted
let len = objects ? get(objects, 'length') : 0;
arrayContentWillChange(this, idx, amt, len);
if (len === 0) {
this.splice(idx, amt);
} else {
replace(this, idx, amt, objects);
}
arrayContentDidChange(this, idx, amt, len);
return this;
},
// If you ask for an unknown property, then try to collect the value
// from member items.
unknownProperty(key, value) {
let ret;// = this.reducedProperty(key, value);
if (value !== undefined && ret === undefined) {
ret = this[key] = value;
}
return ret;
},
indexOf: Array.prototype.indexOf,
lastIndexOf: Array.prototype.lastIndexOf,
copy(deep) {
if (deep) {
return this.map((item) => copy(item, true));
}
return this.slice();
}
});
// Remove any methods implemented natively so we don't override them
const ignore = ['length'];
NativeArray.keys().forEach((methodName) => {
if (Array.prototype[methodName]) {
ignore.push(methodName);
}
});
NativeArray = NativeArray.without.apply(NativeArray, ignore);
/**
Creates an `Ember.NativeArray` from an Array like object.
Does not modify the original object. Ember.A is not needed if
`EmberENV.EXTEND_PROTOTYPES` is `true` (the default value). However,
it is recommended that you use Ember.A when creating addons for
ember or when you can not guarantee that `EmberENV.EXTEND_PROTOTYPES`
will be `true`.
Example
```js
export default Ember.Component.extend({
tagName: 'ul',
classNames: ['pagination'],
init() {
this._super(...arguments);
if (!this.get('content')) {
this.set('content', Ember.A());
}
}
});
```
@method A
@for Ember
@return {Ember.NativeArray}
@public
*/
let A;
if (ENV.EXTEND_PROTOTYPES.Array) {
NativeArray.apply(Array.prototype);
A = arr => arr || [];
} else {
A = arr => {
if (!arr) { arr = []; }
return EmberArray.detect(arr) ? arr : NativeArray.apply(arr);
};
}
Ember.A = A;
export {
A,
NativeArray // TODO: only use default export
};
export default NativeArray;