more simplification

pull/1934/head
Richard Harris 7 years ago
parent 287590e338
commit 49db9e7524

@ -26,10 +26,9 @@ export default class BindingWrapper {
mutation: string; mutation: string;
contextual_dependencies: Set<string> contextual_dependencies: Set<string>
}; };
updateDom: string; snippet: string;
initialUpdate: string; initialUpdate: string;
needsLock: boolean; needsLock: boolean;
updateCondition: string;
constructor(block: Block, node: Binding, parent: ElementWrapper) { constructor(block: Block, node: Binding, parent: ElementWrapper) {
this.node = node; this.node = node;
@ -64,39 +63,25 @@ export default class BindingWrapper {
// view to model // view to model
this.handler = getEventHandler(this, parent.renderer, block, this.object, contextless_snippet); this.handler = getEventHandler(this, parent.renderer, block, this.object, contextless_snippet);
}
isReadOnlyMediaAttribute() {
return readOnlyMediaAttributes.has(this.node.name);
}
munge(block: Block) { this.snippet = this.node.expression.render();
const { parent } = this;
const { renderer } = parent;
const needsLock = (
parent.node.name !== 'input' ||
!/radio|checkbox|range|color/.test(parent.node.getStaticAttributeValue('type'))
);
const isReadOnly = ( const isReadOnly = (
(parent.node.isMediaNode() && readOnlyMediaAttributes.has(this.node.name)) || (parent.node.isMediaNode() && readOnlyMediaAttributes.has(this.node.name)) ||
dimensions.test(this.node.name) dimensions.test(this.node.name)
); );
let updateConditions: string[] = []; this.needsLock = !isReadOnly && (
parent.node.name !== 'input' ||
const snippet = this.node.expression.render(); !/radio|checkbox|range|color/.test(parent.node.getStaticAttributeValue('type'))
);
}
// special case: if you have e.g. `<input type=checkbox bind:checked=selected.done>` get_dependencies() {
// and `selected` is an object chosen with a <select>, then when `checked` changes,
// we need to tell the component to update all the values `selected` might be
// pointing to
// TODO should this happen in preprocess?
const dependencies = new Set(this.node.expression.dependencies); const dependencies = new Set(this.node.expression.dependencies);
this.node.expression.dependencies.forEach((prop: string) => { this.node.expression.dependencies.forEach((prop: string) => {
const indirectDependencies = renderer.component.indirectDependencies.get(prop); const indirectDependencies = this.parent.renderer.component.indirectDependencies.get(prop);
if (indirectDependencies) { if (indirectDependencies) {
indirectDependencies.forEach(indirectDependency => { indirectDependencies.forEach(indirectDependency => {
dependencies.add(indirectDependency); dependencies.add(indirectDependency);
@ -104,8 +89,24 @@ export default class BindingWrapper {
} }
}); });
return dependencies;
}
isReadOnlyMediaAttribute() {
return readOnlyMediaAttributes.has(this.node.name);
}
render(block: Block, lock: string) {
// bind:offsetWidth and bind:offsetHeight — readonly
if (dimensions.test(this.node.name)) return;
const { parent } = this;
const { renderer } = parent;
let updateConditions: string[] = this.needsLock ? [`!${lock}`] : [];
// model to view // model to view
let updateDom = getDomUpdater(parent, this, snippet); let updateDom = getDomUpdater(parent, this);
let initialUpdate = updateDom; let initialUpdate = updateDom;
// special cases // special cases
@ -122,7 +123,7 @@ export default class BindingWrapper {
} }
if (this.node.name === 'currentTime' || this.node.name === 'volume') { if (this.node.name === 'currentTime' || this.node.name === 'volume') {
updateConditions.push(`!isNaN(${snippet})`); updateConditions.push(`!isNaN(${this.snippet})`);
if (this.node.name === 'currentTime') initialUpdate = null; if (this.node.name === 'currentTime') initialUpdate = null;
} }
@ -132,17 +133,11 @@ export default class BindingWrapper {
const last = block.getUniqueName(`${parent.var}_is_paused`); const last = block.getUniqueName(`${parent.var}_is_paused`);
block.addVariable(last, 'true'); block.addVariable(last, 'true');
updateConditions.push(`${last} !== (${last} = ${snippet})`); updateConditions.push(`${last} !== (${last} = ${this.snippet})`);
updateDom = `${parent.var}[${last} ? "pause" : "play"]();`; updateDom = `${parent.var}[${last} ? "pause" : "play"]();`;
initialUpdate = null; initialUpdate = null;
} }
// bind:offsetWidth and bind:offsetHeight
if (dimensions.test(this.node.name)) {
initialUpdate = null;
updateDom = null;
}
const dependencyArray = [...this.node.expression.dynamic_dependencies] const dependencyArray = [...this.node.expression.dynamic_dependencies]
if (dependencyArray.length === 1) { if (dependencyArray.length === 1) {
@ -153,26 +148,21 @@ export default class BindingWrapper {
) )
} }
return { if (updateDom) {
name: this.node.name, block.builders.update.addLine(
object: this.object, updateConditions.length ? `if (${updateConditions.join(' && ')}) ${updateDom}` : updateDom
handler: this.handler, );
snippet, }
updateDom: updateDom,
initialUpdate: initialUpdate, if (initialUpdate) {
needsLock: !isReadOnly && needsLock, block.builders.mount.addBlock(initialUpdate);
updateCondition: updateConditions.length ? updateConditions.join(' && ') : undefined, }
isReadOnlyMediaAttribute: this.isReadOnlyMediaAttribute(),
dependencies,
contextual_dependencies: this.node.expression.contextual_dependencies
};
} }
} }
function getDomUpdater( function getDomUpdater(
element: ElementWrapper, element: ElementWrapper,
binding: BindingWrapper, binding: BindingWrapper
snippet: string
) { ) {
const { node } = element; const { node } = element;
@ -186,21 +176,21 @@ function getDomUpdater(
if (node.name === 'select') { if (node.name === 'select') {
return node.getStaticAttributeValue('multiple') === true ? return node.getStaticAttributeValue('multiple') === true ?
`@selectOptions(${element.var}, ${snippet})` : `@selectOptions(${element.var}, ${binding.snippet})` :
`@selectOption(${element.var}, ${snippet})`; `@selectOption(${element.var}, ${binding.snippet})`;
} }
if (binding.node.name === 'group') { if (binding.node.name === 'group') {
const type = node.getStaticAttributeValue('type'); const type = node.getStaticAttributeValue('type');
const condition = type === 'checkbox' const condition = type === 'checkbox'
? `~${snippet}.indexOf(${element.var}.__value)` ? `~${binding.snippet}.indexOf(${element.var}.__value)`
: `${element.var}.__value === ${snippet}`; : `${element.var}.__value === ${binding.snippet}`;
return `${element.var}.checked = ${condition};` return `${element.var}.checked = ${condition};`
} }
return `${element.var}.${binding.node.name} = ${snippet};`; return `${element.var}.${binding.node.name} = ${binding.snippet};`;
} }
function getBindingGroup(renderer: Renderer, value: Node) { function getBindingGroup(renderer: Renderer, value: Node) {

@ -90,7 +90,6 @@ export default class ElementWrapper extends Wrapper {
attributes: AttributeWrapper[]; attributes: AttributeWrapper[];
bindings: Binding[]; bindings: Binding[];
classDependencies: string[]; classDependencies: string[];
initialUpdate: string;
slotOwner?: InlineComponentWrapper; slotOwner?: InlineComponentWrapper;
selectBindingDependencies?: Set<string>; selectBindingDependencies?: Set<string>;
@ -291,10 +290,6 @@ export default class ElementWrapper extends Wrapper {
this.addActions(block); this.addActions(block);
this.addClasses(block); this.addClasses(block);
if (this.initialUpdate) {
block.builders.mount.addBlock(this.initialUpdate);
}
if (nodes && this.renderer.options.hydratable) { if (nodes && this.renderer.options.hydratable) {
block.builders.claim.addLine( block.builders.claim.addLine(
`${nodes}.forEach(@detachNode);` `${nodes}.forEach(@detachNode);`
@ -378,7 +373,8 @@ export default class ElementWrapper extends Wrapper {
const needsLock = this.node.name !== 'input' || !/radio|checkbox|range|color/.test(this.getStaticAttributeValue('type')); const needsLock = this.node.name !== 'input' || !/radio|checkbox|range|color/.test(this.getStaticAttributeValue('type'));
// TODO munge in constructor // TODO munge in constructor
const mungedBindings = this.bindings.map(binding => binding.munge(block)); // const mungedBindings = this.bindings.map(binding => binding.munge(block));
const mungedBindings = this.bindings;
const lock = mungedBindings.some(binding => binding.needsLock) ? const lock = mungedBindings.some(binding => binding.needsLock) ?
block.getUniqueName(`${this.var}_updating`) : block.getUniqueName(`${this.var}_updating`) :
@ -390,8 +386,8 @@ export default class ElementWrapper extends Wrapper {
.map(event => ({ .map(event => ({
events: event.eventNames, events: event.eventNames,
bindings: mungedBindings bindings: mungedBindings
.filter(binding => binding.name !== 'this') .filter(binding => binding.node.name !== 'this')
.filter(binding => event.filter(this.node, binding.name)) .filter(binding => event.filter(this.node, binding.node.name))
})) }))
.filter(group => group.bindings.length); .filter(group => group.bindings.length);
@ -400,6 +396,7 @@ export default class ElementWrapper extends Wrapper {
renderer.component.declarations.push(handler); renderer.component.declarations.push(handler);
renderer.component.template_references.add(handler); renderer.component.template_references.add(handler);
// TODO figure out how to handle locks
const needsLock = group.bindings.some(binding => binding.needsLock); const needsLock = group.bindings.some(binding => binding.needsLock);
const dependencies = new Set(); const dependencies = new Set();
@ -407,18 +404,11 @@ export default class ElementWrapper extends Wrapper {
group.bindings.forEach(binding => { group.bindings.forEach(binding => {
// TODO this is a mess // TODO this is a mess
addToSet(dependencies, binding.dependencies); addToSet(dependencies, binding.get_dependencies());
addToSet(contextual_dependencies, binding.contextual_dependencies); addToSet(contextual_dependencies, binding.node.expression.contextual_dependencies);
addToSet(contextual_dependencies, binding.handler.contextual_dependencies); addToSet(contextual_dependencies, binding.handler.contextual_dependencies);
if (!binding.updateDom) return; binding.render(block, lock);
const updateConditions = needsLock ? [`!${lock}`] : [];
if (binding.updateCondition) updateConditions.push(binding.updateCondition);
block.builders.update.addLine(
updateConditions.length ? `if (${updateConditions.join(' && ')}) ${binding.updateDom}` : binding.updateDom
);
}); });
const mutations = group.bindings.map(binding => binding.handler.mutation).filter(Boolean).join('\n'); const mutations = group.bindings.map(binding => binding.handler.mutation).filter(Boolean).join('\n');
@ -432,8 +422,6 @@ export default class ElementWrapper extends Wrapper {
block.addVariable(animation_frame); block.addVariable(animation_frame);
} }
// TODO figure out how to handle locks
let callee; let callee;
// TODO dry this out — similar code for event handlers and component bindings // TODO dry this out — similar code for event handlers and component bindings
@ -499,7 +487,7 @@ export default class ElementWrapper extends Wrapper {
.map(binding => `${binding.snippet} === void 0`) .map(binding => `${binding.snippet} === void 0`)
.join(' || '); .join(' || ');
if (this.node.name === 'select' || group.bindings.find(binding => binding.name === 'indeterminate' || binding.isReadOnlyMediaAttribute)) { if (this.node.name === 'select' || group.bindings.find(binding => binding.node.name === 'indeterminate' || binding.isReadOnlyMediaAttribute())) {
block.builders.hydrate.addLine( block.builders.hydrate.addLine(
`if (${someInitialStateIsUndefined}) @add_render_callback(() => ${callee}.call(${this.var}));` `if (${someInitialStateIsUndefined}) @add_render_callback(() => ${callee}.call(${this.var}));`
); );
@ -512,8 +500,6 @@ 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'); const this_binding = this.bindings.find(b => b.node.name === 'this');
if (this_binding) { if (this_binding) {
const name = renderer.component.getUniqueName(`${this.var}_binding`); const name = renderer.component.getUniqueName(`${this.var}_binding`);

Loading…
Cancel
Save