Merge pull request #461 from sveltejs/gh-404-scroll

window scroll bindings are bidirectional
pull/471/head
Rich Harris 8 years ago committed by GitHub
commit 229d9f0a5f

@ -1,5 +1,6 @@
import flattenReference from '../../../../../utils/flattenReference.js'; import flattenReference from '../../../../../utils/flattenReference.js';
import deindent from '../../../../../utils/deindent.js'; import deindent from '../../../../../utils/deindent.js';
import CodeBuilder from '../../../../../utils/CodeBuilder.js';
const associatedEvents = { const associatedEvents = {
innerWidth: 'resize', innerWidth: 'resize',
@ -13,6 +14,7 @@ const associatedEvents = {
export default function visitWindow ( generator, block, node ) { export default function visitWindow ( generator, block, node ) {
const events = {}; const events = {};
const bindings = {};
node.attributes.forEach( attribute => { node.attributes.forEach( attribute => {
if ( attribute.type === 'EventHandler' ) { if ( attribute.type === 'EventHandler' ) {
@ -51,6 +53,8 @@ export default function visitWindow ( generator, block, node ) {
throw new Error( `Bindings on <:Window/> must be to top-level properties, e.g. '${parts.pop()}' rather than '${keypath}'` ); throw new Error( `Bindings on <:Window/> must be to top-level properties, e.g. '${parts.pop()}' rather than '${keypath}'` );
} }
bindings[ attribute.name ] = attribute.value.name;
if ( !events[ associatedEvent ] ) events[ associatedEvent ] = []; if ( !events[ associatedEvent ] ) events[ associatedEvent ] = [];
events[ associatedEvent ].push( `${attribute.value.name}: this.${attribute.name}` ); events[ associatedEvent ].push( `${attribute.value.name}: this.${attribute.name}` );
@ -61,16 +65,31 @@ export default function visitWindow ( generator, block, node ) {
} }
}); });
const lock = block.getUniqueName( `window_updating` );
Object.keys( events ).forEach( event => { Object.keys( events ).forEach( event => {
const handlerName = block.getUniqueName( `onwindow${event}` ); const handlerName = block.getUniqueName( `onwindow${event}` );
const props = events[ event ].join( ',\n' ); const props = events[ event ].join( ',\n' );
block.builders.create.addBlock( deindent` const handlerBody = new CodeBuilder();
var ${handlerName} = function ( event ) { if ( event === 'scroll' ) { // TODO other bidirectional bindings...
block.builders.create.addLine( `var ${lock} = false;` );
handlerBody.addLine( `${lock} = true;` );
}
handlerBody.addBlock( deindent`
component.set({ component.set({
${props} ${props}
}); });
` );
if ( event === 'scroll' ) {
handlerBody.addLine( `${lock} = false;` );
}
block.builders.create.addBlock( deindent`
var ${handlerName} = function ( event ) {
${handlerBody}
}; };
window.addEventListener( '${event}', ${handlerName} ); window.addEventListener( '${event}', ${handlerName} );
` ); ` );
@ -79,4 +98,30 @@ export default function visitWindow ( generator, block, node ) {
window.removeEventListener( '${event}', ${handlerName} ); window.removeEventListener( '${event}', ${handlerName} );
` ); ` );
}); });
// special case... might need to abstract this out if we add more special cases
if ( bindings.scrollX && bindings.scrollY ) {
const observerCallback = block.getUniqueName( `scrollobserver` );
block.builders.create.addBlock( deindent`
function ${observerCallback} () {
if ( ${lock} ) return;
var x = ${bindings.scrollX ? `component.get( '${bindings.scrollX}' )` : `window.scrollX`};
var y = ${bindings.scrollY ? `component.get( '${bindings.scrollY}' )` : `window.scrollY`};
window.scrollTo( x, y );
};
` );
if ( bindings.scrollX ) block.builders.create.addLine( `component.observe( '${bindings.scrollX}', ${observerCallback} );` );
if ( bindings.scrollY ) block.builders.create.addLine( `component.observe( '${bindings.scrollY}', ${observerCallback} );` );
} else if ( bindings.scrollX || bindings.scrollY ) {
const isX = !!bindings.scrollX;
block.builders.create.addBlock( deindent`
component.observe( '${bindings.scrollX || bindings.scrollY}', function ( ${isX ? 'x' : 'y'} ) {
if ( ${lock} ) return;
window.scrollTo( ${isX ? 'x, window.scrollY' : 'window.scrollX, y' } );
});
` );
}
} }

@ -0,0 +1,12 @@
export default {
skip: true, // JSDOM
test ( assert, component, target, window ) {
assert.equal( window.scrollY, 0 );
component.set({ scrollY: 100 });
assert.equal( window.scrollY, 100 );
component.destroy();
}
};

@ -0,0 +1,3 @@
<:Window bind:scrollY/>
<div style='width: 100%; height: 9999px;'></div>
Loading…
Cancel
Save