pull/1746/head
Rich Harris 8 years ago
parent ec6bc6e6de
commit bb304d0a5c

@ -6,11 +6,53 @@ import createDebuggingComment from '../../../utils/createDebuggingComment';
import EachBlock from '../../nodes/EachBlock';
import FragmentWrapper from './Fragment';
import deindent from '../../../utils/deindent';
import ElseBlock from '../../nodes/ElseBlock';
class ElseBlockWrapper extends Wrapper {
node: ElseBlock;
block: Block;
fragment: FragmentWrapper;
isDynamic: boolean;
var = null;
constructor(
renderer: Renderer,
block: Block,
parent: Wrapper,
node: ElseBlock,
stripWhitespace: boolean,
nextSibling: Wrapper
) {
super(renderer, block, parent, node);
this.block = block.child({
comment: createDebuggingComment(node, this.renderer.component),
name: this.renderer.component.getUniqueName(`create_else_block`)
});
this.fragment = new FragmentWrapper(
renderer,
this.block,
this.node.children,
parent,
stripWhitespace,
nextSibling
);
this.isDynamic = this.block.dependencies.size > 0;
if (this.isDynamic) {
// TODO this can't be right
this.block.hasUpdateMethod = true;
}
}
}
export default class EachBlockWrapper extends Wrapper {
block: Block;
node: EachBlock;
fragment: FragmentWrapper;
else?: ElseBlockWrapper;
var: string;
vars: {
anchor: string;
@ -63,23 +105,26 @@ export default class EachBlockWrapper extends Wrapper {
renderer.blocks.push(this.block);
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?
if (this.else) {
this.else.block = block.child({
comment: createDebuggingComment(this.else, this.renderer.component),
name: renderer.component.getUniqueName(`${this.block.name}_else`),
});
renderer.blocks.push(this.else.block);
this.else.initChildren(
this.else.block,
if (this.node.else) {
this.else = new ElseBlockWrapper(
renderer,
block,
this,
this.node.else,
stripWhitespace,
nextSibling
);
this.else.block.hasUpdateMethod = this.else.block.dependencies.size > 0;
renderer.blocks.push(this.else.block);
if (this.else.isDynamic) {
this.block.addDependencies(this.else.block.dependencies);
}
}
block.addDependencies(this.block.dependencies);
this.block.hasUpdateMethod = this.block.dependencies.size > 0; // TODO should this logic be in Block?
if (this.block.hasOutros || (this.else && this.else.block.hasOutros)) {
block.addOutro();
@ -172,7 +217,7 @@ export default class EachBlockWrapper extends Wrapper {
}
`);
const initialMountNode = parentNode || `${anchor}.parentNode`;
const initialMountNode = parentNode || `${this.vars.anchor}.parentNode`;
if (this.else.block.hasUpdateMethod) {
block.builders.update.addBlock(deindent`
@ -197,7 +242,7 @@ export default class EachBlockWrapper extends Wrapper {
} else if (!${each_block_else}) {
${each_block_else} = ${this.else.block.name}(#component, ctx);
${each_block_else}.c();
${each_block_else}.${mountOrIntro}(${initialMountNode}, ${anchor});
${each_block_else}.${mountOrIntro}(${initialMountNode}, ${this.vars.anchor});
}
`);
}
@ -207,14 +252,10 @@ export default class EachBlockWrapper extends Wrapper {
`);
}
this.fragment.nodes.forEach((child: Wrapper) => {
child.render(this.block, null, 'nodes');
});
this.fragment.render(this.block, null, 'nodes');
if (this.else) {
this.else.children.forEach((child: Node) => {
child.build(this.else.block, null, 'nodes');
});
this.else.fragment.render(this.else.block, null, 'nodes');
}
}

@ -0,0 +1,29 @@
import Binding from '../../../../nodes/Binding';
import Element from '../../../../nodes/Element';
import ElementWrapper from '..';
import InputRadioGroupBinding from './InputRadioGroupBinding';
export default class InputCheckboxGroupBinding extends InputRadioGroupBinding {
element: ElementWrapper;
node: Binding;
static filter(
node: Element,
binding_lookup: Record<string, Binding>,
type: string
) {
if (node.name === 'input' && binding_lookup.group) {
return type === 'checkbox';
}
}
fromDom() {
return `@getBindingGroupValue(#component._bindingGroups[${this.bindingGroup}])`;
}
toDom() {
const condition = `~${this.binding.value.snippet}.indexOf(${this.element.var}.__value)`;
return `${this.element.var}.checked = ${condition};`
}
}

@ -10,6 +10,9 @@ import BindingWrapper from './Binding';
export default class InputRadioGroupBinding extends BindingWrapper {
element: ElementWrapper;
node: Binding;
bindingGroup: number;
events = ['change'];
static filter(
node: Element,
@ -26,59 +29,41 @@ export default class InputRadioGroupBinding extends BindingWrapper {
binding_lookup: Record<string, Binding>
) {
super(element, binding_lookup.group);
this.events = ['change'];
// TODO handle cases involving computed member expressions
const { parts } = flattenReference(this.binding.value.node);
const keypath = parts.join('.');
// TODO handle contextual bindings — `keypath` should include unique ID of
// each block that provides context
let index = element.renderer.bindingGroups.indexOf(keypath);
if (index === -1) {
index = element.renderer.bindingGroups.length;
element.renderer.bindingGroups.push(keypath);
}
fromDom() {
const bindingGroup = getBindingGroup(this.element.renderer, this.binding.value.node);
if (this.element.node.getStaticAttributeValue('type') === 'checkbox') {
return `@getBindingGroupValue(#component._bindingGroups[${bindingGroup}])`;
this.bindingGroup = index;
}
fromDom() {
return `${this.element.var}.__value`;
}
toDom() {
const type = this.element.node.getStaticAttributeValue('type');
const condition = type === 'checkbox'
? `~${this.binding.value.snippet}.indexOf(${this.element.var}.__value)`
: `${this.element.var}.__value === ${this.binding.value.snippet}`;
const condition = `${this.element.var}.__value === ${this.binding.value.snippet}`;
return `${this.element.var}.checked = ${condition};`
}
render(block: Block) {
const bindingGroup = getBindingGroup(
this.element.renderer,
this.binding.value.node
);
block.builders.hydrate.addLine(
`#component._bindingGroups[${bindingGroup}].push(${this.element.var});`
`#component._bindingGroups[${this.bindingGroup}].push(${this.element.var});`
);
block.builders.destroy.addLine(
`#component._bindingGroups[${bindingGroup}].splice(#component._bindingGroups[${bindingGroup}].indexOf(${this.element.var}), 1);`
`#component._bindingGroups[${this.bindingGroup}].splice(#component._bindingGroups[${this.bindingGroup}].indexOf(${this.element.var}), 1);`
);
super.render(block);
// this.renderHandler(block, 'TODO');
}
}
function getBindingGroup(renderer: Renderer, value: Node) {
const { parts } = flattenReference(value); // TODO handle cases involving computed member expressions
const keypath = parts.join('.');
// TODO handle contextual bindings — `keypath` should include unique ID of
// each block that provides context
let index = renderer.bindingGroups.indexOf(keypath);
if (index === -1) {
index = renderer.bindingGroups.length;
renderer.bindingGroups.push(keypath);
}
return index;
}

@ -15,6 +15,7 @@ import AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute';
import { dimensions } from '../../../../utils/patterns';
import InputCheckboxBinding from './Binding/InputCheckboxBinding';
import InputCheckboxGroupBinding from './Binding/InputCheckboxGroupBinding';
import InputNumberBinding from './Binding/InputNumberBinding';
import InputRangeBinding from './Binding/InputRangeBinding';
import InputTextBinding from './Binding/InputTextBinding';
@ -25,6 +26,7 @@ const bindings = [
InputTextBinding,
InputRadioGroupBinding,
InputCheckboxBinding,
InputCheckboxGroupBinding,
InputNumberBinding,
InputRangeBinding,
SelectBinding
@ -118,7 +120,7 @@ export default class ElementWrapper extends Wrapper {
nextSibling: Wrapper
) {
super(renderer, block, parent, node);
this.var = node.name;
this.var = node.name.replace(/[^a-zA-Z0-9_$]/g, '_')
this.classDependencies = [];

@ -117,10 +117,13 @@ export default class FragmentWrapper {
first.data = trimStart(first.data);
if (!first.data) {
this.nodes.shift();
if (this.nodes.length) {
link(null, this.nodes[0]);
}
}
}
}
if (windowWrapper) {
this.nodes.unshift(windowWrapper);

Loading…
Cancel
Save