From cdb4a3568d68bbb834051473cb9485f87bc61b16 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 20 Dec 2016 23:21:28 -0500 Subject: [PATCH 1/4] use empty comments as anchors --- src/generators/dom/index.js | 4 ++-- src/generators/dom/visitors/EachBlock.js | 2 +- src/generators/dom/visitors/IfBlock.js | 2 +- src/generators/dom/visitors/YieldTag.js | 2 +- src/shared/dom.js | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 929d737700..de0c5dc496 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -98,9 +98,9 @@ class DomGenerator extends Generator { ` ); } - createAnchor ( name, description = '' ) { + createAnchor ( name ) { this.uses.createComment = true; - const renderStatement = `createComment( ${JSON.stringify( description )} )`; + const renderStatement = `createComment()`; this.addElement( name, renderStatement, true ); } diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index 2799a421b8..700e16ef7a 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -21,7 +21,7 @@ export default { const { dependencies, snippet } = generator.contextualise( node.expression ); const anchor = `${name}_anchor`; - generator.createAnchor( anchor, `#each ${generator.source.slice( node.expression.start, node.expression.end )}` ); + generator.createAnchor( anchor ); generator.current.builders.init.addLine( `var ${name}_value = ${snippet};` ); generator.current.builders.init.addLine( `var ${iterations} = [];` ); diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index 02133e539d..5ceb42d48b 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -41,7 +41,7 @@ export default { const conditionsAndBlocks = getConditionsAndBlocks( generator, node, generator.getUniqueName( `renderIfBlock` ) ); const anchor = `${name}_anchor`; - generator.createAnchor( anchor, `#if ${generator.source.slice( node.expression.start, node.expression.end )}` ); + generator.createAnchor( anchor ); generator.current.builders.init.addBlock( deindent` function ${getBlock} ( ${params} ) { diff --git a/src/generators/dom/visitors/YieldTag.js b/src/generators/dom/visitors/YieldTag.js index 5fefcd73a3..98996486c1 100644 --- a/src/generators/dom/visitors/YieldTag.js +++ b/src/generators/dom/visitors/YieldTag.js @@ -1,7 +1,7 @@ export default { enter ( generator ) { const anchor = `yield_anchor`; - generator.createAnchor( anchor, 'yield' ); + generator.createAnchor( anchor ); generator.current.builders.mount.addLine( `component._yield && component._yield.mount( ${generator.current.target}, ${anchor} );` diff --git a/src/shared/dom.js b/src/shared/dom.js index 9d4231572f..4007e90289 100644 --- a/src/shared/dom.js +++ b/src/shared/dom.js @@ -34,8 +34,8 @@ export function createText ( data ) { return document.createTextNode( data ); } -export function createComment ( data ) { - return document.createComment( data ); +export function createComment () { + return document.createComment( '' ); } export function addEventListener ( node, event, handler ) { From 2316d7d3482ca3f31dfe3e0fe5cfd9eee9463364 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 27 Dec 2016 20:59:43 -0500 Subject: [PATCH 2/4] fix unit tests --- test/generator/attribute-dynamic-multiple/_config.js | 2 +- test/generator/binding-input-text-contextual/_config.js | 6 +++--- .../generator/binding-input-text-deep-contextual/_config.js | 6 +++--- test/generator/component-yield-parent/_config.js | 6 +++--- test/generator/each-block-indexed/_config.js | 2 +- test/generator/each-block/_config.js | 6 +++--- test/generator/each-blocks-expression/_config.js | 2 +- test/generator/each-blocks-nested-b/_config.js | 2 +- test/generator/each-blocks-nested/_config.js | 2 +- test/generator/event-handler-removal/_config.js | 2 +- test/generator/event-handler/_config.js | 6 +++--- test/generator/if-block-widget/_config.js | 6 +++--- test/generator/if-block/_config.js | 6 +++--- 13 files changed, 27 insertions(+), 27 deletions(-) diff --git a/test/generator/attribute-dynamic-multiple/_config.js b/test/generator/attribute-dynamic-multiple/_config.js index 83c6a58a86..1a0c602cb6 100644 --- a/test/generator/attribute-dynamic-multiple/_config.js +++ b/test/generator/attribute-dynamic-multiple/_config.js @@ -7,5 +7,5 @@ export default { ] }, - html: `
1
2
3
` + html: `
1
2
3
` }; diff --git a/test/generator/binding-input-text-contextual/_config.js b/test/generator/binding-input-text-contextual/_config.js index 3f2d3f3fc0..332d2c6f39 100644 --- a/test/generator/binding-input-text-contextual/_config.js +++ b/test/generator/binding-input-text-contextual/_config.js @@ -6,7 +6,7 @@ export default { 'three' ] }, - html: `

one

two

three

`, + html: `

one

two

three

`, test ( assert, component, target, window ) { const inputs = [ ...target.querySelectorAll( 'input' ) ]; const items = component.get( 'items' ); @@ -18,12 +18,12 @@ export default { inputs[1].dispatchEvent( event ); assert.equal( items[1], 'four' ); - assert.equal( target.innerHTML, `

one

four

three

` ); + assert.equal( target.innerHTML, `

one

four

three

` ); items[2] = 'five'; component.set({ items }); assert.equal( inputs[2].value, 'five' ); - assert.equal( target.innerHTML, `

one

four

five

` ); + assert.equal( target.innerHTML, `

one

four

five

` ); } }; diff --git a/test/generator/binding-input-text-deep-contextual/_config.js b/test/generator/binding-input-text-deep-contextual/_config.js index f24902a962..587110786c 100644 --- a/test/generator/binding-input-text-deep-contextual/_config.js +++ b/test/generator/binding-input-text-deep-contextual/_config.js @@ -6,7 +6,7 @@ export default { { description: 'three' } ] }, - html: `

one

two

three

`, + html: `

one

two

three

`, test ( assert, component, target, window ) { const inputs = [ ...target.querySelectorAll( 'input' ) ]; @@ -17,13 +17,13 @@ export default { inputs[1].value = 'four'; inputs[1].dispatchEvent( event ); - assert.equal( target.innerHTML, `

one

four

three

` ); + assert.equal( target.innerHTML, `

one

four

three

` ); const items = component.get( 'items' ); items[2].description = 'five'; component.set({ items }); assert.equal( inputs[2].value, 'five' ); - assert.equal( target.innerHTML, `

one

four

five

` ); + assert.equal( target.innerHTML, `

one

four

five

` ); } }; diff --git a/test/generator/component-yield-parent/_config.js b/test/generator/component-yield-parent/_config.js index 28b8e175de..cc3b39ca81 100644 --- a/test/generator/component-yield-parent/_config.js +++ b/test/generator/component-yield-parent/_config.js @@ -2,8 +2,8 @@ export default { html: '

Hello

', test ( assert, component, target ) { assert.equal( component.get( 'data' ), 'Hello' ); - component.set({data: 'World'}) + component.set({data: 'World'}); assert.equal( component.get( 'data' ), 'World' ); - assert.equal( target.innerHTML, '

World

' ); + assert.equal( target.innerHTML, '

World

' ); } -} +}; diff --git a/test/generator/each-block-indexed/_config.js b/test/generator/each-block-indexed/_config.js index 34640e18cb..5aaadafb05 100644 --- a/test/generator/each-block-indexed/_config.js +++ b/test/generator/each-block-indexed/_config.js @@ -2,5 +2,5 @@ export default { data: { animals: [ 'adder', 'blue whale', 'chameleon' ] }, - html: `

0: adder

1: blue whale

2: chameleon

` + html: `

0: adder

1: blue whale

2: chameleon

` }; diff --git a/test/generator/each-block/_config.js b/test/generator/each-block/_config.js index 959bf88c04..655556bedf 100644 --- a/test/generator/each-block/_config.js +++ b/test/generator/each-block/_config.js @@ -2,11 +2,11 @@ export default { data: { animals: [ 'alpaca', 'baboon', 'capybara' ] }, - html: '

alpaca

baboon

capybara

', + html: '

alpaca

baboon

capybara

', test ( assert, component, target ) { component.set({ animals: [ 'alpaca', 'baboon', 'caribou', 'dogfish' ] }); - assert.equal( target.innerHTML, '

alpaca

baboon

caribou

dogfish

' ); + assert.equal( target.innerHTML, '

alpaca

baboon

caribou

dogfish

' ); component.set({ animals: [] }); - assert.equal( target.innerHTML, '' ); + assert.equal( target.innerHTML, '' ); } }; diff --git a/test/generator/each-blocks-expression/_config.js b/test/generator/each-blocks-expression/_config.js index b610b055b4..239a18b6dc 100644 --- a/test/generator/each-blocks-expression/_config.js +++ b/test/generator/each-blocks-expression/_config.js @@ -1,3 +1,3 @@ export default { - html: `

a

b

c

` + html: `

a

b

c

` }; diff --git a/test/generator/each-blocks-nested-b/_config.js b/test/generator/each-blocks-nested-b/_config.js index 806284ef2d..1ba0f685b8 100644 --- a/test/generator/each-blocks-nested-b/_config.js +++ b/test/generator/each-blocks-nested-b/_config.js @@ -28,7 +28,7 @@ export default { } ] }, - html: `

animals: aardvark

animals: buffalo

animals: chinchilla

countries: albania

countries: brazil

countries: china

people: alice

people: bob

people: carol

people: dave

`, + html: `

animals: aardvark

animals: buffalo

animals: chinchilla

countries: albania

countries: brazil

countries: china

people: alice

people: bob

people: carol

people: dave

`, test ( assert, component, target ) { // TODO } diff --git a/test/generator/each-blocks-nested/_config.js b/test/generator/each-blocks-nested/_config.js index 0c21561e75..5486c8274e 100644 --- a/test/generator/each-blocks-nested/_config.js +++ b/test/generator/each-blocks-nested/_config.js @@ -4,7 +4,7 @@ export default { rows: [ 1, 2, 3 ] }, - html: `
a, 1
a, 2
a, 3
b, 1
b, 2
b, 3
c, 1
c, 2
c, 3
`, + html: `
a, 1
a, 2
a, 3
b, 1
b, 2
b, 3
c, 1
c, 2
c, 3
`, test ( assert, component, target ) { // TODO diff --git a/test/generator/event-handler-removal/_config.js b/test/generator/event-handler-removal/_config.js index 91bc0452a5..b196db1765 100644 --- a/test/generator/event-handler-removal/_config.js +++ b/test/generator/event-handler-removal/_config.js @@ -1,7 +1,7 @@ // TODO gah, JSDOM appears to behave differently to real browsers here... probably need to raise an issue export default { - html: '', + html: '', test ( assert, component ) { component.refs.input.focus(); diff --git a/test/generator/event-handler/_config.js b/test/generator/event-handler/_config.js index 5fb7f6bc86..8aa60ff387 100644 --- a/test/generator/event-handler/_config.js +++ b/test/generator/event-handler/_config.js @@ -1,13 +1,13 @@ export default { - html: '\n\n', + html: '\n\n', test ( assert, component, target, window ) { const button = target.querySelector( 'button' ); const event = new window.MouseEvent( 'click' ); button.dispatchEvent( event ); - assert.equal( target.innerHTML, '\n\n

hello!

' ); + assert.equal( target.innerHTML, '\n\n

hello!

' ); button.dispatchEvent( event ); - assert.equal( target.innerHTML, '\n\n' ); + assert.equal( target.innerHTML, '\n\n' ); } }; diff --git a/test/generator/if-block-widget/_config.js b/test/generator/if-block-widget/_config.js index 674fefb0ba..40d9d050e9 100644 --- a/test/generator/if-block-widget/_config.js +++ b/test/generator/if-block-widget/_config.js @@ -2,11 +2,11 @@ export default { data: { visible: true }, - html: 'before\n

Widget

\nafter', + html: 'before\n

Widget

\nafter', test ( assert, component, target ) { component.set({ visible: false }); - assert.equal( target.innerHTML, 'before\n\nafter' ); + assert.equal( target.innerHTML, 'before\n\nafter' ); component.set({ visible: true }); - assert.equal( target.innerHTML, 'before\n

Widget

\nafter' ); + assert.equal( target.innerHTML, 'before\n

Widget

\nafter' ); } }; diff --git a/test/generator/if-block/_config.js b/test/generator/if-block/_config.js index f8014c5c9a..4194fd29bc 100644 --- a/test/generator/if-block/_config.js +++ b/test/generator/if-block/_config.js @@ -2,11 +2,11 @@ export default { data: { visible: true }, - html: '

i am visible

', + html: '

i am visible

', test ( assert, component, target ) { component.set({ visible: false }); - assert.equal( target.innerHTML, '' ); + assert.equal( target.innerHTML, '' ); component.set({ visible: true }); - assert.equal( target.innerHTML, '

i am visible

' ); + assert.equal( target.innerHTML, '

i am visible

' ); } }; From fa705302616e511860401b98df76426e687be1c0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 24 Jan 2017 17:03:14 -0500 Subject: [PATCH 3/4] handle xlink attributes --- .../attributes/addElementAttributes.js | 51 +++++++++++-------- src/shared/dom.js | 4 ++ test/generator/svg-xlink/_config.js | 19 +++++++ test/generator/svg-xlink/main.html | 7 +++ test/helpers.js | 4 ++ 5 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 test/generator/svg-xlink/_config.js create mode 100644 test/generator/svg-xlink/main.html diff --git a/src/generators/dom/visitors/attributes/addElementAttributes.js b/src/generators/dom/visitors/attributes/addElementAttributes.js index 490d330348..c6009ff2e8 100644 --- a/src/generators/dom/visitors/attributes/addElementAttributes.js +++ b/src/generators/dom/visitors/attributes/addElementAttributes.js @@ -5,15 +5,24 @@ import flattenReference from '../../../../utils/flattenReference.js'; export default function addElementAttributes ( generator, node, local ) { node.attributes.forEach( attribute => { + const name = attribute.name; + if ( attribute.type === 'Attribute' ) { - let metadata = local.namespace ? null : attributeLookup[ attribute.name ]; + let metadata = local.namespace ? null : attributeLookup[ name ]; if ( metadata && metadata.appliesTo && !~metadata.appliesTo.indexOf( node.name ) ) metadata = null; let dynamic = false; - const isBoundOptionValue = node.name === 'option' && attribute.name === 'value'; // TODO check it's actually bound + const isBoundOptionValue = node.name === 'option' && name === 'value'; // TODO check it's actually bound const propertyName = isBoundOptionValue ? '__value' : metadata && metadata.propertyName; + const isXlink = name.slice( 0, 6 ) === 'xlink:'; + + // xlink is a special case... we could maybe extend this to generic + // namespaced attributes but I'm not sure that's applicable in + // HTML5? + const helper = isXlink ? 'setXlinkAttribute' : 'setAttribute'; + if ( attribute.value === true ) { // attributes without values, e.g.