ember-inspector 4.11.0-alpha.2024.3.9 → 4.11.0-alpha.2024.4.2
Sign up to get free protection for your applications and to get access to all the features.
- package/app/components/component-tree-arg.js +9 -0
- package/app/components/component-tree-item.hbs +18 -2
- package/app/components/object-inspector/properties-all.hbs +1 -0
- package/app/components/object-inspector/properties-base.js +10 -0
- package/app/components/object-inspector/properties-grouped.hbs +1 -0
- package/app/components/object-inspector/property.hbs +12 -1
- package/app/components/object-inspector/property.ts +4 -2
- package/app/components/object-inspector.hbs +16 -2
- package/app/components/object-inspector.js +14 -0
- package/app/controllers/component-tree.js +54 -3
- package/app/routes/component-tree.js +0 -6
- package/app/services/adapters/web-extension.js +3 -3
- package/app/services/port.js +4 -0
- package/app/styles/component_tree.scss +13 -0
- package/app/utils/parse-text.ts +1 -0
- package/dist/bookmarklet/panes-3-16-0/assets/{chunk.143.ac621af5331b75527946.js → chunk.143.9f3a22b07387ec438672.js} +4 -4
- package/dist/{firefox/panes-3-16-0/assets/chunk.178.e6b2f8bb19b9f072aa49.js → bookmarklet/panes-3-16-0/assets/chunk.178.4fe3df60bd7ba157b035.js} +3 -3
- package/dist/bookmarklet/panes-3-16-0/assets/ember-inspector.css +13 -0
- package/dist/bookmarklet/panes-3-16-0/assets/ember-inspector.js +27 -23
- package/dist/bookmarklet/panes-3-16-0/assets/svg/code-source.svg +9 -0
- package/dist/bookmarklet/panes-3-16-0/assets/vendor.css +33 -0
- package/dist/bookmarklet/panes-3-16-0/assets/vendor.js +12 -10
- package/dist/bookmarklet/panes-3-16-0/ember_debug.js +408 -538
- package/dist/bookmarklet/panes-3-16-0/index.html +2 -2
- package/dist/chrome/manifest.json +2 -2
- package/dist/{firefox/panes-3-16-0/assets/chunk.143.ac621af5331b75527946.js → chrome/panes-3-16-0/assets/chunk.143.9f3a22b07387ec438672.js} +4 -4
- package/dist/{bookmarklet/panes-3-16-0/assets/chunk.178.e6b2f8bb19b9f072aa49.js → chrome/panes-3-16-0/assets/chunk.178.4fe3df60bd7ba157b035.js} +3 -3
- package/dist/chrome/panes-3-16-0/assets/ember-inspector.css +13 -0
- package/dist/chrome/panes-3-16-0/assets/ember-inspector.js +27 -23
- package/dist/chrome/panes-3-16-0/assets/svg/code-source.svg +9 -0
- package/dist/chrome/panes-3-16-0/assets/vendor.css +33 -0
- package/dist/chrome/panes-3-16-0/assets/vendor.js +12 -10
- package/dist/chrome/panes-3-16-0/ember_debug.js +408 -538
- package/dist/chrome/panes-3-16-0/index.html +2 -2
- package/dist/firefox/manifest.json +2 -2
- package/dist/{chrome/panes-3-16-0/assets/chunk.143.ac621af5331b75527946.js → firefox/panes-3-16-0/assets/chunk.143.9f3a22b07387ec438672.js} +4 -4
- package/dist/{websocket/assets/chunk.178.e6b2f8bb19b9f072aa49.js → firefox/panes-3-16-0/assets/chunk.178.4fe3df60bd7ba157b035.js} +3 -3
- package/dist/firefox/panes-3-16-0/assets/ember-inspector.css +13 -0
- package/dist/firefox/panes-3-16-0/assets/ember-inspector.js +27 -23
- package/dist/firefox/panes-3-16-0/assets/svg/code-source.svg +9 -0
- package/dist/firefox/panes-3-16-0/assets/vendor.css +33 -0
- package/dist/firefox/panes-3-16-0/assets/vendor.js +12 -10
- package/dist/firefox/panes-3-16-0/ember_debug.js +408 -538
- package/dist/firefox/panes-3-16-0/index.html +2 -2
- package/dist/websocket/assets/{chunk.143.ac621af5331b75527946.js → chunk.143.9f3a22b07387ec438672.js} +4 -4
- package/dist/{chrome/panes-3-16-0/assets/chunk.178.e6b2f8bb19b9f072aa49.js → websocket/assets/chunk.178.4fe3df60bd7ba157b035.js} +3 -3
- package/dist/websocket/assets/ember-inspector.css +13 -0
- package/dist/websocket/assets/ember-inspector.js +27 -23
- package/dist/websocket/assets/svg/code-source.svg +9 -0
- package/dist/websocket/assets/vendor.css +33 -0
- package/dist/websocket/assets/vendor.js +12 -10
- package/dist/websocket/ember_debug.js +408 -538
- package/dist/websocket/index.html +2 -2
- package/ember-cli-build.js +3 -4
- package/ember_debug/adapters/basic.js +4 -4
- package/ember_debug/adapters/web-extension.js +9 -5
- package/ember_debug/general-debug.js +3 -1
- package/ember_debug/libs/capture-render-tree.js +7 -426
- package/ember_debug/libs/render-tree.js +210 -31
- package/ember_debug/libs/view-inspection.js +28 -0
- package/ember_debug/object-inspector.js +49 -88
- package/ember_debug/route-debug.js +2 -3
- package/ember_debug/utils/ember.js +16 -0
- package/ember_debug/utils/get-object-name.js +4 -0
- package/ember_debug/utils/name-functions.js +1 -1
- package/ember_debug/utils/type-check.js +82 -12
- package/ember_debug/utils/version.js +37 -0
- package/ember_debug/view-debug.js +1 -1
- package/lib/ui/addon/styles/_goto-source.scss +30 -0
- package/lib/ui/addon/styles/addon.scss +1 -0
- package/lib/ui/addon/styles/toolbar/_index.scss +4 -0
- package/package.json +1 -1
- package/public/assets/svg/code-source.svg +9 -0
- package/skeletons/web-extension/manifest.json +2 -2
- package/tests/acceptance/object-inspector-test.js +68 -0
- package/tests/ember_debug/view-debug-test.js +211 -69
- package/tests/index.html +1 -0
@@ -9,7 +9,7 @@
|
|
9
9
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
10
10
|
|
11
11
|
|
12
|
-
<meta name="ember-inspector/config/environment" content="%7B%22modulePrefix%22%3A%22ember-inspector%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22hash%22%2C%22version%22%3A%224.11.0-alpha.2024.
|
12
|
+
<meta name="ember-inspector/config/environment" content="%7B%22modulePrefix%22%3A%22ember-inspector%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22hash%22%2C%22version%22%3A%224.11.0-alpha.2024.4.2%2Be4d8062%22%2C%22emberVersionsSupported%22%3A%5B%223.16.0%22%2C%22%22%5D%2C%22previousEmberVersionsSupported%22%3A%5B%220.0.0%22%2C%222.7.0%22%2C%223.4.0%22%5D%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22ember-inspector%22%2C%22version%22%3A%224.11.0-alpha.2024.4.2%2Be4d8062%2Be4d8062b%22%7D%7D" />
|
13
13
|
|
14
14
|
<style type="text/css">
|
15
15
|
@font-face {
|
@@ -39,7 +39,7 @@
|
|
39
39
|
|
40
40
|
<script src="assets/vendor.js"></script>
|
41
41
|
<script src="assets/chunk.359.0be5d21f60d2b5d6d423.js"></script>
|
42
|
-
<script src="assets/chunk.143.
|
42
|
+
<script src="assets/chunk.143.9f3a22b07387ec438672.js"></script>
|
43
43
|
<script src="assets/ember-inspector.js"></script>
|
44
44
|
|
45
45
|
|
package/ember-cli-build.js
CHANGED
@@ -381,19 +381,18 @@ module.exports = function (defaults) {
|
|
381
381
|
if (env === 'test') {
|
382
382
|
// `ember test` expects the index.html file to be in the
|
383
383
|
// output directory.
|
384
|
-
output = mergeTrees([dists.basic, dists.chrome]);
|
385
|
-
} else {
|
386
384
|
// Change base tag for running tests in development env.
|
387
385
|
dists.basic = replace(dists.basic, {
|
388
386
|
files: ['tests/index.html'],
|
389
387
|
patterns: [
|
390
388
|
{
|
391
389
|
match: /<base.*\/>/,
|
392
|
-
replacement: '
|
390
|
+
replacement: '',
|
393
391
|
},
|
394
392
|
],
|
395
393
|
});
|
396
|
-
|
394
|
+
output = mergeTrees([dists.basic, dists.chrome]);
|
395
|
+
} else {
|
397
396
|
dists.testing = mergeTrees([dists.basic, dists.chrome]);
|
398
397
|
|
399
398
|
output = mergeTrees([
|
@@ -61,17 +61,17 @@ export default class BasicAdapter extends BaseObject {
|
|
61
61
|
}
|
62
62
|
|
63
63
|
/**
|
64
|
-
Inspect a specific DOM node. This usually
|
64
|
+
Inspect a js value or specific DOM node. This usually
|
65
65
|
means using the current environment's tools
|
66
66
|
to inspect the node in the DOM.
|
67
67
|
|
68
68
|
For example, in chrome, `inspect(node)`
|
69
69
|
will open the Elements tab in dev tools
|
70
70
|
and highlight the DOM node.
|
71
|
-
|
72
|
-
@param {Node} node
|
71
|
+
For functions, it will open the sources tab and goto the definition
|
72
|
+
@param {Node|Function} node
|
73
73
|
*/
|
74
|
-
|
74
|
+
inspectValue(/* value */) {}
|
75
75
|
|
76
76
|
_messageReceived(message) {
|
77
77
|
this._messageCallbacks.forEach((callback) => {
|
@@ -28,15 +28,19 @@ export default class extends BasicAdapter {
|
|
28
28
|
// "clone" them through postMessage unless they are converted to a
|
29
29
|
// native array.
|
30
30
|
options = deepClone(options);
|
31
|
-
|
31
|
+
try {
|
32
|
+
this._chromePort.postMessage(options);
|
33
|
+
} catch (e) {
|
34
|
+
console.log('failed to send message', e);
|
35
|
+
}
|
32
36
|
}
|
33
37
|
|
34
38
|
/**
|
35
39
|
* Open the devtools "Elements" and select an DOM node.
|
36
40
|
*
|
37
|
-
* @param {Node}
|
41
|
+
* @param {Node|Function} value The DOM node to select
|
38
42
|
*/
|
39
|
-
|
43
|
+
inspectValue(value) {
|
40
44
|
// NOTE:
|
41
45
|
//
|
42
46
|
// Basically, we are just trying to call `inspect(node)` here.
|
@@ -58,9 +62,9 @@ export default class extends BasicAdapter {
|
|
58
62
|
|
59
63
|
let name = `__EMBER_INSPECTOR_${(Math.random() * 100000000).toFixed(0)}`;
|
60
64
|
|
61
|
-
window[name] =
|
65
|
+
window[name] = value;
|
62
66
|
|
63
|
-
this.namespace.port.send('view:
|
67
|
+
this.namespace.port.send('view:inspectJSValue', { name });
|
64
68
|
}
|
65
69
|
|
66
70
|
_listen() {
|
@@ -87,7 +87,9 @@ export default class extends DebugPort {
|
|
87
87
|
* the info tab.
|
88
88
|
*/
|
89
89
|
getLibraries() {
|
90
|
-
this.sendMessage('libraries', {
|
90
|
+
this.sendMessage('libraries', {
|
91
|
+
libraries: Ember.libraries?._registry,
|
92
|
+
});
|
91
93
|
},
|
92
94
|
|
93
95
|
getEmberCliConfig() {
|
@@ -1,434 +1,15 @@
|
|
1
|
-
import {
|
2
|
-
import Ember from 'ember-debug/utils/ember';
|
1
|
+
import { captureRenderTree, getEnv } from 'ember-debug/utils/ember';
|
3
2
|
|
4
3
|
/* eslint-disable no-console, no-inner-declarations */
|
5
|
-
|
6
|
-
let captureRenderTree;
|
7
|
-
|
4
|
+
let capture = captureRenderTree;
|
8
5
|
// Ember 3.14+ comes with debug render tree, but the version in 3.14.0/3.14.1 is buggy
|
9
|
-
if (
|
10
|
-
if (
|
11
|
-
|
6
|
+
if (captureRenderTree) {
|
7
|
+
if (getEnv()._DEBUG_RENDER_TREE) {
|
8
|
+
capture = captureRenderTree;
|
12
9
|
} else {
|
13
|
-
|
10
|
+
capture = function captureRenderTree() {
|
14
11
|
return [];
|
15
12
|
};
|
16
13
|
}
|
17
|
-
} else {
|
18
|
-
/**
|
19
|
-
* Best-effort polyfill for `Ember._captureRenderTree`.
|
20
|
-
*
|
21
|
-
* Just like the Ember API, it takes an owner (`ApplicationInstance`, specifically)
|
22
|
-
* and return an array of render nodes:
|
23
|
-
*
|
24
|
-
* interface CapturedRenderNode {
|
25
|
-
* id: string;
|
26
|
-
* type: 'outlet' | 'engine' | 'route-template' | 'component';
|
27
|
-
* name: string;
|
28
|
-
* args: {
|
29
|
-
* named: Dict<unknown>;
|
30
|
-
* positional: unknown[];
|
31
|
-
* };
|
32
|
-
* instance: unknown;
|
33
|
-
* template: Option<string>;
|
34
|
-
* bounds: Option<{
|
35
|
-
* parentElement: Simple.Element;
|
36
|
-
* firstNode: Simple.Node;
|
37
|
-
* lastNode: Simple.Node;
|
38
|
-
* }>;
|
39
|
-
* children: CapturedRenderNode[];
|
40
|
-
* }
|
41
|
-
*
|
42
|
-
* While the API is identical, there are some differences and limitations:
|
43
|
-
*
|
44
|
-
* 1. `args` property is not available (it always report empty args).
|
45
|
-
* 2. `bounds` property is only available on component nodes (`null` everywhere else).
|
46
|
-
* 3. `{{mount}}` does not insert an `engine` node.
|
47
|
-
* 4. `Ember.Component` (classic components) are the only type of component in the tree
|
48
|
-
* (other components are skipped over).
|
49
|
-
* 5. Ordering of `children` may be different (but this is also not guarenteed in the
|
50
|
-
* Ember API).
|
51
|
-
*/
|
52
|
-
|
53
|
-
const { Controller, ViewUtils, get, getOwner, guidFor } = Ember;
|
54
|
-
const { getRootViews, getChildViews, getViewBounds } = ViewUtils;
|
55
|
-
|
56
|
-
/**
|
57
|
-
* We are building the final tree by doing the following steps:
|
58
|
-
*
|
59
|
-
* 1. Get the "outlet state" tree from the router.
|
60
|
-
* 2. Collect the "top level" components. That is, components rendered directly from within
|
61
|
-
* a route template.
|
62
|
-
* 3. Do an "interleaved walk" down the outlet and (classic) component tree and map things
|
63
|
-
* into render nodes.
|
64
|
-
* 4. Return the array of render nodes we captured.
|
65
|
-
*
|
66
|
-
* Usually, this function returns an array of exactly one render node, which is the "root"
|
67
|
-
* outlet. However, sometimes there may be other top-level components in the app (e.g.
|
68
|
-
* rendered using the `Ember.Component#appendTo` API).
|
69
|
-
*/
|
70
|
-
captureRenderTree = function captureRenderTree(owner) {
|
71
|
-
let tree = [];
|
72
|
-
let outletState = getOutletState(owner);
|
73
|
-
let components = getTopLevelComponents(owner);
|
74
|
-
|
75
|
-
if (outletState && components) {
|
76
|
-
tree.push(captureOutlet('root', owner, components, outletState));
|
77
|
-
}
|
78
|
-
|
79
|
-
return tree;
|
80
|
-
};
|
81
|
-
|
82
|
-
/**
|
83
|
-
* Get the "outlet state" tree from the router. It corresponds to the "settled",
|
84
|
-
* app state after resolving all the hooks, redirects, etc. The rendering layer
|
85
|
-
* takes this tree from the router and render it on screen.
|
86
|
-
*
|
87
|
-
* It has the following format:
|
88
|
-
*
|
89
|
-
* interface OutletState {
|
90
|
-
* render: {
|
91
|
-
* // The current owner, could be the app or an engine
|
92
|
-
* owner: Owner;
|
93
|
-
*
|
94
|
-
* // The name of the route
|
95
|
-
* name: string;
|
96
|
-
*
|
97
|
-
* // The controller for the route
|
98
|
-
* controller: Controller;
|
99
|
-
*
|
100
|
-
* // The template (or template factory?) for the route (can this really be undefined?)
|
101
|
-
* template: OwnedTemplate | undefined;
|
102
|
-
*
|
103
|
-
* // The name of the outlet this was rendered into (in the parent route template)
|
104
|
-
* outlet: string;
|
105
|
-
*
|
106
|
-
* // The name of the parent route (we don't use this)
|
107
|
-
* into: string | undefined;
|
108
|
-
* },
|
109
|
-
*
|
110
|
-
* // The children outlets of this route, keyed by the outlet names (e.g. "main", "sidebar", ...)
|
111
|
-
* outlets: Dict<OutletState | undefined>;
|
112
|
-
* }
|
113
|
-
*
|
114
|
-
* This function returns the "root" outlet state.
|
115
|
-
*/
|
116
|
-
function getOutletState(owner) {
|
117
|
-
try {
|
118
|
-
// eslint-disable-next-line ember/no-private-routing-service
|
119
|
-
return owner.lookup('router:main')._toplevelView.state.ref.value();
|
120
|
-
} catch (error) {
|
121
|
-
console.log('[Ember Inspector] failed to capture render tree');
|
122
|
-
console.log(error);
|
123
|
-
return undefined;
|
124
|
-
}
|
125
|
-
}
|
126
|
-
|
127
|
-
/**
|
128
|
-
* Collect the "top level" components. That is, components rendered directly
|
129
|
-
* from within a route template.
|
130
|
-
*
|
131
|
-
* We do this by walking the classic component tree and identify components
|
132
|
-
* that has its "target" (~= the parent template's `{{this}}` object) set to
|
133
|
-
* a controller (or undefined, for root components rendered outside of the
|
134
|
-
* application route).
|
135
|
-
*
|
136
|
-
* This function returns a `Map` keyed by controllers (`undefiend` is also a
|
137
|
-
* possible key) to arrays of top-level components for that route/controller.
|
138
|
-
*/
|
139
|
-
function getTopLevelComponents(owner) {
|
140
|
-
try {
|
141
|
-
let map = new Map();
|
142
|
-
collectComponentsByController(map, null, getRootViews(owner));
|
143
|
-
return map;
|
144
|
-
} catch (error) {
|
145
|
-
console.log('[Ember Inspector] failed to capture render tree');
|
146
|
-
console.log(error);
|
147
|
-
return undefined;
|
148
|
-
}
|
149
|
-
}
|
150
|
-
|
151
|
-
/**
|
152
|
-
* Returns the "target" of a (classic) component.
|
153
|
-
*/
|
154
|
-
function targetForComponent(component) {
|
155
|
-
return get(component, '_target') || get(component, '_targetObject');
|
156
|
-
}
|
157
|
-
|
158
|
-
/**
|
159
|
-
* Recursively walk an array of components and add any "top level" components
|
160
|
-
* to the map keyed by their controller.
|
161
|
-
*/
|
162
|
-
function collectComponentsByController(map, controller, components) {
|
163
|
-
components.forEach((component) => {
|
164
|
-
let target = targetForComponent(component);
|
165
|
-
|
166
|
-
if (target === undefined || target instanceof Controller) {
|
167
|
-
/**
|
168
|
-
* If our parent is already added, don't add ourself again.
|
169
|
-
*
|
170
|
-
* This is to prevent something like this:
|
171
|
-
*
|
172
|
-
* {{!-- app/templates/application.hbs}}
|
173
|
-
* <Parent>
|
174
|
-
* <Child />
|
175
|
-
* </Parent>
|
176
|
-
*
|
177
|
-
* Without this check, both the parent and the yielded child will be
|
178
|
-
* considered "top level" since they both have the controller as their
|
179
|
-
* target.
|
180
|
-
*/
|
181
|
-
if (target !== controller) {
|
182
|
-
if (!map.has(target)) {
|
183
|
-
map.set(target, []);
|
184
|
-
}
|
185
|
-
|
186
|
-
map.get(target).push(component);
|
187
|
-
}
|
188
|
-
|
189
|
-
collectComponentsByController(map, target, getChildViews(component));
|
190
|
-
} else {
|
191
|
-
collectComponentsByController(
|
192
|
-
map,
|
193
|
-
controller,
|
194
|
-
getChildViews(component)
|
195
|
-
);
|
196
|
-
}
|
197
|
-
});
|
198
|
-
}
|
199
|
-
|
200
|
-
const EMPTY_ARGS = {
|
201
|
-
named: Object.create(null),
|
202
|
-
positional: [],
|
203
|
-
};
|
204
|
-
|
205
|
-
/**
|
206
|
-
* Return the module name (e.g. `my-app/templates/application.hbs`) for a
|
207
|
-
* template or template factory, if available. This may not be present for,
|
208
|
-
* e.g. templates compiled using the "inline" `hbs` tagged string method.
|
209
|
-
*/
|
210
|
-
function nameForTemplate(template) {
|
211
|
-
if (template.meta) {
|
212
|
-
// Factory
|
213
|
-
return template.meta.moduleName || null;
|
214
|
-
} else if (template.referrer) {
|
215
|
-
// Instance
|
216
|
-
return template.referrer.moduleName || null;
|
217
|
-
} else {
|
218
|
-
return null;
|
219
|
-
}
|
220
|
-
}
|
221
|
-
|
222
|
-
/**
|
223
|
-
* Walk an outlet tree (the last parameter) and map its content into render nodes.
|
224
|
-
*
|
225
|
-
* For each level of the outlet tree, we also have to walk the (classic) component
|
226
|
-
* tree to attach any components for the current level (and their children) to the
|
227
|
-
* resulting render nodes tree.
|
228
|
-
*
|
229
|
-
* We also check if the owner has changed between the current level and the previous
|
230
|
-
* level, and if so, we infer that we must have just crossed an engine boundary and
|
231
|
-
* insert an engine render node to account for that.
|
232
|
-
*
|
233
|
-
* Because we don't have a good way to generate a stable ID for the outlet nodes, we
|
234
|
-
* also pass down a "path" of the routes/outlets we have encountered so far which we
|
235
|
-
* use to generate the ID.
|
236
|
-
*/
|
237
|
-
function captureOutlet(path, owner, components, { outlets, render }) {
|
238
|
-
let outlet = {
|
239
|
-
id: `render-node:${path}@${render.outlet}`,
|
240
|
-
type: 'outlet',
|
241
|
-
name: render.outlet,
|
242
|
-
args: EMPTY_ARGS,
|
243
|
-
instance: undefined,
|
244
|
-
template: null,
|
245
|
-
bounds: null,
|
246
|
-
children: [],
|
247
|
-
};
|
248
|
-
|
249
|
-
let parent = outlet;
|
250
|
-
|
251
|
-
if (owner !== render.owner) {
|
252
|
-
let engine = {
|
253
|
-
id: `render-node:${guidFor(render.owner)}`,
|
254
|
-
type: 'engine',
|
255
|
-
name: render.owner.mountPoint,
|
256
|
-
args: EMPTY_ARGS,
|
257
|
-
instance: render.owner,
|
258
|
-
template: null,
|
259
|
-
bounds: null,
|
260
|
-
children: [],
|
261
|
-
};
|
262
|
-
|
263
|
-
parent.children.push(engine);
|
264
|
-
parent = engine;
|
265
|
-
}
|
266
|
-
|
267
|
-
let subpath = `${path}@${render.outlet}/${render.name}`;
|
268
|
-
|
269
|
-
let route = {
|
270
|
-
id: `render-node:${subpath}`,
|
271
|
-
type: 'route-template',
|
272
|
-
name: render.name,
|
273
|
-
args: EMPTY_ARGS,
|
274
|
-
instance: render.controller,
|
275
|
-
template: nameForTemplate(render.template),
|
276
|
-
bounds: null,
|
277
|
-
children: [],
|
278
|
-
};
|
279
|
-
|
280
|
-
parent.children.push(route);
|
281
|
-
parent = route;
|
282
|
-
|
283
|
-
let childOutlets = Object.keys(outlets).map((name) =>
|
284
|
-
captureOutlet(subpath, render.owner, components, outlets[name])
|
285
|
-
);
|
286
|
-
|
287
|
-
let childComponents = captureComponents(
|
288
|
-
components.get(render.controller) || [],
|
289
|
-
render.controller
|
290
|
-
);
|
291
|
-
|
292
|
-
parent.children.push(
|
293
|
-
...mergeOutletChildren(render.controller, childOutlets, childComponents)
|
294
|
-
);
|
295
|
-
|
296
|
-
return outlet;
|
297
|
-
}
|
298
|
-
|
299
|
-
/**
|
300
|
-
* Its is possible to nest an outlet inside a component, one pretty common example
|
301
|
-
* is a "layout" component:
|
302
|
-
*
|
303
|
-
* <SidebarWrapper>
|
304
|
-
* {{outlet "sidebar"}}
|
305
|
-
* </SidebarWrapper>
|
306
|
-
*
|
307
|
-
* On the other hand, it's not possible to put a component inside an outlet anymore
|
308
|
-
* when we get to this point. Try to find a suitable parent for each child outlet
|
309
|
-
* taking the above into account.
|
310
|
-
*/
|
311
|
-
function mergeOutletChildren(controller, outlets, components) {
|
312
|
-
let merged = [];
|
313
|
-
|
314
|
-
for (let outlet of outlets) {
|
315
|
-
if (controller) {
|
316
|
-
let parentComponent = findOutletComponentParent(outlet.children);
|
317
|
-
|
318
|
-
if (controllerForComponent(parentComponent) === controller) {
|
319
|
-
let parentNode = findOutletComponentNode(components, parentComponent);
|
320
|
-
|
321
|
-
if (parentNode) {
|
322
|
-
parentNode.children.unshift(outlet);
|
323
|
-
continue;
|
324
|
-
}
|
325
|
-
}
|
326
|
-
}
|
327
|
-
|
328
|
-
merged.push(outlet);
|
329
|
-
}
|
330
|
-
|
331
|
-
merged.push(...components);
|
332
|
-
|
333
|
-
return merged;
|
334
|
-
}
|
335
|
-
|
336
|
-
function findOutletComponentParent(nodes) {
|
337
|
-
let result;
|
338
|
-
|
339
|
-
for (let node of nodes) {
|
340
|
-
if (node.type === 'component') {
|
341
|
-
result = node.instance.parentView;
|
342
|
-
} else if (node.type === 'engine' || node.type === 'route-template') {
|
343
|
-
result = findOutletComponentParent(node.children);
|
344
|
-
}
|
345
|
-
|
346
|
-
if (result !== undefined) {
|
347
|
-
return result;
|
348
|
-
}
|
349
|
-
}
|
350
|
-
}
|
351
|
-
|
352
|
-
function findOutletComponentNode(nodes, instance) {
|
353
|
-
let result;
|
354
|
-
|
355
|
-
for (let node of nodes) {
|
356
|
-
if (node.type === 'component') {
|
357
|
-
if (node.instance === instance) {
|
358
|
-
result = node;
|
359
|
-
} else {
|
360
|
-
result = findOutletComponentNode(node.children, instance);
|
361
|
-
}
|
362
|
-
}
|
363
|
-
|
364
|
-
if (result !== undefined) {
|
365
|
-
return result;
|
366
|
-
}
|
367
|
-
}
|
368
|
-
}
|
369
|
-
|
370
|
-
/**
|
371
|
-
* Returns the name of a (classic) component.
|
372
|
-
*/
|
373
|
-
function nameForComponent(component) {
|
374
|
-
// remove "component:" prefix
|
375
|
-
return component._debugContainerKey.slice(10);
|
376
|
-
}
|
377
|
-
|
378
|
-
/**
|
379
|
-
* Returns the nearest controller of a (classic) component. This is so that we know
|
380
|
-
* whether a given component belongs to the current level (the route that we are
|
381
|
-
* processing right now) or not.
|
382
|
-
*/
|
383
|
-
function controllerForComponent(component) {
|
384
|
-
let target = component;
|
385
|
-
|
386
|
-
while (target && !(target instanceof Controller)) {
|
387
|
-
target = targetForComponent(target);
|
388
|
-
}
|
389
|
-
|
390
|
-
return target;
|
391
|
-
}
|
392
|
-
|
393
|
-
/**
|
394
|
-
* Returns the template (or template factory?) for a (classic) component.
|
395
|
-
*/
|
396
|
-
function templateForComponent(component) {
|
397
|
-
let layout = get(component, 'layout');
|
398
|
-
|
399
|
-
if (layout) {
|
400
|
-
return nameForTemplate(layout);
|
401
|
-
}
|
402
|
-
|
403
|
-
let layoutName = get(component, 'layoutName');
|
404
|
-
|
405
|
-
if (layoutName) {
|
406
|
-
let owner = getOwner(component);
|
407
|
-
let template = owner.lookup(`template:${layoutName}`);
|
408
|
-
return nameForTemplate(template);
|
409
|
-
}
|
410
|
-
|
411
|
-
return null;
|
412
|
-
}
|
413
|
-
|
414
|
-
/**
|
415
|
-
* Return the render node for a given (classic) component, and its children up
|
416
|
-
* until the next route boundary.
|
417
|
-
*/
|
418
|
-
function captureComponents(components, controller) {
|
419
|
-
return components
|
420
|
-
.filter((component) => controllerForComponent(component) === controller)
|
421
|
-
.map((component) => ({
|
422
|
-
id: `render-node:${guidFor(component)}`,
|
423
|
-
type: 'component',
|
424
|
-
name: nameForComponent(component),
|
425
|
-
args: EMPTY_ARGS,
|
426
|
-
instance: component,
|
427
|
-
template: templateForComponent(component),
|
428
|
-
bounds: getViewBounds(component),
|
429
|
-
children: captureComponents(getChildViews(component), controller),
|
430
|
-
}));
|
431
|
-
}
|
432
14
|
}
|
433
|
-
|
434
|
-
export default captureRenderTree;
|
15
|
+
export default capture;
|