ember-source 4.4.0-alpha.6 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -5
- package/build-metadata.json +3 -3
- package/dist/ember-template-compiler.js +4 -4
- package/dist/ember-template-compiler.map +1 -1
- package/dist/ember-testing.js +1 -1
- package/dist/ember-testing.map +1 -1
- package/dist/ember.debug.js +306 -595
- package/dist/ember.debug.map +1 -1
- package/dist/header/license.js +1 -1
- package/dist/packages/@ember/-internals/container/index.js +0 -1
- package/dist/packages/@ember/-internals/glimmer/index.js +102 -217
- package/dist/packages/@ember/-internals/meta/lib/meta.js +1 -1
- package/dist/packages/@ember/-internals/metal/index.js +6 -3
- package/dist/packages/@ember/-internals/routing/lib/system/route-info.js +4 -0
- package/dist/packages/@ember/-internals/routing/lib/system/transition.js +4 -0
- package/dist/packages/@ember/-internals/runtime/lib/system/core_object.js +118 -302
- package/dist/packages/@ember/-internals/runtime/lib/system/object.js +8 -23
- package/dist/packages/@ember/-internals/views/lib/views/core_view.js +47 -29
- package/dist/packages/@ember/canary-features/index.js +2 -2
- package/dist/packages/ember/version.js +1 -1
- package/docs/data.json +401 -760
- package/package.json +17 -20
- package/dist/packages/@ember/renderer/index.js +0 -21
|
@@ -5,13 +5,22 @@ import { getFactoryFor, setFactoryFor } from '@ember/-internals/container';
|
|
|
5
5
|
import { getOwner } from '@ember/-internals/owner';
|
|
6
6
|
import { guidFor, makeArray, isInternalSymbol } from '@ember/-internals/utils';
|
|
7
7
|
import { meta } from '@ember/-internals/meta';
|
|
8
|
-
import { PROXY_CONTENT, sendEvent, Mixin, activateObserver, applyMixin, defineProperty, descriptorForProperty, isClassicDecorator, DEBUG_INJECTION_FUNCTIONS } from '@ember/-internals/metal';
|
|
8
|
+
import { PROXY_CONTENT, sendEvent, Mixin, activateObserver, applyMixin, defineProperty, descriptorForProperty, isClassicDecorator, DEBUG_INJECTION_FUNCTIONS, hasUnknownProperty } from '@ember/-internals/metal';
|
|
9
9
|
import ActionHandler from '../mixins/action_handler';
|
|
10
10
|
import { assert } from '@ember/debug';
|
|
11
11
|
import { DEBUG } from '@glimmer/env';
|
|
12
12
|
import { _WeakSet as WeakSet } from '@glimmer/util';
|
|
13
13
|
import { destroy, isDestroying, isDestroyed, registerDestructor } from '@glimmer/destroyable';
|
|
14
14
|
import { OWNER } from '@glimmer/owner';
|
|
15
|
+
|
|
16
|
+
function hasSetUnknownProperty(val) {
|
|
17
|
+
return typeof val === 'object' && val !== null && typeof val.setUnknownProperty === 'function';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function hasToStringExtension(val) {
|
|
21
|
+
return typeof val === 'object' && val !== null && typeof val.toStringExtension === 'function';
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
const reopen = Mixin.prototype.reopen;
|
|
16
25
|
const wasApplied = new WeakSet();
|
|
17
26
|
const prototypeMixinMap = new WeakMap();
|
|
@@ -33,12 +42,9 @@ function initialize(obj, properties) {
|
|
|
33
42
|
assert('EmberObject.create no longer supports mixing in other ' + 'definitions, use .extend & .create separately instead.', !(properties instanceof Mixin));
|
|
34
43
|
let concatenatedProperties = obj.concatenatedProperties;
|
|
35
44
|
let mergedProperties = obj.mergedProperties;
|
|
36
|
-
let hasConcatenatedProps = concatenatedProperties !== undefined && concatenatedProperties.length > 0;
|
|
37
|
-
let hasMergedProps = mergedProperties !== undefined && mergedProperties.length > 0;
|
|
38
45
|
let keyNames = Object.keys(properties);
|
|
39
46
|
|
|
40
|
-
for (let
|
|
41
|
-
let keyName = keyNames[i];
|
|
47
|
+
for (let keyName of keyNames) {
|
|
42
48
|
let value = properties[keyName];
|
|
43
49
|
assert('EmberObject.create no longer supports defining computed ' + 'properties. Define computed properties using extend() or reopen() ' + 'before calling create().', !isClassicDecorator(value));
|
|
44
50
|
assert('EmberObject.create no longer supports defining methods that call _super.', !(typeof value === 'function' && value.toString().indexOf('._super') !== -1));
|
|
@@ -47,7 +53,7 @@ function initialize(obj, properties) {
|
|
|
47
53
|
let isDescriptor = possibleDesc !== undefined;
|
|
48
54
|
|
|
49
55
|
if (!isDescriptor) {
|
|
50
|
-
if (
|
|
56
|
+
if (concatenatedProperties !== undefined && concatenatedProperties.length > 0 && concatenatedProperties.includes(keyName)) {
|
|
51
57
|
let baseValue = obj[keyName];
|
|
52
58
|
|
|
53
59
|
if (baseValue) {
|
|
@@ -57,7 +63,7 @@ function initialize(obj, properties) {
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
if (
|
|
66
|
+
if (mergedProperties !== undefined && mergedProperties.length > 0 && mergedProperties.includes(keyName)) {
|
|
61
67
|
let baseValue = obj[keyName];
|
|
62
68
|
value = Object.assign({}, baseValue, value);
|
|
63
69
|
}
|
|
@@ -65,7 +71,7 @@ function initialize(obj, properties) {
|
|
|
65
71
|
|
|
66
72
|
if (isDescriptor) {
|
|
67
73
|
possibleDesc.set(obj, keyName, value);
|
|
68
|
-
} else if (
|
|
74
|
+
} else if (hasSetUnknownProperty(obj) && !(keyName in obj)) {
|
|
69
75
|
obj.setUnknownProperty(keyName, value);
|
|
70
76
|
} else {
|
|
71
77
|
if (DEBUG) {
|
|
@@ -92,79 +98,17 @@ function initialize(obj, properties) {
|
|
|
92
98
|
}
|
|
93
99
|
}
|
|
94
100
|
|
|
95
|
-
sendEvent(obj, 'init', undefined, undefined,
|
|
101
|
+
sendEvent(obj, 'init', undefined, undefined, m);
|
|
96
102
|
}
|
|
97
|
-
/**
|
|
98
|
-
`CoreObject` is the base class for all Ember constructs. It establishes a
|
|
99
|
-
class system based on Ember's Mixin system, and provides the basis for the
|
|
100
|
-
Ember Object Model. `CoreObject` should generally not be used directly,
|
|
101
|
-
instead you should use `EmberObject`.
|
|
102
|
-
|
|
103
|
-
## Usage
|
|
104
|
-
|
|
105
|
-
You can define a class by extending from `CoreObject` using the `extend`
|
|
106
|
-
method:
|
|
107
|
-
|
|
108
|
-
```js
|
|
109
|
-
const Person = CoreObject.extend({
|
|
110
|
-
name: 'Tomster',
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
For detailed usage, see the [Object Model](https://guides.emberjs.com/release/object-model/)
|
|
115
|
-
section of the guides.
|
|
116
|
-
|
|
117
|
-
## Usage with Native Classes
|
|
118
|
-
|
|
119
|
-
Native JavaScript `class` syntax can be used to extend from any `CoreObject`
|
|
120
|
-
based class:
|
|
121
|
-
|
|
122
|
-
```js
|
|
123
|
-
class Person extends CoreObject {
|
|
124
|
-
init() {
|
|
125
|
-
super.init(...arguments);
|
|
126
|
-
this.name = 'Tomster';
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Some notes about `class` usage:
|
|
132
|
-
|
|
133
|
-
* `new` syntax is not currently supported with classes that extend from
|
|
134
|
-
`EmberObject` or `CoreObject`. You must continue to use the `create` method
|
|
135
|
-
when making new instances of classes, even if they are defined using native
|
|
136
|
-
class syntax. If you want to use `new` syntax, consider creating classes
|
|
137
|
-
which do _not_ extend from `EmberObject` or `CoreObject`. Ember features,
|
|
138
|
-
such as computed properties and decorators, will still work with base-less
|
|
139
|
-
classes.
|
|
140
|
-
* Instead of using `this._super()`, you must use standard `super` syntax in
|
|
141
|
-
native classes. See the [MDN docs on classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Super_class_calls_with_super)
|
|
142
|
-
for more details.
|
|
143
|
-
* Native classes support using [constructors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Constructor)
|
|
144
|
-
to set up newly-created instances. Ember uses these to, among other things,
|
|
145
|
-
support features that need to retrieve other entities by name, like Service
|
|
146
|
-
injection and `getOwner`. To ensure your custom instance setup logic takes
|
|
147
|
-
place after this important work is done, avoid using the `constructor` in
|
|
148
|
-
favor of `init`.
|
|
149
|
-
* Properties passed to `create` will be available on the instance by the time
|
|
150
|
-
`init` runs, so any code that requires these values should work at that
|
|
151
|
-
time.
|
|
152
|
-
* Using native classes, and switching back to the old Ember Object model is
|
|
153
|
-
fully supported.
|
|
154
|
-
|
|
155
|
-
@class CoreObject
|
|
156
|
-
@public
|
|
157
|
-
*/
|
|
158
|
-
|
|
159
103
|
|
|
160
104
|
class CoreObject {
|
|
161
105
|
constructor(owner) {
|
|
162
106
|
this[OWNER] = owner; // prepare prototype...
|
|
163
107
|
|
|
164
108
|
this.constructor.proto();
|
|
165
|
-
let self
|
|
109
|
+
let self;
|
|
166
110
|
|
|
167
|
-
if (DEBUG &&
|
|
111
|
+
if (DEBUG && hasUnknownProperty(this)) {
|
|
168
112
|
let messageFor = (obj, property) => {
|
|
169
113
|
return `You attempted to access the \`${String(property)}\` property (of ${obj}).\n` + `Since Ember 3.1, this is usually fine as you no longer need to use \`.get()\`\n` + `to access computed properties. However, in this case, the object in question\n` + `is a special kind of Ember object (a proxy). Therefore, it is still necessary\n` + `to use \`.get('${String(property)}')\` in this case.\n\n` + `If you encountered this error because of third-party code that you don't control,\n` + `there is more information at https://github.com/emberjs/ember.js/issues/16148, and\n` + `you can help us improve this error message by telling us more about what happened in\n` + `this situation.`;
|
|
170
114
|
};
|
|
@@ -188,10 +132,13 @@ class CoreObject {
|
|
|
188
132
|
}
|
|
189
133
|
|
|
190
134
|
});
|
|
135
|
+
} else {
|
|
136
|
+
self = this;
|
|
191
137
|
}
|
|
192
138
|
|
|
139
|
+
const destroyable = self;
|
|
193
140
|
registerDestructor(self, ensureDestroyCalled, true);
|
|
194
|
-
registerDestructor(self, () =>
|
|
141
|
+
registerDestructor(self, () => destroyable.willDestroy()); // disable chains
|
|
195
142
|
|
|
196
143
|
let m = meta(self);
|
|
197
144
|
m.setInitializing(); // only return when in debug builds and `self` is the proxy created above
|
|
@@ -208,61 +155,61 @@ class CoreObject {
|
|
|
208
155
|
/**
|
|
209
156
|
An overridable method called when objects are instantiated. By default,
|
|
210
157
|
does nothing unless it is overridden during class definition.
|
|
211
|
-
|
|
212
|
-
|
|
158
|
+
Example:
|
|
159
|
+
```javascript
|
|
213
160
|
import EmberObject from '@ember/object';
|
|
214
|
-
|
|
161
|
+
const Person = EmberObject.extend({
|
|
215
162
|
init() {
|
|
216
163
|
alert(`Name is ${this.get('name')}`);
|
|
217
164
|
}
|
|
218
165
|
});
|
|
219
|
-
|
|
166
|
+
let steve = Person.create({
|
|
220
167
|
name: 'Steve'
|
|
221
168
|
});
|
|
222
|
-
|
|
169
|
+
// alerts 'Name is Steve'.
|
|
223
170
|
```
|
|
224
|
-
|
|
171
|
+
NOTE: If you do override `init` for a framework class like `Component`
|
|
225
172
|
from `@ember/component`, be sure to call `this._super(...arguments)`
|
|
226
173
|
in your `init` declaration!
|
|
227
174
|
If you don't, Ember may not have an opportunity to
|
|
228
175
|
do important setup work, and you'll see strange behavior in your
|
|
229
176
|
application.
|
|
230
|
-
|
|
177
|
+
@method init
|
|
231
178
|
@public
|
|
232
179
|
*/
|
|
233
180
|
|
|
234
181
|
|
|
235
|
-
init() {}
|
|
182
|
+
init(_properties) {}
|
|
236
183
|
/**
|
|
237
184
|
Defines the properties that will be concatenated from the superclass
|
|
238
185
|
(instead of overridden).
|
|
239
|
-
|
|
186
|
+
By default, when you extend an Ember class a property defined in
|
|
240
187
|
the subclass overrides a property with the same name that is defined
|
|
241
188
|
in the superclass. However, there are some cases where it is preferable
|
|
242
189
|
to build up a property's value by combining the superclass' property
|
|
243
190
|
value with the subclass' value. An example of this in use within Ember
|
|
244
191
|
is the `classNames` property of `Component` from `@ember/component`.
|
|
245
|
-
|
|
192
|
+
Here is some sample code showing the difference between a concatenated
|
|
246
193
|
property and a normal one:
|
|
247
|
-
|
|
194
|
+
```javascript
|
|
248
195
|
import EmberObject from '@ember/object';
|
|
249
|
-
|
|
196
|
+
const Bar = EmberObject.extend({
|
|
250
197
|
// Configure which properties to concatenate
|
|
251
198
|
concatenatedProperties: ['concatenatedProperty'],
|
|
252
|
-
|
|
199
|
+
someNonConcatenatedProperty: ['bar'],
|
|
253
200
|
concatenatedProperty: ['bar']
|
|
254
201
|
});
|
|
255
|
-
|
|
202
|
+
const FooBar = Bar.extend({
|
|
256
203
|
someNonConcatenatedProperty: ['foo'],
|
|
257
204
|
concatenatedProperty: ['foo']
|
|
258
205
|
});
|
|
259
|
-
|
|
206
|
+
let fooBar = FooBar.create();
|
|
260
207
|
fooBar.get('someNonConcatenatedProperty'); // ['foo']
|
|
261
208
|
fooBar.get('concatenatedProperty'); // ['bar', 'foo']
|
|
262
209
|
```
|
|
263
|
-
|
|
210
|
+
This behavior extends to object creation as well. Continuing the
|
|
264
211
|
above example:
|
|
265
|
-
|
|
212
|
+
```javascript
|
|
266
213
|
let fooBar = FooBar.create({
|
|
267
214
|
someNonConcatenatedProperty: ['baz'],
|
|
268
215
|
concatenatedProperty: ['baz']
|
|
@@ -270,23 +217,23 @@ class CoreObject {
|
|
|
270
217
|
fooBar.get('someNonConcatenatedProperty'); // ['baz']
|
|
271
218
|
fooBar.get('concatenatedProperty'); // ['bar', 'foo', 'baz']
|
|
272
219
|
```
|
|
273
|
-
|
|
274
|
-
|
|
220
|
+
Adding a single property that is not an array will just add it in the array:
|
|
221
|
+
```javascript
|
|
275
222
|
let fooBar = FooBar.create({
|
|
276
223
|
concatenatedProperty: 'baz'
|
|
277
224
|
})
|
|
278
225
|
view.get('concatenatedProperty'); // ['bar', 'foo', 'baz']
|
|
279
226
|
```
|
|
280
|
-
|
|
227
|
+
Using the `concatenatedProperties` property, we can tell Ember to mix the
|
|
281
228
|
content of the properties.
|
|
282
|
-
|
|
229
|
+
In `Component` the `classNames`, `classNameBindings` and
|
|
283
230
|
`attributeBindings` properties are concatenated.
|
|
284
|
-
|
|
231
|
+
This feature is available for you to use throughout the Ember object model,
|
|
285
232
|
although typical app developers are likely to use it infrequently. Since
|
|
286
233
|
it changes expectations about behavior of properties, you should properly
|
|
287
234
|
document its usage in each individual concatenated property (to not
|
|
288
235
|
mislead your users to think they can override the property in a subclass).
|
|
289
|
-
|
|
236
|
+
@property concatenatedProperties
|
|
290
237
|
@type Array
|
|
291
238
|
@default null
|
|
292
239
|
@public
|
|
@@ -295,20 +242,20 @@ class CoreObject {
|
|
|
295
242
|
/**
|
|
296
243
|
Defines the properties that will be merged from the superclass
|
|
297
244
|
(instead of overridden).
|
|
298
|
-
|
|
245
|
+
By default, when you extend an Ember class a property defined in
|
|
299
246
|
the subclass overrides a property with the same name that is defined
|
|
300
247
|
in the superclass. However, there are some cases where it is preferable
|
|
301
248
|
to build up a property's value by merging the superclass property value
|
|
302
249
|
with the subclass property's value. An example of this in use within Ember
|
|
303
250
|
is the `queryParams` property of routes.
|
|
304
|
-
|
|
251
|
+
Here is some sample code showing the difference between a merged
|
|
305
252
|
property and a normal one:
|
|
306
|
-
|
|
253
|
+
```javascript
|
|
307
254
|
import EmberObject from '@ember/object';
|
|
308
|
-
|
|
255
|
+
const Bar = EmberObject.extend({
|
|
309
256
|
// Configure which properties are to be merged
|
|
310
257
|
mergedProperties: ['mergedProperty'],
|
|
311
|
-
|
|
258
|
+
someNonMergedProperty: {
|
|
312
259
|
nonMerged: 'superclass value of nonMerged'
|
|
313
260
|
},
|
|
314
261
|
mergedProperty: {
|
|
@@ -316,7 +263,7 @@ class CoreObject {
|
|
|
316
263
|
limit: { replace: true }
|
|
317
264
|
}
|
|
318
265
|
});
|
|
319
|
-
|
|
266
|
+
const FooBar = Bar.extend({
|
|
320
267
|
someNonMergedProperty: {
|
|
321
268
|
completelyNonMerged: 'subclass value of nonMerged'
|
|
322
269
|
},
|
|
@@ -324,13 +271,13 @@ class CoreObject {
|
|
|
324
271
|
limit: { replace: false }
|
|
325
272
|
}
|
|
326
273
|
});
|
|
327
|
-
|
|
328
|
-
|
|
274
|
+
let fooBar = FooBar.create();
|
|
275
|
+
fooBar.get('someNonMergedProperty');
|
|
329
276
|
// => { completelyNonMerged: 'subclass value of nonMerged' }
|
|
330
277
|
//
|
|
331
278
|
// Note the entire object, including the nonMerged property of
|
|
332
279
|
// the superclass object, has been replaced
|
|
333
|
-
|
|
280
|
+
fooBar.get('mergedProperty');
|
|
334
281
|
// => {
|
|
335
282
|
// page: {replace: false},
|
|
336
283
|
// limit: {replace: false}
|
|
@@ -340,15 +287,15 @@ class CoreObject {
|
|
|
340
287
|
// `limit` property's value of `false` has been merged from
|
|
341
288
|
// the subclass.
|
|
342
289
|
```
|
|
343
|
-
|
|
290
|
+
This behavior is not available during object `create` calls. It is only
|
|
344
291
|
available at `extend` time.
|
|
345
|
-
|
|
346
|
-
|
|
292
|
+
In `Route` the `queryParams` property is merged.
|
|
293
|
+
This feature is available for you to use throughout the Ember object model,
|
|
347
294
|
although typical app developers are likely to use it infrequently. Since
|
|
348
295
|
it changes expectations about behavior of properties, you should properly
|
|
349
296
|
document its usage in each individual merged property (to not
|
|
350
297
|
mislead your users to think they can override the property in a subclass).
|
|
351
|
-
|
|
298
|
+
@property mergedProperties
|
|
352
299
|
@type Array
|
|
353
300
|
@default null
|
|
354
301
|
@public
|
|
@@ -356,9 +303,9 @@ class CoreObject {
|
|
|
356
303
|
|
|
357
304
|
/**
|
|
358
305
|
Destroyed object property flag.
|
|
359
|
-
|
|
306
|
+
if this property is `true` the observers and bindings were already
|
|
360
307
|
removed by the effect of calling the `destroy()` method.
|
|
361
|
-
|
|
308
|
+
@property isDestroyed
|
|
362
309
|
@default false
|
|
363
310
|
@public
|
|
364
311
|
*/
|
|
@@ -368,14 +315,14 @@ class CoreObject {
|
|
|
368
315
|
return isDestroyed(this);
|
|
369
316
|
}
|
|
370
317
|
|
|
371
|
-
set isDestroyed(
|
|
318
|
+
set isDestroyed(_value) {
|
|
372
319
|
assert(`You cannot set \`${this}.isDestroyed\` directly, please use \`.destroy()\`.`, false);
|
|
373
320
|
}
|
|
374
321
|
/**
|
|
375
322
|
Destruction scheduled flag. The `destroy()` method has been called.
|
|
376
|
-
|
|
323
|
+
The object stays intact until the end of the run loop at which point
|
|
377
324
|
the `isDestroyed` flag is set.
|
|
378
|
-
|
|
325
|
+
@property isDestroying
|
|
379
326
|
@default false
|
|
380
327
|
@public
|
|
381
328
|
*/
|
|
@@ -385,17 +332,17 @@ class CoreObject {
|
|
|
385
332
|
return isDestroying(this);
|
|
386
333
|
}
|
|
387
334
|
|
|
388
|
-
set isDestroying(
|
|
335
|
+
set isDestroying(_value) {
|
|
389
336
|
assert(`You cannot set \`${this}.isDestroying\` directly, please use \`.destroy()\`.`, false);
|
|
390
337
|
}
|
|
391
338
|
/**
|
|
392
339
|
Destroys an object by setting the `isDestroyed` flag and removing its
|
|
393
340
|
metadata, which effectively destroys observers and bindings.
|
|
394
|
-
|
|
341
|
+
If you try to set a property on a destroyed object, an exception will be
|
|
395
342
|
raised.
|
|
396
|
-
|
|
343
|
+
Note that destruction is scheduled for the end of the run loop and does not
|
|
397
344
|
happen immediately. It will set an isDestroying flag immediately.
|
|
398
|
-
|
|
345
|
+
@method destroy
|
|
399
346
|
@return {EmberObject} receiver
|
|
400
347
|
@public
|
|
401
348
|
*/
|
|
@@ -415,7 +362,7 @@ class CoreObject {
|
|
|
415
362
|
}
|
|
416
363
|
/**
|
|
417
364
|
Override to implement teardown.
|
|
418
|
-
|
|
365
|
+
@method willDestroy
|
|
419
366
|
@public
|
|
420
367
|
*/
|
|
421
368
|
|
|
@@ -425,22 +372,22 @@ class CoreObject {
|
|
|
425
372
|
Returns a string representation which attempts to provide more information
|
|
426
373
|
than Javascript's `toString` typically does, in a generic way for all Ember
|
|
427
374
|
objects.
|
|
428
|
-
|
|
375
|
+
```javascript
|
|
429
376
|
import EmberObject from '@ember/object';
|
|
430
|
-
|
|
377
|
+
const Person = EmberObject.extend();
|
|
431
378
|
person = Person.create();
|
|
432
379
|
person.toString(); //=> "<Person:ember1024>"
|
|
433
380
|
```
|
|
434
|
-
|
|
381
|
+
If the object's class is not defined on an Ember namespace, it will
|
|
435
382
|
indicate it is a subclass of the registered superclass:
|
|
436
|
-
|
|
383
|
+
```javascript
|
|
437
384
|
const Student = Person.extend();
|
|
438
385
|
let student = Student.create();
|
|
439
386
|
student.toString(); //=> "<(subclass of Person):ember1025>"
|
|
440
387
|
```
|
|
441
|
-
|
|
388
|
+
If the method `toStringExtension` is defined, its return value will be
|
|
442
389
|
included in the output.
|
|
443
|
-
|
|
390
|
+
```javascript
|
|
444
391
|
const Teacher = Person.extend({
|
|
445
392
|
toStringExtension() {
|
|
446
393
|
return this.get('fullName');
|
|
@@ -449,133 +396,25 @@ class CoreObject {
|
|
|
449
396
|
teacher = Teacher.create();
|
|
450
397
|
teacher.toString(); //=> "<Teacher:ember1026:Tom Dale>"
|
|
451
398
|
```
|
|
452
|
-
|
|
399
|
+
@method toString
|
|
453
400
|
@return {String} string representation
|
|
454
401
|
@public
|
|
455
402
|
*/
|
|
456
403
|
|
|
457
404
|
|
|
458
405
|
toString() {
|
|
459
|
-
let
|
|
460
|
-
let extension = hasToStringExtension ? `:${this.toStringExtension()}` : '';
|
|
406
|
+
let extension = hasToStringExtension(this) ? `:${this.toStringExtension()}` : '';
|
|
461
407
|
return `<${getFactoryFor(this) || '(unknown)'}:${guidFor(this)}${extension}>`;
|
|
462
408
|
}
|
|
463
|
-
/**
|
|
464
|
-
Creates a new subclass.
|
|
465
|
-
```javascript
|
|
466
|
-
import EmberObject from '@ember/object';
|
|
467
|
-
const Person = EmberObject.extend({
|
|
468
|
-
say(thing) {
|
|
469
|
-
alert(thing);
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
```
|
|
473
|
-
This defines a new subclass of EmberObject: `Person`. It contains one method: `say()`.
|
|
474
|
-
You can also create a subclass from any existing class by calling its `extend()` method.
|
|
475
|
-
For example, you might want to create a subclass of Ember's built-in `Component` class:
|
|
476
|
-
```javascript
|
|
477
|
-
import Component from '@ember/component';
|
|
478
|
-
const PersonComponent = Component.extend({
|
|
479
|
-
tagName: 'li',
|
|
480
|
-
classNameBindings: ['isAdministrator']
|
|
481
|
-
});
|
|
482
|
-
```
|
|
483
|
-
When defining a subclass, you can override methods but still access the
|
|
484
|
-
implementation of your parent class by calling the special `_super()` method:
|
|
485
|
-
```javascript
|
|
486
|
-
import EmberObject from '@ember/object';
|
|
487
|
-
const Person = EmberObject.extend({
|
|
488
|
-
say(thing) {
|
|
489
|
-
let name = this.get('name');
|
|
490
|
-
alert(`${name} says: ${thing}`);
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
const Soldier = Person.extend({
|
|
494
|
-
say(thing) {
|
|
495
|
-
this._super(`${thing}, sir!`);
|
|
496
|
-
},
|
|
497
|
-
march(numberOfHours) {
|
|
498
|
-
alert(`${this.get('name')} marches for ${numberOfHours} hours.`);
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
let yehuda = Soldier.create({
|
|
502
|
-
name: 'Yehuda Katz'
|
|
503
|
-
});
|
|
504
|
-
yehuda.say('Yes'); // alerts "Yehuda Katz says: Yes, sir!"
|
|
505
|
-
```
|
|
506
|
-
The `create()` on line #17 creates an *instance* of the `Soldier` class.
|
|
507
|
-
The `extend()` on line #8 creates a *subclass* of `Person`. Any instance
|
|
508
|
-
of the `Person` class will *not* have the `march()` method.
|
|
509
|
-
You can also pass `Mixin` classes to add additional properties to the subclass.
|
|
510
|
-
```javascript
|
|
511
|
-
import EmberObject from '@ember/object';
|
|
512
|
-
import Mixin from '@ember/object/mixin';
|
|
513
|
-
const Person = EmberObject.extend({
|
|
514
|
-
say(thing) {
|
|
515
|
-
alert(`${this.get('name')} says: ${thing}`);
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
const SingingMixin = Mixin.create({
|
|
519
|
-
sing(thing) {
|
|
520
|
-
alert(`${this.get('name')} sings: la la la ${thing}`);
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
const BroadwayStar = Person.extend(SingingMixin, {
|
|
524
|
-
dance() {
|
|
525
|
-
alert(`${this.get('name')} dances: tap tap tap tap `);
|
|
526
|
-
}
|
|
527
|
-
});
|
|
528
|
-
```
|
|
529
|
-
The `BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`.
|
|
530
|
-
@method extend
|
|
531
|
-
@static
|
|
532
|
-
@for @ember/object
|
|
533
|
-
@param {Mixin} [mixins]* One or more Mixin classes
|
|
534
|
-
@param {Object} [arguments]* Object containing values to use within the new class
|
|
535
|
-
@public
|
|
536
|
-
*/
|
|
537
409
|
|
|
538
|
-
|
|
539
|
-
static extend() {
|
|
410
|
+
static extend(...mixins) {
|
|
540
411
|
let Class = class extends this {};
|
|
541
|
-
reopen.apply(Class.PrototypeMixin,
|
|
412
|
+
reopen.apply(Class.PrototypeMixin, mixins);
|
|
542
413
|
return Class;
|
|
543
414
|
}
|
|
544
|
-
/**
|
|
545
|
-
Creates an instance of a class. Accepts either no arguments, or an object
|
|
546
|
-
containing values to initialize the newly instantiated object with.
|
|
547
|
-
```javascript
|
|
548
|
-
import EmberObject from '@ember/object';
|
|
549
|
-
const Person = EmberObject.extend({
|
|
550
|
-
helloWorld() {
|
|
551
|
-
alert(`Hi, my name is ${this.get('name')}`);
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
let tom = Person.create({
|
|
555
|
-
name: 'Tom Dale'
|
|
556
|
-
});
|
|
557
|
-
tom.helloWorld(); // alerts "Hi, my name is Tom Dale".
|
|
558
|
-
```
|
|
559
|
-
`create` will call the `init` function if defined during
|
|
560
|
-
`AnyObject.extend`
|
|
561
|
-
If no arguments are passed to `create`, it will not set values to the new
|
|
562
|
-
instance during initialization:
|
|
563
|
-
```javascript
|
|
564
|
-
let noName = Person.create();
|
|
565
|
-
noName.helloWorld(); // alerts undefined
|
|
566
|
-
```
|
|
567
|
-
NOTE: For performance reasons, you cannot declare methods or computed
|
|
568
|
-
properties during `create`. You should instead declare methods and computed
|
|
569
|
-
properties when using `extend`.
|
|
570
|
-
@method create
|
|
571
|
-
@for @ember/object
|
|
572
|
-
@static
|
|
573
|
-
@param [arguments]*
|
|
574
|
-
@public
|
|
575
|
-
*/
|
|
576
|
-
|
|
577
415
|
|
|
578
|
-
static create(
|
|
416
|
+
static create(...args) {
|
|
417
|
+
let props = args[0];
|
|
579
418
|
let instance;
|
|
580
419
|
|
|
581
420
|
if (props !== undefined) {
|
|
@@ -585,10 +424,10 @@ class CoreObject {
|
|
|
585
424
|
instance = new this();
|
|
586
425
|
}
|
|
587
426
|
|
|
588
|
-
if (
|
|
427
|
+
if (args.length <= 1) {
|
|
589
428
|
initialize(instance, props);
|
|
590
429
|
} else {
|
|
591
|
-
initialize(instance, flattenProps.apply(this,
|
|
430
|
+
initialize(instance, flattenProps.apply(this, args));
|
|
592
431
|
}
|
|
593
432
|
|
|
594
433
|
return instance;
|
|
@@ -596,34 +435,34 @@ class CoreObject {
|
|
|
596
435
|
/**
|
|
597
436
|
Augments a constructor's prototype with additional
|
|
598
437
|
properties and functions:
|
|
599
|
-
|
|
438
|
+
```javascript
|
|
600
439
|
import EmberObject from '@ember/object';
|
|
601
|
-
|
|
440
|
+
const MyObject = EmberObject.extend({
|
|
602
441
|
name: 'an object'
|
|
603
442
|
});
|
|
604
|
-
|
|
443
|
+
o = MyObject.create();
|
|
605
444
|
o.get('name'); // 'an object'
|
|
606
|
-
|
|
445
|
+
MyObject.reopen({
|
|
607
446
|
say(msg) {
|
|
608
447
|
console.log(msg);
|
|
609
448
|
}
|
|
610
449
|
});
|
|
611
|
-
|
|
450
|
+
o2 = MyObject.create();
|
|
612
451
|
o2.say('hello'); // logs "hello"
|
|
613
|
-
|
|
452
|
+
o.say('goodbye'); // logs "goodbye"
|
|
614
453
|
```
|
|
615
|
-
|
|
454
|
+
To add functions and properties to the constructor itself,
|
|
616
455
|
see `reopenClass`
|
|
617
|
-
|
|
456
|
+
@method reopen
|
|
618
457
|
@for @ember/object
|
|
619
458
|
@static
|
|
620
459
|
@public
|
|
621
460
|
*/
|
|
622
461
|
|
|
623
462
|
|
|
624
|
-
static reopen() {
|
|
463
|
+
static reopen(...args) {
|
|
625
464
|
this.willReopen();
|
|
626
|
-
reopen.apply(this.PrototypeMixin,
|
|
465
|
+
reopen.apply(this.PrototypeMixin, args);
|
|
627
466
|
return this;
|
|
628
467
|
}
|
|
629
468
|
|
|
@@ -642,55 +481,55 @@ class CoreObject {
|
|
|
642
481
|
}
|
|
643
482
|
/**
|
|
644
483
|
Augments a constructor's own properties and functions:
|
|
645
|
-
|
|
484
|
+
```javascript
|
|
646
485
|
import EmberObject from '@ember/object';
|
|
647
|
-
|
|
486
|
+
const MyObject = EmberObject.extend({
|
|
648
487
|
name: 'an object'
|
|
649
488
|
});
|
|
650
|
-
|
|
489
|
+
MyObject.reopenClass({
|
|
651
490
|
canBuild: false
|
|
652
491
|
});
|
|
653
|
-
|
|
492
|
+
MyObject.canBuild; // false
|
|
654
493
|
o = MyObject.create();
|
|
655
494
|
```
|
|
656
|
-
|
|
495
|
+
In other words, this creates static properties and functions for the class.
|
|
657
496
|
These are only available on the class and not on any instance of that class.
|
|
658
|
-
|
|
497
|
+
```javascript
|
|
659
498
|
import EmberObject from '@ember/object';
|
|
660
|
-
|
|
499
|
+
const Person = EmberObject.extend({
|
|
661
500
|
name: '',
|
|
662
501
|
sayHello() {
|
|
663
502
|
alert(`Hello. My name is ${this.get('name')}`);
|
|
664
503
|
}
|
|
665
504
|
});
|
|
666
|
-
|
|
505
|
+
Person.reopenClass({
|
|
667
506
|
species: 'Homo sapiens',
|
|
668
|
-
|
|
507
|
+
createPerson(name) {
|
|
669
508
|
return Person.create({ name });
|
|
670
509
|
}
|
|
671
510
|
});
|
|
672
|
-
|
|
511
|
+
let tom = Person.create({
|
|
673
512
|
name: 'Tom Dale'
|
|
674
513
|
});
|
|
675
514
|
let yehuda = Person.createPerson('Yehuda Katz');
|
|
676
|
-
|
|
515
|
+
tom.sayHello(); // "Hello. My name is Tom Dale"
|
|
677
516
|
yehuda.sayHello(); // "Hello. My name is Yehuda Katz"
|
|
678
517
|
alert(Person.species); // "Homo sapiens"
|
|
679
518
|
```
|
|
680
|
-
|
|
519
|
+
Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda`
|
|
681
520
|
variables. They are only valid on `Person`.
|
|
682
|
-
|
|
521
|
+
To add functions and properties to instances of
|
|
683
522
|
a constructor by extending the constructor's prototype
|
|
684
523
|
see `reopen`
|
|
685
|
-
|
|
524
|
+
@method reopenClass
|
|
686
525
|
@for @ember/object
|
|
687
526
|
@static
|
|
688
527
|
@public
|
|
689
528
|
*/
|
|
690
529
|
|
|
691
530
|
|
|
692
|
-
static reopenClass() {
|
|
693
|
-
applyMixin(this,
|
|
531
|
+
static reopenClass(...mixins) {
|
|
532
|
+
applyMixin(this, mixins);
|
|
694
533
|
return this;
|
|
695
534
|
}
|
|
696
535
|
|
|
@@ -718,21 +557,21 @@ class CoreObject {
|
|
|
718
557
|
metadata about how they function or what values they operate on. For
|
|
719
558
|
example, computed property functions may close over variables that are then
|
|
720
559
|
no longer available for introspection.
|
|
721
|
-
|
|
722
|
-
|
|
560
|
+
You can pass a hash of these values to a computed property like this:
|
|
561
|
+
```javascript
|
|
723
562
|
import { computed } from '@ember/object';
|
|
724
|
-
|
|
563
|
+
person: computed(function() {
|
|
725
564
|
let personId = this.get('personId');
|
|
726
565
|
return Person.create({ id: personId });
|
|
727
566
|
}).meta({ type: Person })
|
|
728
567
|
```
|
|
729
|
-
|
|
568
|
+
Once you've done this, you can retrieve the values saved to the computed
|
|
730
569
|
property from your class like this:
|
|
731
|
-
|
|
570
|
+
```javascript
|
|
732
571
|
MyClass.metaForProperty('person');
|
|
733
572
|
```
|
|
734
|
-
|
|
735
|
-
|
|
573
|
+
This will return the original hash that was passed to `meta()`.
|
|
574
|
+
@static
|
|
736
575
|
@method metaForProperty
|
|
737
576
|
@param key {String} property name
|
|
738
577
|
@private
|
|
@@ -749,7 +588,7 @@ class CoreObject {
|
|
|
749
588
|
/**
|
|
750
589
|
Iterate over each computed property for the class, passing its name
|
|
751
590
|
and any associated metadata (see `metaForProperty`) to the callback.
|
|
752
|
-
|
|
591
|
+
@static
|
|
753
592
|
@method eachComputedProperty
|
|
754
593
|
@param {Function} callback
|
|
755
594
|
@param {Object} binding
|
|
@@ -817,38 +656,15 @@ CoreObject.isClass = true;
|
|
|
817
656
|
CoreObject.isMethod = false;
|
|
818
657
|
|
|
819
658
|
function flattenProps(...props) {
|
|
820
|
-
let {
|
|
821
|
-
concatenatedProperties,
|
|
822
|
-
mergedProperties
|
|
823
|
-
} = this;
|
|
824
|
-
let hasConcatenatedProps = concatenatedProperties !== undefined && concatenatedProperties.length > 0;
|
|
825
|
-
let hasMergedProps = mergedProperties !== undefined && mergedProperties.length > 0;
|
|
826
659
|
let initProperties = {};
|
|
827
660
|
|
|
828
|
-
for (let
|
|
829
|
-
let properties = props[i];
|
|
661
|
+
for (let properties of props) {
|
|
830
662
|
assert('EmberObject.create no longer supports mixing in other ' + 'definitions, use .extend & .create separately instead.', !(properties instanceof Mixin));
|
|
831
663
|
let keyNames = Object.keys(properties);
|
|
832
664
|
|
|
833
665
|
for (let j = 0, k = keyNames.length; j < k; j++) {
|
|
834
666
|
let keyName = keyNames[j];
|
|
835
667
|
let value = properties[keyName];
|
|
836
|
-
|
|
837
|
-
if (hasConcatenatedProps && concatenatedProperties.indexOf(keyName) > -1) {
|
|
838
|
-
let baseValue = initProperties[keyName];
|
|
839
|
-
|
|
840
|
-
if (baseValue) {
|
|
841
|
-
value = makeArray(baseValue).concat(value);
|
|
842
|
-
} else {
|
|
843
|
-
value = makeArray(value);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
if (hasMergedProps && mergedProperties.indexOf(keyName) > -1) {
|
|
848
|
-
let baseValue = initProperties[keyName];
|
|
849
|
-
value = Object.assign({}, baseValue, value);
|
|
850
|
-
}
|
|
851
|
-
|
|
852
668
|
initProperties[keyName] = value;
|
|
853
669
|
}
|
|
854
670
|
}
|
|
@@ -859,7 +675,7 @@ function flattenProps(...props) {
|
|
|
859
675
|
if (DEBUG) {
|
|
860
676
|
/**
|
|
861
677
|
Provides lookup-time type validation for injected properties.
|
|
862
|
-
|
|
678
|
+
@private
|
|
863
679
|
@method _onLookup
|
|
864
680
|
*/
|
|
865
681
|
CoreObject._onLookup = function injectedPropertyAssertion(debugContainerKey) {
|
|
@@ -877,7 +693,7 @@ if (DEBUG) {
|
|
|
877
693
|
/**
|
|
878
694
|
Returns a hash of property names and container names that injected
|
|
879
695
|
properties will lookup on the container lazily.
|
|
880
|
-
|
|
696
|
+
@method _lazyInjections
|
|
881
697
|
@return {Object} Hash of all lazy injected property keys to container names
|
|
882
698
|
@private
|
|
883
699
|
*/
|