/** @module ember */ import { EMBER_ENGINES_MOUNT_PARAMS } from '@ember/canary-features'; import { assert } from '@ember/debug'; import { curry, UNDEFINED_REFERENCE, } from '@glimmer/runtime'; import * as WireFormat from '@glimmer/wire-format'; import { MountDefinition } from '../component-managers/mount'; export function mountHelper(vm, args) { let env = vm.env; let nameRef = args.positional.at(0); let modelRef = args.named.has('model') ? args.named.get('model') : undefined; return new DynamicEngineReference(nameRef, env, modelRef); } /** 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"}} ``` Additionally, you can also pass in a `model` argument that will be set as the engines model. This can be an existing object: ```
{{mount 'admin' model=userSettings}}
``` Or an inline `hash`, and you can even pass components: ```

Application template!

{{mount 'admin' model=(hash title='Secret Admin' signInButton=(component 'sign-in-button') )}}
``` @method mount @param {String} name Name of the engine to mount. @param {Object} [model] Object that will be set as the model of the engine. @for Ember.Templates.helpers @category ember-application-engines @public */ export function mountMacro(_name, params, hash, builder) { if (EMBER_ENGINES_MOUNT_PARAMS) { assert('You can only pass a single positional argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}.', params.length === 1); } else { assert('You can only pass a single argument to the {{mount}} helper, e.g. {{mount "chat-engine"}}.', params.length === 1 && hash === null); } let expr = [WireFormat.Ops.Helper, '-mount', params || [], hash]; builder.dynamicComponent(expr, null, [], null, false, null, null); return true; } class DynamicEngineReference { constructor(nameRef, env, modelRef) { this.tag = nameRef.tag; this.nameRef = nameRef; this.modelRef = modelRef; this.env = env; this._lastName = null; this._lastDef = null; } value() { let { env, nameRef, modelRef } = this; let name = nameRef.value(); if (typeof name === 'string') { if (this._lastName === name) { return this._lastDef; } assert(`You used \`{{mount '${name}'}}\`, but the engine '${name}' can not be found.`, env.owner.hasRegistration(`engine:${name}`)); if (!env.owner.hasRegistration(`engine:${name}`)) { return null; } this._lastName = name; this._lastDef = curry(new MountDefinition(name, modelRef)); return this._lastDef; } else { assert(`Invalid engine name '${name}' specified, engine name must be either a string, null or undefined.`, name === null || name === undefined); this._lastDef = null; this._lastName = null; return null; } } get() { return UNDEFINED_REFERENCE; } }