diff --git a/packages/@ember/-internals/glimmer/lib/helpers/gt.ts b/packages/@ember/-internals/glimmer/lib/helpers/gt.ts new file mode 100644 index 00000000000..b0c3035c465 --- /dev/null +++ b/packages/@ember/-internals/glimmer/lib/helpers/gt.ts @@ -0,0 +1,38 @@ +import { Arguments, CapturedArguments, VM } from '@glimmer/runtime'; +import { InternalHelperReference } from '../utils/references'; + +/** +@module ember +*/ + +/** + Compares the two given values with > + + Example: + + ```handlebars + {{gt age 17}} + + {{! be true if `age` is > 17}} + ``` + + @public + @method gt + @for Ember.Templates.helpers + @since 2.7.0 +*/ +function gt({ positional: { references } }: CapturedArguments) { + let left = references[0].value(); + if (left === undefined || left === null) { + return false; + } + let right = references[1].value(); + if (right === undefined || right === null) { + return false; + } + return left > right; +} + +export default function(_vm: VM, args: Arguments) { + return new InternalHelperReference(gt, args.capture()); +} diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts index 02c2a9d15fd..652e58fe923 100644 --- a/packages/@ember/-internals/glimmer/lib/resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/resolver.ts @@ -33,6 +33,7 @@ import { default as array } from './helpers/array'; import { default as concat } from './helpers/concat'; import { default as eq } from './helpers/eq'; import { default as not } from './helpers/not'; +import { default as gt } from './helpers/gt'; import { default as eachIn } from './helpers/each-in'; import { default as get } from './helpers/get'; import { default as hash } from './helpers/hash'; @@ -69,6 +70,7 @@ const BUILTINS_HELPERS = { concat, eq, get, + gt, hash, array, log, diff --git a/packages/@ember/-internals/glimmer/tests/integration/helpers/gt-test.js b/packages/@ember/-internals/glimmer/tests/integration/helpers/gt-test.js new file mode 100644 index 00000000000..2ea137ecdef --- /dev/null +++ b/packages/@ember/-internals/glimmer/tests/integration/helpers/gt-test.js @@ -0,0 +1,137 @@ +import { RenderingTest, moduleFor } from '../../utils/test-case'; +import { set } from '@ember/-internals/metal'; +import { Component } from '../../utils/helpers'; +import { computed } from '@ember/-internals/metal'; + +moduleFor( + 'Helpers test: {{gt}}', + class extends RenderingTest { + ['@test returns true when the first static argument is bigger than the second one']() { + this.render(`{{gt 2 1}}`); + this.assertText('true'); + } + + ['@test returns false when the first static argument is not bigger than the second one']() { + this.render(`{{gt 0 1}}`); + this.assertText('false'); + } + + ['@test returns false when both arguments are the same']() { + this.render(`{{gt 1 1}}`); + this.assertText('false'); + } + + ['@test it updates for bound arguments']() { + this.render(`{{gt left right}}`, { left: 1, right: 2 }); + + this.assertText('false'); + + this.runTask(() => this.rerender()); + + this.assertText('false'); + + this.runTask(() => set(this.context, 'left', 3)); + + this.assertText('true'); + + this.runTask(() => set(this.context, 'right', 4)); + + this.assertText('false'); + + this.runTask(() => set(this.context, 'left', 5)); + + this.assertText('true'); + + this.runTask(() => set(this.context, 'right', 5)); + + this.assertText('false'); + } + + ['@test it can be used as a sub-expression']() { + this.render(`{{if (gt left right) "yes" "no"}}`, { left: 1, right: 2 }); + + this.assertText('no'); + + this.runTask(() => this.rerender()); + + this.assertText('no'); + + this.runTask(() => set(this.context, 'left', 3)); + + this.assertText('yes'); + + this.runTask(() => set(this.context, 'right', 4)); + + this.assertText('no'); + + this.runTask(() => { + set(this.context, 'left', 5); + set(this.context, 'right', 0); + }); + + this.assertText('yes'); + } + + ['@test of the first argument is undefined, it never pulls the second argument']() { + let didInvokeLeft = false; + let didInvokeRight = false; + let FooBarComponent = Component.extend({ + left: computed(function() { + didInvokeLeft = true; + return undefined; + }), + right: computed(function() { + didInvokeRight = true; + return 5; + }), + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{gt left right}}`, + }); + + this.render(`{{foo-bar}}`, {}); + + this.assertText('false'); + + this.runTask(() => this.rerender()); + + this.assertText('false'); + + this.assert.ok(didInvokeLeft, 'the `left` property was accessed'); + this.assert.notOk(didInvokeRight, "the `right` property wasn't accessed"); + } + + ['@test of the first argument is null, it never pulls the second argument']() { + let didInvokeLeft = false; + let didInvokeRight = false; + let FooBarComponent = Component.extend({ + left: computed(function() { + didInvokeLeft = true; + return null; + }), + right: computed(function() { + didInvokeRight = true; + return 5; + }), + }); + + this.registerComponent('foo-bar', { + ComponentClass: FooBarComponent, + template: `{{gt left right}}`, + }); + + this.render(`{{foo-bar}}`, {}); + + this.assertText('false'); + + this.runTask(() => this.rerender()); + + this.assertText('false'); + + this.assert.ok(didInvokeLeft, 'the `left` property was accessed'); + this.assert.notOk(didInvokeRight, "the `right` property wasn't accessed"); + } + } +);