ember-source
Version:
A JavaScript framework for creating ambitious web applications
199 lines (162 loc) • 5.69 kB
JavaScript
import { a as createComputeRef, i as isInvokableRef, u as updateRef } from './reference-BshxG6wn.js';
import { f as reifyPositional, g as check, e as reifyNamed } from './debug-render-tree-CF5O4-WI.js';
import { j as setInternalHelperManager } from './api-zh_k31vb.js';
function internalHelper(helper) {
return setInternalHelperManager(helper, {});
}
/**
Use the `{{array}}` helper to create an array to pass as an option to your
components.
```handlebars
<MyComponent @people={{array
'Tom Dale'
'Yehuda Katz'
this.myOtherPerson}}
/>
```
or
```handlebars
{{yield people=(array
'Tom Dale'
'Yehuda Katz'
this.myOtherPerson)
}}
```
Would result in an object such as:
```js
['Tom Dale', 'Yehuda Katz', this.get('myOtherPerson')]
```
Where the 3rd item in the array is bound to updates of the `myOtherPerson` property.
@method array
@param {Array} options
@return {Array} Array
@public
*/
const array = internalHelper(({
positional
}) => {
return createComputeRef(() => reifyPositional(positional), null, 'array');
});
/* eslint-disable @typescript-eslint/no-empty-object-type */
function buildUntouchableThis(source) {
let context = null;
return context;
}
const context = buildUntouchableThis();
/**
The `fn` helper allows you to ensure a function that you are passing off
to another component, helper, or modifier has access to arguments that are
available in the template.
For example, if you have an `each` helper looping over a number of items, you
may need to pass a function that expects to receive the item as an argument
to a component invoked within the loop. Here's how you could use the `fn`
helper to pass both the function and its arguments together:
```app/components/items-listing.gjs
import DisplayItem from './display-item';
<template>
{{#each @items as |item|}}
<DisplayItem @item=item @select={{fn this.handleSelected item}} />
{{/each}}
</template>
```
```app/components/items-list.gjs
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class ItemsList extends Component {
handleSelected = (item) => {
// ...snip...
}
}
```
In this case the `DisplayItem` component will receive a normal function
that it can invoke. When it invokes the function, the `handleSelected`
function will receive the `item` and any arguments passed, thanks to the
`fn` helper.
Let's take look at what that means in a couple circumstances:
- When invoked as `this.args.select()` the `handleSelected` function will
receive the `item` from the loop as its first and only argument.
- When invoked as `this.args.select('foo')` the `handleSelected` function
will receive the `item` from the loop as its first argument and the
string `'foo'` as its second argument.
In the example above, we used an arrow function to ensure that
`handleSelected` is properly bound to the `items-list`, but let's explore what
happens if we left out the arrow function:
```app/components/items-list.gjs
import Component from '@glimmer/component';
export default class ItemsList extends Component {
handleSelected(item) {
// ...snip...
}
}
```
In this example, when `handleSelected` is invoked inside the `display-item`
component, it will **not** have access to the component instance. In other
words, it will have no `this` context, so please make sure your functions
are bound (via an arrow function or other means) before passing into `fn`!
See also [partial application](https://en.wikipedia.org/wiki/Partial_application).
`fn` is built-in and does not require any additional imports.
@method fn
@public
*/
const fn = internalHelper(({
positional
}) => {
let callbackRef = check(positional[0]);
return createComputeRef(() => {
return (...invocationArgs) => {
let [fn, ...args] = reifyPositional(positional);
if (isInvokableRef(callbackRef)) {
let value = args.length > 0 ? args[0] : invocationArgs[0];
return void updateRef(callbackRef, value);
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return -- @fixme
return fn.call(context, ...args, ...invocationArgs);
}
};
}, null, 'fn');
});
/**
Use the `{{hash}}` helper to create a hash to pass as an option to your
components. This is especially useful for contextual components where you can
just yield a hash:
```handlebars
{{yield (hash
name='Sarah'
title=office
)}}
```
Would result in an object such as:
```js
{ name: 'Sarah', title: this.get('office') }
```
Where the `title` is bound to updates of the `office` property.
Note that the hash is an empty object with no prototype chain, therefore
common methods like `toString` are not available in the resulting hash.
If you need to use such a method, you can use the `call` or `apply`
approach:
```js
function toString(obj) {
return Object.prototype.toString.apply(obj);
}
```
@method hash
@param {Object} options
@return {Object} Hash
@public
*/
const hash = internalHelper(({
named
}) => {
let ref = createComputeRef(() => {
return reifyNamed(named);
}, null, 'hash');
// Setup the children so that templates can bypass getting the value of
// the reference and treat children lazily
let children = new Map();
for (let name in named) {
children.set(name, named[name]);
}
ref.children = children;
return ref;
});
export { array as a, fn as f, hash as h, internalHelper as i };