some binding stuff

pull/1746/head
Rich Harris 7 years ago
parent 69804ecaf8
commit d381294651

@ -9,7 +9,7 @@ export interface BlockOptions {
renderer?: Renderer;
comment?: string;
key?: string;
bindings?: Map<string, string>;
bindings?: Map<string, () => string>;
dependencies?: Set<string>;
}
@ -26,7 +26,7 @@ export default class Block {
dependencies: Set<string>;
bindings: Map<string, string>;
bindings: Map<string, () => string>;
builders: {
init: CodeBuilder;
@ -109,30 +109,37 @@ export default class Block {
const seen = new Set();
const dupes = new Set();
this.wrappers.forEach(wrapper => {
if (!wrapper.var) return;
if (wrapper.parent && wrapper.parent.canUseInnerHTML) return;
let i = this.wrappers.length;
while (i--) {
const wrapper = this.wrappers[i];
if (!wrapper.var) continue;
if (wrapper.parent && wrapper.parent.canUseInnerHTML) continue;
if (seen.has(wrapper.var)) {
dupes.add(wrapper.var);
}
seen.add(wrapper.var);
});
}
const counts = new Map();
i = this.wrappers.length;
while (i--) {
const wrapper = this.wrappers[i];
this.wrappers.forEach(wrapper => {
if (!wrapper.var) return;
if (dupes.has(wrapper.var)) {
const i = counts.get(wrapper.var) || 0;
wrapper.var = this.getUniqueName(wrapper.var + i);
counts.set(wrapper.var, i + 1);
wrapper.var = this.getUniqueName(wrapper.var + i);
} else {
wrapper.var = this.getUniqueName(wrapper.var);
}
});
}
}
addDependencies(dependencies: Set<string>) {

@ -49,9 +49,12 @@ export default class EachBlockWrapper extends Wrapper {
// TODO this seems messy
this.block.hasAnimation = this.node.hasAnimation;
// node.contexts.forEach(prop => {
// this.block.bindings.set(prop.key.name, `ctx.${this.vars.each_block_value}[ctx.${indexName}]${prop.tail}`);
// });
this.indexName = this.node.index || renderer.component.getUniqueName(`${this.node.context}_index`);
node.contexts.forEach(prop => {
// TODO this doesn't feel great
this.block.bindings.set(prop.key.name, () => `ctx.${this.vars.each_block_value}[ctx.${this.indexName}]${prop.tail}`);
});
if (this.node.index) {
this.block.getUniqueName(this.node.index); // this prevents name collisions (#1254)
@ -59,7 +62,7 @@ export default class EachBlockWrapper extends Wrapper {
renderer.blocks.push(this.block);
this.fragment = new FragmentWrapper(renderer, block, node.children, this, stripWhitespace, nextSibling);
this.fragment = new FragmentWrapper(renderer, this.block, node.children, this, stripWhitespace, nextSibling);
block.addDependencies(this.block.dependencies);
this.block.hasUpdateMethod = this.block.dependencies.size > 0; // TODO should this logic be in Block?
@ -116,12 +119,10 @@ export default class EachBlockWrapper extends Wrapper {
this.contextProps = this.node.contexts.map(prop => `child_ctx.${prop.key.name} = list[i]${prop.tail};`);
const indexName = this.node.index || renderer.component.getUniqueName(`${this.node.context}_index`);
// TODO only add these if necessary
this.contextProps.push(
`child_ctx.${this.vars.each_block_value} = list;`,
`child_ctx.${indexName} = i;`
`child_ctx.${this.indexName} = i;`
);
const { snippet } = this.node.expression;

@ -3,7 +3,6 @@ import Block from '../../Block';
import fixAttributeCasing from '../../../../utils/fixAttributeCasing';
import ElementWrapper from './index';
import { stringify } from '../../../../utils/stringify';
import Wrapper from '../shared/wrapper';
import deindent from '../../../../utils/deindent';
export default class AttributeWrapper {

@ -214,13 +214,15 @@ export default class BindingWrapper {
updateConditions.length ? `if (${updateConditions.join(' && ')}) ${this.updateDom}` : this.updateDom
);
block.builders.hydrate.addLine(
`@addListener(${this.element.var}, "${name}", ${handler_name});`
);
block.builders.destroy.addLine(
`@removeListener(${this.element.var}, "${name}", ${handler_name});`
);
this.events.forEach(name => {
block.builders.hydrate.addLine(
`@addListener(${this.element.var}, "${name}", ${handler_name});`
);
block.builders.destroy.addLine(
`@removeListener(${this.element.var}, "${name}", ${handler_name});`
);
});
}
}
@ -247,7 +249,7 @@ function getEventHandler(
usesContext: true,
usesState: true,
usesStore: storeDependencies.length > 0,
mutation: `${head}${tail} = ${value};`,
mutation: `${head()}${tail} = ${value};`,
props: dependenciesArray.map(prop => `${prop}: ctx.${prop}`),
storeProps: storeDependencies.map(prop => `${prop}: $.${prop}`)
};

@ -0,0 +1,35 @@
import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import BindingWrapper from './Binding';
export default class InputCheckboxBinding extends BindingWrapper {
events = ['change'];
static filter(
node: Element,
binding_lookup: Record<string, Binding>,
type: string
) {
return (
node.name === 'input' &&
binding_lookup.checked &&
type === 'checkbox'
);
}
constructor(
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.checked);
}
fromDom() {
return `${this.element.var}.checked`;
}
toDom() {
return `${this.element.var}.checked = ${this.binding.value.snippet};`;
}
}

@ -1,10 +1,11 @@
import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import Block from '../../../Block';
import BindingWrapper from './Binding';
export default class InputTextBinding extends BindingWrapper {
events = ['input'];
static filter(
node: Element,
binding_lookup: Record<string, Binding>,
@ -23,10 +24,15 @@ export default class InputTextBinding extends BindingWrapper {
element: ElementWrapper,
binding_lookup: Record<string, Binding>
) {
super(element);
super(element, binding_lookup.value);
this.needsLock = true;
}
render(block: Block) {
fromDom() {
return `${this.element.var}.value`;
}
toDom() {
return `${this.element.var}.value = ${this.binding.value.snippet};`;
}
}

@ -1,10 +1,6 @@
import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import Block from '../../../Block';
import Renderer from '../../../Renderer';
import flattenReference from '../../../../../utils/flattenReference';
import { Node } from '../../../../../interfaces';
import BindingWrapper from './Binding';
export default class SelectBinding extends BindingWrapper {
@ -47,10 +43,4 @@ export default class SelectBinding extends BindingWrapper {
`@selectOptions(${this.element.var}, ${this.binding.value.snippet});` :
`@selectOption(${this.element.var}, ${this.binding.value.snippet});`;
}
render(block: Block) {
super.render(block);
}
}

@ -3,7 +3,6 @@ import Element from '../../../nodes/Element';
import Wrapper from '../shared/Wrapper';
import Block from '../../Block';
import Node from '../../../nodes/shared/Node';
import { CompileOptions } from '../../../../interfaces';
import { quotePropIfNecessary, quoteNameIfNecessary } from '../../../../utils/quoteIfNecessary';
import isVoidElementName from '../../../../utils/isVoidElementName';
import FragmentWrapper from '../Fragment';
@ -15,6 +14,7 @@ import namespaces from '../../../../utils/namespaces';
import AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute';
import { dimensions } from '../../../../utils/patterns';
import InputCheckboxBinding from './Binding/InputCheckboxBinding';
import InputTextBinding from './Binding/InputTextBinding';
import InputRadioGroupBinding from './Binding/InputRadioGroupBinding';
import SelectBinding from './Binding/SelectBinding';
@ -22,6 +22,7 @@ import SelectBinding from './Binding/SelectBinding';
const bindings = [
InputTextBinding,
InputRadioGroupBinding,
InputCheckboxBinding,
SelectBinding
];
@ -124,9 +125,11 @@ export default class ElementWrapper extends Wrapper {
return new AttributeWrapper(attribute, this);
});
let has_bindings;
const binding_lookup = {};
this.node.bindings.forEach(binding => {
binding_lookup[binding.name] = binding;
has_bindings = true;
});
const type = this.node.getStaticAttributeValue('type');
@ -140,6 +143,11 @@ export default class ElementWrapper extends Wrapper {
})
.map(Binding => new Binding(this, binding_lookup));
// TODO remove this, it's just useful during refactoring
if (has_bindings && !this.bindings.length) {
throw new Error(`no binding was created`);
}
this.fragment = new FragmentWrapper(renderer, block, node.children, this, stripWhitespace, nextSibling);
}

@ -14,10 +14,6 @@ function isElseIf(node: ElseBlock) {
);
}
function isElseBranch(branch) {
return branch.block && !branch.condition;
}
class IfBlockBranch extends Wrapper {
block: Block;
fragment: FragmentWrapper;

@ -204,7 +204,7 @@ export default class InlineComponentWrapper extends Wrapper {
const lhs = binding.value.node.type === 'MemberExpression'
? binding.value.snippet
: `${head}${tail} = childState${quotePropIfNecessary(binding.name)}`;
: `${head()}${tail} = childState${quotePropIfNecessary(binding.name)}`;
setFromChild = deindent`
${lhs} = childState${quotePropIfNecessary(binding.name)};

@ -4,6 +4,8 @@ import Node from '../../nodes/shared/Node';
import Tag from './shared/Tag';
export default class MustacheTagWrapper extends Tag {
var = 'text';
constructor(renderer: Renderer, block: Block, parent: Wrapper, node: Node) {
super(renderer, block, parent, node);
this.cannotUseInnerHTML();

@ -6,6 +6,8 @@ import Wrapper from './shared/wrapper';
import deindent from '../../../utils/deindent';
export default class RawMustacheTagWrapper extends Tag {
var = 'raw';
constructor(
renderer: Renderer,
block: Block,

@ -2,13 +2,16 @@ import Wrapper from './Wrapper';
import Renderer from '../../Renderer';
import Block from '../../Block';
import Node from '../../../nodes/shared/Node';
import MustacheTag from '../../../nodes/MustacheTag';
import RawMustacheTag from '../../../nodes/RawMustacheTag';
export default class Tag extends Wrapper {
constructor(renderer: Renderer, block: Block, parent: Wrapper, node: Node) {
node: MustacheTag | RawMustacheTag;
constructor(renderer: Renderer, block: Block, parent: Wrapper, node: MustacheTag | RawMustacheTag) {
super(renderer, block, parent, node);
this.cannotUseInnerHTML();
this.var = this.type === 'MustacheTag' ? 'text' : 'raw';
block.addDependencies(node.expression.dependencies);
}

Loading…
Cancel
Save