Skip to content

Commit fb9edf2

Browse files
committed
align component code more closely with post-refactor element code
1 parent 1e2c859 commit fb9edf2

File tree

6 files changed

+150
-143
lines changed

6 files changed

+150
-143
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
export default function visitAttribute ( generator, block, state, node, attribute, local ) {
2+
if ( attribute.value === true ) {
3+
// attributes without values, e.g. <textarea readonly>
4+
local.staticAttributes.push({
5+
name: attribute.name,
6+
value: true
7+
});
8+
}
9+
10+
else if ( attribute.value.length === 0 ) {
11+
local.staticAttributes.push({
12+
name: attribute.name,
13+
value: `''`
14+
});
15+
}
16+
17+
else if ( attribute.value.length === 1 ) {
18+
const value = attribute.value[0];
19+
20+
if ( value.type === 'Text' ) {
21+
// static attributes
22+
const result = isNaN( value.data ) ? JSON.stringify( value.data ) : value.data;
23+
local.staticAttributes.push({
24+
name: attribute.name,
25+
value: result
26+
});
27+
}
28+
29+
else {
30+
// simple dynamic attributes
31+
const { dependencies, string } = generator.contextualise( block, value.expression );
32+
33+
// TODO only update attributes that have changed
34+
local.dynamicAttributes.push({
35+
name: attribute.name,
36+
value: string,
37+
dependencies
38+
});
39+
}
40+
}
41+
42+
else {
43+
// complex dynamic attributes
44+
const allDependencies = [];
45+
46+
const value = ( attribute.value[0].type === 'Text' ? '' : `"" + ` ) + (
47+
attribute.value.map( chunk => {
48+
if ( chunk.type === 'Text' ) {
49+
return JSON.stringify( chunk.data );
50+
} else {
51+
const { dependencies, string } = generator.contextualise( block, chunk.expression );
52+
dependencies.forEach( dependency => {
53+
if ( !~allDependencies.indexOf( dependency ) ) allDependencies.push( dependency );
54+
});
55+
56+
return `( ${string} )`;
57+
}
58+
}).join( ' + ' )
59+
);
60+
61+
local.dynamicAttributes.push({
62+
name: attribute.name,
63+
value,
64+
dependencies: allDependencies
65+
});
66+
}
67+
}

src/generators/dom/visitors/Component/attributes/addComponentBinding.js src/generators/dom/visitors/Component/Binding.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import deindent from '../../../../../utils/deindent.js';
2-
import flattenReference from '../../../../../utils/flattenReference.js';
3-
import getSetter from '../../shared/binding/getSetter.js';
1+
import deindent from '../../../../utils/deindent.js';
2+
import flattenReference from '../../../../utils/flattenReference.js';
3+
import getSetter from '../shared/binding/getSetter.js';
44

