Skip to content

Commit

Permalink
💀 orphaned outlets
Browse files Browse the repository at this point in the history
  • Loading branch information
lorcan committed Dec 2, 2017
1 parent 23a8c92 commit c60d571
Show file tree
Hide file tree
Showing 5 changed files with 4 additions and 300 deletions.
8 changes: 0 additions & 8 deletions packages/ember-glimmer/lib/component-managers/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ class SingletonRenderManager extends AbstractRenderManager {
this._pushToDebugStack(`controller:${name} (with the render helper)`, environment);
}

if (dynamicScope.rootOutletState) {
dynamicScope.outletState = dynamicScope.rootOutletState.getOrphan(name);
}

return { controller };
}
}
Expand All @@ -61,10 +57,6 @@ class NonSingletonRenderManager extends AbstractRenderManager {
this._pushToDebugStack(`controller:${name} (with the render helper)`, environment);
}

if (dynamicScope.rootOutletState) {
dynamicScope.outletState = dynamicScope.rootOutletState.getOrphan(name);
}

return { controller, model: modelRef };
}

Expand Down
5 changes: 2 additions & 3 deletions packages/ember-glimmer/lib/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ import { assert } from 'ember-debug';
const { backburner } = run;

class DynamicScope {
constructor(view, outletState, rootOutletState, targetObject) {
constructor(view, outletState) {
this.view = view;
this.outletState = outletState;
this.rootOutletState = rootOutletState;
}

child() {
return new DynamicScope(
this.view, this.outletState, this.rootOutletState
this.view, this.outletState
);
}

Expand Down
36 changes: 0 additions & 36 deletions packages/ember-glimmer/lib/views/outlet.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,11 @@ class OutletStateReference {
return this.outletView.outletState;
}

getOrphan(name) {
return new OrphanedOutletStateReference(this, name);
}

update(state) {
this.outletView.setOutletState(state);
}
}

// So this is a relic of the past that SHOULD go away
// in 3.0. Preferably it is deprecated in the release that
// follows the Glimmer release.
class OrphanedOutletStateReference extends OutletStateReference {
constructor(root, name) {
super(root.outletView);
this.root = root;
this.name = name;
}

value() {
let rootState = this.root.value();

let orphans = rootState.outlets.main.outlets.__ember_orphans__;

if (!orphans) {
return null;
}

let matched = orphans.outlets[this.name];

if (!matched) {
return null;
}

let state = Object.create(null);
state[matched.render.outlet] = matched;
matched.wasUsed = true;
return { outlets: state };
}
}

class ChildOutletStateReference {
constructor(parent, key) {
this.parent = parent;
Expand Down
40 changes: 2 additions & 38 deletions packages/ember-routing/lib/system/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -1505,51 +1505,15 @@ function appendLiveRoute(liveRoutes, defaultParentState, renderOptions) {
if (target) {
set(target.outlets, renderOptions.outlet, myState);
} else {
if (renderOptions.into) {
deprecate(
`Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated.`,
false,
{
id: 'ember-routing.top-level-render-helper',
until: '3.0.0',
url: 'https://emberjs.com/deprecations/v2.x/#toc_rendering-into-a-render-helper-that-resolves-to-an-outlet'
}
);

// Megahax time. Post-3.0-breaking-changes, we will just assert
// right here that the user tried to target a nonexistent
// thing. But for now we still need to support the `render`
// helper, and people are allowed to target templates rendered
// by the render helper. So instead we defer doing anyting with
// these orphan renders until afterRender.
appendOrphan(liveRoutes, renderOptions.into, myState);
} else {
liveRoutes = myState;
}
assert(`Cannot render into a {{render}} helper () that resolves to an {{outlet}}`, !renderOptions.into);
liveRoutes = myState;
}
return {
liveRoutes,
ownState: myState
};
}

function appendOrphan(liveRoutes, into, myState) {
if (!liveRoutes.outlets.__ember_orphans__) {
liveRoutes.outlets.__ember_orphans__ = {
render: {
name: '__ember_orphans__'
},
outlets: Object.create(null)
};
}
liveRoutes.outlets.__ember_orphans__.outlets[into] = myState;
run.schedule('afterRender', () => {
// `wasUsed` gets set by the render helper.
assert(`You attempted to render into '${into}' but it was not found`,
liveRoutes.outlets.__ember_orphans__.outlets[into].wasUsed);
});
}

function representEmptyRoute(liveRoutes, defaultParentState, route) {
// the route didn't render anything
let alreadyAppended = findLiveRoute(liveRoutes, route.routeName);
Expand Down
215 changes: 0 additions & 215 deletions packages/ember/tests/routing/basic_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2282,23 +2282,6 @@ QUnit.test('Route should tear down multiple outlets', function() {
equal(jQuery('div.posts-footer:contains(postsFooter)', '#qunit-fixture').length, 0, 'The posts/footer template was removed');
});


QUnit.test('Route will assert if you try to explicitly render {into: ...} a missing template', function () {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

Router.map(function() {
this.route('home', { path: '/' });
});

App.HomeRoute = Route.extend({
renderTemplate() {
this.render({ into: 'nonexistent' });
}
});

expectAssertion(() => bootApplication(), 'You attempted to render into \'nonexistent\' but it was not found');
});

QUnit.test('Route supports clearing outlet explicitly', function() {
setTemplate('application', compile('{{outlet}}{{outlet \'modal\'}}'));
setTemplate('posts', compile('{{outlet}}'));
Expand Down Expand Up @@ -3434,204 +3417,6 @@ QUnit.test('Allows any route to disconnectOutlet another route\'s templates', fu
equal(trim(jQuery('#qunit-fixture').text()), 'hi');
});

QUnit.test('Can this.render({into:...}) the render helper', function() {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

expectDeprecation(() => {
setTemplate('application', compile('{{render "sidebar"}}'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

setTemplate('sidebar', compile('<div class="sidebar">{{outlet}}</div>'));
setTemplate('index', compile('other'));
setTemplate('bar', compile('bar'));

App.IndexRoute = Route.extend({
renderTemplate() {
this.render({ into: 'sidebar' });
},
actions: {
changeToBar() {
this.disconnectOutlet({
parentView: 'sidebar',
outlet: 'main'
});
this.render('bar', { into: 'sidebar' });
}
}
});

bootApplication();
equal(jQuery('#qunit-fixture .sidebar').text(), 'other');
run(router, 'send', 'changeToBar');
equal(jQuery('#qunit-fixture .sidebar').text(), 'bar');
});

QUnit.test('Can disconnect from the render helper', function() {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

expectDeprecation(() => {
setTemplate('application', compile('{{render "sidebar"}}'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

setTemplate('sidebar', compile('<div class="sidebar">{{outlet}}</div>'));
setTemplate('index', compile('other'));

App.IndexRoute = Route.extend({
renderTemplate() {
this.render({ into: 'sidebar' });
},
actions: {
disconnect: function() {
this.disconnectOutlet({
parentView: 'sidebar',
outlet: 'main'
});
}
}
});

bootApplication();
equal(jQuery('#qunit-fixture .sidebar').text(), 'other');
run(router, 'send', 'disconnect');
equal(jQuery('#qunit-fixture .sidebar').text(), '');
});

QUnit.test('Can this.render({into:...}) the render helper\'s children', function() {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

expectDeprecation(() => {
setTemplate('application', compile('{{render "sidebar"}}'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

setTemplate('sidebar', compile('<div class="sidebar">{{outlet}}</div>'));
setTemplate('index', compile('<div class="index">{{outlet}}</div>'));
setTemplate('other', compile('other'));
setTemplate('bar', compile('bar'));

App.IndexRoute = Route.extend({
renderTemplate() {
this.render({ into: 'sidebar' });
this.render('other', { into: 'index' });
},
actions: {
changeToBar() {
this.disconnectOutlet({
parentView: 'index',
outlet: 'main'
});
this.render('bar', { into: 'index' });
}
}
});

bootApplication();
equal(jQuery('#qunit-fixture .sidebar .index').text(), 'other');
run(router, 'send', 'changeToBar');
equal(jQuery('#qunit-fixture .sidebar .index').text(), 'bar');
});

QUnit.test('Can disconnect from the render helper\'s children', function() {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

expectDeprecation(() => {
setTemplate('application', compile('{{render "sidebar"}}'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

setTemplate('sidebar', compile('<div class="sidebar">{{outlet}}</div>'));
setTemplate('index', compile('<div class="index">{{outlet}}</div>'));
setTemplate('other', compile('other'));

App.IndexRoute = Route.extend({
renderTemplate() {
this.render({ into: 'sidebar' });
this.render('other', { into: 'index' });
},
actions: {
disconnect() {
this.disconnectOutlet({
parentView: 'index',
outlet: 'main'
});
}
}
});

bootApplication();
equal(jQuery('#qunit-fixture .sidebar .index').text(), 'other');
run(router, 'send', 'disconnect');
equal(jQuery('#qunit-fixture .sidebar .index').text(), '');
});

QUnit.test('Can this.render({into:...}) nested render helpers', function() {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

expectDeprecation(() => {
setTemplate('application', compile('{{render "sidebar"}}'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

expectDeprecation(() => {
setTemplate('sidebar', compile('<div class="sidebar">{{render "cart"}}</div>'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

setTemplate('cart', compile('<div class="cart">{{outlet}}</div>'));
setTemplate('index', compile('other'));
setTemplate('baz', compile('baz'));

App.IndexRoute = Route.extend({
renderTemplate() {
this.render({ into: 'cart' });
},
actions: {
changeToBaz() {
this.disconnectOutlet({
parentView: 'cart',
outlet: 'main'
});
this.render('baz', { into: 'cart' });
}
}
});

bootApplication();
equal(jQuery('#qunit-fixture .cart').text(), 'other');
run(router, 'send', 'changeToBaz');
equal(jQuery('#qunit-fixture .cart').text(), 'baz');
});

QUnit.test('Can disconnect from nested render helpers', function() {
expectDeprecation(/Rendering into a {{render}} helper that resolves to an {{outlet}} is deprecated./);

expectDeprecation(() => {
setTemplate('application', compile('{{render "sidebar"}}'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

expectDeprecation(() => {
setTemplate('sidebar', compile('<div class="sidebar">{{render "cart"}}</div>'));
}, /Please refactor [\w\{\}"` ]+ to a component/);

setTemplate('cart', compile('<div class="cart">{{outlet}}</div>'));
setTemplate('index', compile('other'));

App.IndexRoute = Route.extend({
renderTemplate() {
this.render({ into: 'cart' });
},
actions: {
disconnect() {
this.disconnectOutlet({
parentView: 'cart',
outlet: 'main'
});
}
}
});

bootApplication();
equal(jQuery('#qunit-fixture .cart').text(), 'other');
run(router, 'send', 'disconnect');
equal(jQuery('#qunit-fixture .cart').text(), '');
});

QUnit.test('Components inside an outlet have their didInsertElement hook invoked when the route is displayed', function(assert) {
setTemplate('index', compile('{{#if showFirst}}{{my-component}}{{else}}{{other-component}}{{/if}}'));

Expand Down

0 comments on commit c60d571

Please sign in to comment.