get bind:this mostly working

pull/1878/head
Rich Harris 7 years ago
parent ea567f1492
commit dcc4d38861

2
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.0.0-alpha1",
"version": "3.0.0-alpha3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

@ -551,7 +551,7 @@ export default class Element extends Node {
message: `'${binding.name}' is not a valid binding on void elements like <${this.name}>. Use a wrapper element instead`
});
}
} else {
} else if (name !== 'this') {
component.error(binding, {
code: `invalid-binding`,
message: `'${binding.name}' is not a valid binding`

@ -178,6 +178,10 @@ function getDomUpdater(
return null;
}
if (binding.node.name === 'this') {
return null;
}
if (node.name === 'select') {
return node.getStaticAttributeValue('multiple') === true ?
`@selectOptions(${element.var}, ${snippet})` :
@ -259,6 +263,10 @@ function getValueFromDom(
const { node } = element;
const { name } = binding.node;
if (name === 'this') {
return `$$node`;
}
// <select bind:value='selected>
if (node.name === 'select') {
return node.getStaticAttributeValue('multiple') === true ?

@ -185,7 +185,6 @@ export default class ElementWrapper extends Wrapper {
if (node.classes.length > 0) this.parent.cannotUseInnerHTML();
if (node.intro || node.outro) this.parent.cannotUseInnerHTML();
if (node.handlers.length > 0) this.parent.cannotUseInnerHTML();
if (node.ref) this.parent.cannotUseInnerHTML();
if (this.node.name === 'option') this.parent.cannotUseInnerHTML();
@ -300,7 +299,6 @@ export default class ElementWrapper extends Wrapper {
this.addBindings(block);
this.addEventHandlers(block);
if (this.node.ref) this.addRef(block);
this.addAttributes(block);
this.addTransitions(block);
this.addAnimation(block);
@ -527,6 +525,23 @@ export default class ElementWrapper extends Wrapper {
});
this.initialUpdate = mungedBindings.map(binding => binding.initialUpdate).filter(Boolean).join('\n');
const this_binding = this.bindings.find(b => b.node.name === 'this');
if (this_binding) {
const name = renderer.component.getUniqueName(`${this.var}_binding`);
renderer.component.declarations.push(name);
renderer.component.template_references.add(name);
const { handler } = this_binding.munge(block);
renderer.component.partly_hoisted.push(deindent`
function ${name}($$node) {
${handler.mutation}
}
`);
block.builders.mount.addLine(`ctx.${name}(${this.var});`);
}
}
addAttributes(block: Block) {
@ -597,21 +612,6 @@ export default class ElementWrapper extends Wrapper {
addEventHandlers(block, this.var, this.node.handlers);
}
addRef(block: Block) {
const ref = `#component.$$.refs.${this.node.ref.name}`;
block.builders.mount.addLine(
`${ref} = ${this.var};`
);
block.builders.destroy.addLine(
`if (${ref} === ${this.var}) {
${ref} = null;
#component.$$.inject_refs(#component.$$.refs);
}`
);
}
addTransitions(
block: Block
) {

@ -196,6 +196,32 @@ export default class InlineComponentWrapper extends Wrapper {
}
const munged_bindings = this.node.bindings.map(binding => {
if (binding.name === 'this') {
const fn = component.getUniqueName(`${this.var}_binding`);
component.declarations.push(fn);
component.template_references.add(fn);
let lhs;
if (binding.isContextual && binding.expression.node.type === 'Identifier') {
// bind:x={y} — we can't just do `y = x`, we need to
// to `array[index] = x;
const { name } = binding.expression.node;
const { object, property, snippet } = block.bindings.get(name)();
lhs = snippet;
} else {
lhs = component.source.slice(binding.expression.node.start, binding.expression.node.end).trim();
}
component.partly_hoisted.push(deindent`
function ${fn}($$component) {
${lhs} = $$component;
}
`);
return `ctx.${fn}(${this.var})`;
}
component.has_reactive_assignments = true;
const name = component.getUniqueName(`${this.var}_${binding.name}_binding`);

@ -2,4 +2,4 @@
export let h1;
</script>
<h1 ref:h1>Hello world!</h1>
<h1 bind:this={h1}>Hello world!</h1>

@ -1,7 +0,0 @@
<div ref:foo/>
<style>
ref:foo {
color: red;
}
</style>

@ -1,99 +0,0 @@
{
"html": {
"start": 0,
"end": 14,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 14,
"type": "Element",
"name": "div",
"attributes": [
{
"start": 5,
"end": 12,
"type": "Ref",
"name": "foo",
"modifiers": [],
"expression": null
}
],
"children": []
},
{
"start": 14,
"end": 16,
"type": "Text",
"data": "\n\n"
}
]
},
"css": [
{
"start": 16,
"end": 60,
"attributes": [],
"children": [
{
"type": "Rule",
"selector": {
"type": "SelectorList",
"children": [
{
"type": "Selector",
"children": [
{
"type": "RefSelector",
"start": 25,
"end": 32,
"name": "foo"
}
],
"start": 25,
"end": 32
}
],
"start": 25,
"end": 32
},
"block": {
"type": "Block",
"children": [
{
"type": "Declaration",
"important": false,
"property": "color",
"value": {
"type": "Value",
"children": [
{
"type": "Identifier",
"name": "red",
"start": 44,
"end": 47
}
],
"start": 43,
"end": 47
},
"start": 37,
"end": 47
}
],
"start": 33,
"end": 51
},
"start": 25,
"end": 51
}
],
"content": {
"start": 23,
"end": 52,
"styles": "\n\tref:foo {\n\t\tcolor: red;\n\t}\n"
}
}
],
"js": []
}

@ -1 +1 @@
<canvas ref:foo></canvas>
<canvas bind:this={foo}></canvas>

@ -1,22 +1,27 @@
{
"html": {
"start": 0,
"end": 25,
"end": 33,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 25,
"end": 33,
"type": "Element",
"name": "canvas",
"attributes": [
{
"start": 8,
"end": 15,
"type": "Ref",
"name": "foo",
"end": 23,
"type": "Binding",
"name": "this",
"modifiers": [],
"expression": null
"expression": {
"type": "Identifier",
"start": 19,
"end": 22,
"name": "foo"
}
}
],
"children": []

@ -11,5 +11,5 @@
});
</script>
<p ref:a>{value}</p>
<p ref:b></p>
<p bind:this={a}>{value}</p>
<p bind:this={b}></p>

@ -4,5 +4,5 @@
</script>
{#if visible}
<input ref:input autofocus>
<input bind:this={input} autofocus>
{/if}

@ -7,7 +7,7 @@
{#await thePromise}
<p>loading...</p>
{:then theValue}
<button ref:button on:click='{() => clicked = theValue}'>click me</button>
<button bind:this={button} on:click='{() => clicked = theValue}'>click me</button>
{:catch theError}
<p>oh no! {theError.message}</p>
{/await}

@ -4,4 +4,4 @@
import List from './List.html';
</script>
<List ref:list/>
<List bind:this={list}/>

@ -6,7 +6,7 @@
export let letters = ['a', 'b', 'c'];
</script>
<Modal ref:modal>
<Modal bind:this={modal}>
<span>{letter}</span>
<select bind:value={letter}>
{#each letters as letter}

@ -4,4 +4,4 @@
export let one;
</script>
<One ref:one/>
<One bind:this={one}/>

@ -8,5 +8,5 @@
export let baz;
</script>
<Foo ref:foo bind:bar bind:baz/>
<p ref:p>{bar + baz}</p>
<Foo bind:this={foo} bind:bar bind:baz/>
<p bind:this={p}>{bar + baz}</p>

@ -4,4 +4,4 @@
export let l1;
</script>
<Level1 ref:l1 />
<Level1 bind:this={l1} />

@ -4,5 +4,5 @@
</script>
<div>
<Widget ref:widget/>
<Widget bind:this={widget}/>
</div>

@ -4,6 +4,6 @@
export let nested;
</script>
<Nested ref:nested>
<Nested bind:this={nested}>
<p>override default slot</p>
</Nested>

@ -6,5 +6,5 @@
</script>
<div>
<Widget ref:widget>{data}</Widget>
<Widget bind:this={widget}>{data}</Widget>
</div>

@ -7,7 +7,7 @@
{#each components as component}
<li>
{#if component.edit}
<input ref:name bind:value={component.name} />
<input bind:this={name} bind:value={component.name} />
{:else}
{component.name}
{/if}

@ -4,4 +4,4 @@
export let test;
</script>
<svelte:component this={Foo} ref:test/>
<svelte:component this={Foo} bind:this={test}/>

@ -5,5 +5,5 @@
</script>
{#if visible}
<input ref:input on:blur='{() => blurred = true}'>
<input bind:this={input} on:blur='{() => blurred = true}'>
{/if}

@ -5,5 +5,5 @@
</script>
<div>
<Nested ref:nested />
<Nested bind:this={nested} />
</div>

@ -4,4 +4,4 @@
import Folder from './Folder.html';
</script>
<Folder ref:folder dir="a"/>
<Folder bind:this={folder} dir="a"/>

@ -9,4 +9,4 @@
});
</script>
<div ref:element></div>
<div bind:this={element}></div>

@ -6,5 +6,5 @@
</script>
{#if visible}
<Top ref:top></Top>
<Top bind:this={top}></Top>
{/if}

@ -10,4 +10,4 @@
});
</script>
<p ref:x>{inDocument}</p>
<p bind:this={x}>{inDocument}</p>

@ -10,4 +10,4 @@
});
</script>
<p ref:x>{inDocument}</p>
<p bind:this={x}>{inDocument}</p>

@ -2,4 +2,4 @@
export let foo;
</script>
<div><canvas ref:foo></canvas></div>
<div><canvas bind:this={foo}></canvas></div>

@ -4,7 +4,7 @@
</script>
{#if x}
<canvas ref:foo data-x='true'></canvas>
<canvas bind:this={foo} data-x='true'></canvas>
{:else}
<canvas ref:foo data-x='false'></canvas>
<canvas bind:this={foo} data-x='false'></canvas>
{/if}

@ -2,4 +2,4 @@
export let foo;
</script>
<canvas ref:foo></canvas>
<canvas bind:this={foo}></canvas>

@ -13,5 +13,5 @@
</script>
{#if visible}
<div out:fade style="opacity: 1;" ref:div>yes</div>
<div out:fade style="opacity: 1;" bind:this={div}>yes</div>
{/if}

@ -16,7 +16,7 @@
</script>
{#if x}
<div ref:yes out:foo>{z}</div>
<div bind:this={yes} out:foo>{z}</div>
{:else}
<div ref:no out:foo>{z}</div>
<div bind:this={no} out:foo>{z}</div>
{/if}

@ -15,7 +15,7 @@
</script>
{#if x}
<div ref:yes in:foo>yes</div>
<div bind:this={yes} in:foo>yes</div>
{:else}
<div ref:no in:foo>no</div>
<div bind:this={no} in:foo>no</div>
{/if}

@ -15,7 +15,7 @@
</script>
{#if x}
<div ref:yes out:foo>yes</div>
<div bind:this={yes} out:foo>yes</div>
{:else}
<div ref:no out:foo>no</div>
<div bind:this={no} out:foo>no</div>
{/if}

@ -16,7 +16,7 @@
</script>
{#if x}
<div ref:yes out:foo>yes</div>
<div bind:this={yes} out:foo>yes</div>
{:elseif y}
<div ref:no out:foo>no</div>
<div bind:this={no} out:foo>no</div>
{/if}

@ -6,4 +6,4 @@
export let foo = 42;
</script>
<div><Widget ref:widget foo='{foo}'/></div>
<div><Widget bind:this={widget} foo='{foo}'/></div>

@ -4,4 +4,4 @@
import Widget from './Widget.html';
</script>
<div><Widget ref:widget/></div>
<div><Widget bind:this={widget}/></div>

@ -1,15 +0,0 @@
[{
"message": "Reference name 'foo-bar' is invalid — must be a valid identifier such as foo_bar",
"start": {
"line": 1,
"column": 5,
"character": 5
},
"end": {
"line": 1,
"column": 16,
"character": 16
},
"pos": 5,
"code": "invalid-reference-name"
}]

@ -1,8 +0,0 @@
<div ref:foo-bar>
</div>
<style>
ref:foo-bar {
display: flex;
}
</style>
Loading…
Cancel
Save