5-
export default function addComponentBinding ( generator, node, attribute, block, local ) {
5+
export default function visitBinding ( generator, block, state, node, attribute, local ) {
66
const { name, keypath } = flattenReference( attribute.value );
77
const { snippet, contexts, dependencies } = generator.contextualise( block, attribute.value );
88

@@ -62,4 +62,4 @@ export default function addComponentBinding ( generator, node, attribute, block,
6262
${updating} = false;
6363
}
6464
` );
65-
}
65+
}

src/generators/dom/visitors/Component/Component.js

+30-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import deindent from '../../../../utils/deindent.js';
22
import CodeBuilder from '../../../../utils/CodeBuilder.js';
33
import visit from '../../visit.js';
4-
import addComponentAttributes from './attributes/addComponentAttributes.js';
4+
import visitAttribute from './Attribute.js';
5+
import visitEventHandler from './EventHandler.js';
6+
import visitBinding from './Binding.js';
7+
import visitRef from './Ref.js';
58

69
function capDown ( name ) {
710
return `${name[0].toLowerCase()}${name.slice( 1 )}`;
@@ -19,16 +22,37 @@ function stringifyProps ( props ) {
1922
return `{ ${joined} }`;
2023
}
2124

25+
const order = {
26+
Attribute: 1,
27+
EventHandler: 2,
28+
Binding: 3,
29+
Ref: 4
30+
};
31+
32+
const visitors = {
33+
Attribute: visitAttribute,
34+
EventHandler: visitEventHandler,
35+
Binding: visitBinding,
36+
Ref: visitRef
37+
};
38+
2239
export default function visitComponent ( generator, block, state, node ) {
2340
const hasChildren = node.children.length > 0;
2441
const name = block.getUniqueName( capDown( node.name === ':Self' ? generator.name : node.name ) );
2542

43+
const childState = Object.assign( {}, state, {
44+
parentNode: null
45+
});
46+
2647
const local = {
2748
name,
2849
namespace: state.namespace,
2950
isComponent: true,
3051

3152
allUsedContexts: [],
53+
staticAttributes: [],
54+
dynamicAttributes: [],
55+
bindings: [],
3256

3357
create: new CodeBuilder(),
3458
update: new CodeBuilder()
@@ -38,7 +62,11 @@ export default function visitComponent ( generator, block, state, node ) {
3862

3963
generator.hasComponents = true;
4064

41-
addComponentAttributes( generator, block, node, local );
65+
node.attributes
66+
.sort( ( a, b ) => order[ a.type ] - order[ b.type ] )
67+
.forEach( attribute => {
68+
visitors[ attribute.type ]( generator, block, childState, node, attribute, local );
69+
});
4270

4371
if ( local.allUsedContexts.length ) {
4472
const initialProps = local.allUsedContexts.map( contextName => {
@@ -81,10 +109,6 @@ export default function visitComponent ( generator, block, state, node ) {
81109
name: generator.getUniqueName( `create_${name}_yield_fragment` ) // TODO should getUniqueName happen inside Fragment? probably
82110
});
83111

84-
const childState = Object.assign( {}, state, {
85-
parentNode: null
86-
});
87-
88112
node.children.forEach( child => {
89113
visit( generator, childBlock, childState, child );
90114
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import deindent from '../../../../utils/deindent.js';
2+
3+
export default function visitEventHandler ( generator, block, state, node, attribute, local ) {
4+
// TODO verify that it's a valid callee (i.e. built-in or declared method)
5+
generator.addSourcemapLocations( attribute.expression );
6+
generator.code.prependRight( attribute.expression.start, `${block.component}.` );
7+
8+
const usedContexts = [];
9+
attribute.expression.arguments.forEach( arg => {
10+
const { contexts } = generator.contextualise( block, arg, null, true );
11+
12+
contexts.forEach( context => {
13+
if ( !~usedContexts.indexOf( context ) ) usedContexts.push( context );
14+
if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context );
15+
});
16+
});
17+
18+
// TODO hoist event handlers? can do `this.__component.method(...)`
19+
const declarations = usedContexts.map( name => {
20+
if ( name === 'root' ) return 'var root = this._context.root;';
21+
22+
const listName = block.listNames.get( name );
23+
const indexName = block.indexNames.get( name );
24+
25+
return `var ${listName} = this._context.${listName}, ${indexName} = this._context.${indexName}, ${name} = ${listName}[${indexName}]`;
26+
});
27+
28+
const handlerBody = ( declarations.length ? declarations.join( '\n' ) + '\n\n' : '' ) + `[✂${attribute.expression.start}-${attribute.expression.end}✂];`;
29+
30+
local.create.addBlock( deindent`
31+
${local.name}.on( '${attribute.name}', function ( event ) {
32+
${handlerBody}
33+
});
34+
` );
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import deindent from '../../../../utils/deindent.js';
2+
3+
export default function visitRef ( generator, block, state, node, attribute, local ) {
4+
generator.usesRefs = true;
5+
6+
local.create.addLine(
7+
`${block.component}.refs.${attribute.name} = ${local.name};`
8+
);
9+
10+
block.builders.destroy.addLine( deindent`
11+
if ( ${block.component}.refs.${attribute.name} === ${local.name} ) ${block.component}.refs.${attribute.name} = null;
12+
` );
13+
}

src/generators/dom/visitors/Component/attributes/addComponentAttributes.js

-132
This file was deleted.

0 commit comments

Comments
 (0)