File: packages/ember-glimmer/lib/syntax/mount.js
/**
@module ember
@submodule ember-glimmer
*/
import {
ArgsSyntax,
StatementSyntax,
ComponentDefinition
} from 'glimmer-runtime';
import { UNDEFINED_REFERENCE } from 'glimmer-reference';
import { assert, runInDebug } from 'ember-metal';
import { RootReference } from '../utils/references';
import { generateControllerFactory } from 'ember-routing';
import { OutletLayoutCompiler } from './outlet';
import AbstractManager from './abstract-manager';
/**
The `{{mount}}` helper lets you embed a routeless engine in a template.
Mounting an engine will cause an instance to be booted and its `application`
template to be rendered.
For example, the following template mounts the `ember-chat` engine:
```handlebars
{{! application.hbs }}
{{mount "ember-chat"}}
```
Currently, the engine name is the only argument that can be passed to
`{{mount}}`.
@method mount
@for Ember.Templates.helpers
@category ember-application-engines
@public
*/
export class MountSyntax extends StatementSyntax {
static create(env, args, symbolTable) {
assert(
'You can only pass a single argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}.',
args.positional.length === 1 && args.named.length === 0
);
assert(
'The first argument of {{mount}} must be quoted, e.g. {{mount "chat-engine"}}.',
args.positional.at(0).type === 'value' && typeof args.positional.at(0).inner() === 'string'
);
let name = args.positional.at(0).inner();
assert(
`You used \`{{mount '${name}'}}\`, but the engine '${name}' can not be found.`,
env.owner.hasRegistration(`engine:${name}`)
);
let definition = new MountDefinition(name, env);
return new MountSyntax(definition, symbolTable);
}
constructor(definition, symbolTable) {
super();
this.definition = definition;
this.symbolTable = symbolTable;
}
compile(builder) {
builder.component.static(this.definition, ArgsSyntax.empty(), null, this.symbolTable, null);
}
}
class MountManager extends AbstractManager {
prepareArgs(definition, args) {
return args;
}
create(environment, { name, env }, args, dynamicScope) {
runInDebug(() => this._pushEngineToDebugStack(`engine:${name}`, env));
dynamicScope.outletState = UNDEFINED_REFERENCE;
let engine = env.owner.buildChildEngineInstance(name);
engine.boot();
return { engine };
}
layoutFor(definition, { engine }, env) {
let template = engine.lookup(`template:application`);
return env.getCompiledBlock(OutletLayoutCompiler, template);
}
getSelf({ engine }) {
let factory = engine._lookupFactory(`controller:application`) || generateControllerFactory(engine, 'application');
return new RootReference(factory.create());
}
getTag() {
return null;
}
getDestructor({ engine }) {
return engine;
}
didCreateElement() {}
didRenderLayout() {
runInDebug(() => this.debugStack.pop());
}
didCreate(state) {}
update(state, args, dynamicScope) {}
didUpdateLayout() {}
didUpdate(state) {}
}
const MOUNT_MANAGER = new MountManager();
class MountDefinition extends ComponentDefinition {
constructor(name, env) {
super(name, MOUNT_MANAGER, null);
this.env = env;
}
}