Skip to content

Commit

Permalink
Modifying in-element semantics to support non-null insertBefore elements
Browse files Browse the repository at this point in the history
- This is a slight modification of the changes introduced in PR glimmerjs#918, to continue to allow passing non null values to the insertBefore param of the in-element helper
  • Loading branch information
chiragpat committed Apr 10, 2019
1 parent 99c6410 commit a3917d6
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 22 deletions.
39 changes: 30 additions & 9 deletions packages/@glimmer/integration-tests/lib/suites/in-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,38 @@ export class InElementSuite extends RenderTest {
}

@test
'`insertBefore` can only be null'() {
'With insertBefore'() {
let externalElement = this.delegate.createElement('div');
let before = this.delegate.createElement('div');
replaceHTML(externalElement, '<b>Hello</b><em>there!</em>');

this.assert.throws(() => {
this.render('{{#in-element externalElement insertBefore=before}}[{{foo}}]{{/in-element}}', {
externalElement,
before,
foo: 'Yippie!',
});
}, /insertBefore only takes `null` as an argument/);
this.render(
stripTight`{{#in-element externalElement insertBefore=insertBefore}}[{{foo}}]{{/in-element}}`,
{ externalElement, insertBefore: externalElement.lastChild, foo: 'Yippie!' }
);

equalsElement(externalElement, 'div', {}, '<b>Hello</b>[Yippie!]<em>there!</em>');
this.assertHTML('<!---->');
this.assertStableRerender();

this.rerender({ foo: 'Double Yips!' });
equalsElement(externalElement, 'div', {}, '<b>Hello</b>[Double Yips!]<em>there!</em>');
this.assertHTML('<!---->');
this.assertStableNodes();

this.rerender({ insertBefore: null });
equalsElement(externalElement, 'div', {}, '<b>Hello</b><em>there!</em>[Double Yips!]');
this.assertHTML('<!---->');
this.assertStableRerender();

this.rerender({ externalElement: null });
equalsElement(externalElement, 'div', {}, '<b>Hello</b><em>there!</em>');
this.assertHTML('<!---->');
this.assertStableRerender();

this.rerender({ externalElement, insertBefore: externalElement.lastChild, foo: 'Yippie!' });
equalsElement(externalElement, 'div', {}, '<b>Hello</b>[Yippie!]<em>there!</em>');
this.assertHTML('<!---->');
this.assertStableRerender();
}

@test
Expand Down
2 changes: 1 addition & 1 deletion packages/@glimmer/interfaces/lib/dom/attributes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface DOMStack {
pushRemoteElement(
element: SimpleElement,
guid: string,
insertBefore: Option<null>
insertBefore: Option<SimpleNode>
): Option<RemoteLiveBlock>;
popRemoteElement(): void;
popElement(): void;
Expand Down
2 changes: 1 addition & 1 deletion packages/@glimmer/node/lib/serialize-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class SerializeBuilder extends NewElementBuilder implements ElementBuilder {
pushRemoteElement(
element: SimpleElement,
cursorId: string,
insertBefore: Option<null> = null
insertBefore: Option<SimpleNode> = null
): Option<RemoteLiveBlock> {
let { dom } = this;
let script = dom.createElement('script');
Expand Down
2 changes: 1 addition & 1 deletion packages/@glimmer/opcode-compiler/lib/syntax/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export function populateBuiltins(

for (let i = 0; i < keys.length; i++) {
let key = keys[i];
if (key === 'guid' || key === 'insertBefore') {
if (key === 'insertBefore' || key === 'guid') {
actions.push(op('Expr', values[i]));
} else {
throw new Error(`SYNTAX ERROR: #in-element does not take a \`${keys[0]}\` option`);
Expand Down
15 changes: 12 additions & 3 deletions packages/@glimmer/runtime/lib/compiled/opcodes/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
isConst,
isConstTag,
} from '@glimmer/reference';
import { check, CheckString, CheckElement } from '@glimmer/debug';
import { check, CheckString, CheckElement, CheckOption, CheckNode } from '@glimmer/debug';
import { Op, Option, ModifierManager } from '@glimmer/interfaces';
import { $t0 } from '@glimmer/vm';
import {
Expand All @@ -21,7 +21,7 @@ import { Assert } from './vm';
import { DynamicAttribute } from '../../vm/attributes/dynamic';
import { CheckReference, CheckArguments, CheckOperations } from './-debug-strip';
import { CONSTANTS } from '../../symbols';
import { SimpleElement } from '@simple-dom/interface';
import { SimpleElement, SimpleNode } from '@simple-dom/interface';
import { expect } from '@glimmer/util';

APPEND_OPCODES.add(Op.Text, (vm, { op1: text }) => {
Expand All @@ -47,6 +47,7 @@ APPEND_OPCODES.add(Op.PushRemoteElement, vm => {
let guidRef = check(vm.stack.pop(), CheckReference);

let element: SimpleElement;
let insertBefore: Option<SimpleNode>;
let guid = guidRef.value() as string;

if (isConst(elementRef)) {
Expand All @@ -57,7 +58,15 @@ APPEND_OPCODES.add(Op.PushRemoteElement, vm => {
vm.updateWith(new Assert(cache));
}

let insertBefore = insertBeforeRef.value() as Option<null>;
if (insertBeforeRef.value() !== undefined) {
if (isConst(insertBeforeRef)) {
insertBefore = check(insertBeforeRef.value(), CheckOption(CheckNode));
} else {
let cache = new ReferenceCache(insertBeforeRef as Reference<Option<SimpleNode>>);
insertBefore = check(cache.peek(), CheckOption(CheckNode));
vm.updateWith(new Assert(cache));
}
}

let block = vm.elements().pushRemoteElement(element, guid, insertBefore);
if (block) vm.associateDestroyable(block);
Expand Down
4 changes: 2 additions & 2 deletions packages/@glimmer/runtime/lib/vm/element-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,15 @@ export class NewElementBuilder implements ElementBuilder {
pushRemoteElement(
element: SimpleElement,
guid: string,
insertBefore: Option<null>
insertBefore: Option<SimpleNode>
): Option<RemoteLiveBlock> {
return this.__pushRemoteElement(element, guid, insertBefore);
}

__pushRemoteElement(
element: SimpleElement,
_guid: string,
insertBefore: Option<null>
insertBefore: Option<SimpleNode>
): Option<RemoteLiveBlock> {
this.pushElement(element, insertBefore);

Expand Down
2 changes: 1 addition & 1 deletion packages/@glimmer/runtime/lib/vm/rehydrate-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ export class RehydrateBuilder extends NewElementBuilder implements ElementBuilde
__pushRemoteElement(
element: SimpleElement,
cursorId: string,
insertBefore: Option<null>
insertBefore: Option<SimpleNode>
): Option<RemoteLiveBlock> {
let marker = this.getMarker(element as HTMLElement, cursorId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,10 +448,6 @@ function addInElementHash(cursor: string, hash: AST.Hash, loc: AST.SourceLocatio
}

if (pair.key === 'insertBefore') {
if (pair.value.type !== 'NullLiteral') {
throw new SyntaxError('insertBefore only takes `null` as an argument', loc);
}

hasInsertBefore = true;
}
});
Expand Down

0 comments on commit a3917d6

Please sign in to comment.