|
|
@ -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' ) {
|
|
|
@ -40,17 +42,22 @@ export default function visitWindow ( generator, block, node ) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( attribute.type === 'Binding' ) {
|
|
|
|
if ( attribute.type === 'Binding' ) {
|
|
|
|
|
|
|
|
if ( attribute.value.type !== 'Identifier' ) {
|
|
|
|
|
|
|
|
const { parts, keypath } = flattenReference( attribute.value );
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// bind:online is a special case, we need to listen for two separate events
|
|
|
|
|
|
|
|
if ( attribute.name === 'online' ) return;
|
|
|
|
|
|
|
|
|
|
|
|
const associatedEvent = associatedEvents[ attribute.name ];
|
|
|
|
const associatedEvent = associatedEvents[ attribute.name ];
|
|
|
|
|
|
|
|
|
|
|
|
if ( !associatedEvent ) {
|
|
|
|
if ( !associatedEvent ) {
|
|
|
|
throw new Error( `Cannot bind to ${attribute.name} on <:Window>` );
|
|
|
|
throw new Error( `Cannot bind to ${attribute.name} on <:Window>` );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( attribute.value.type !== 'Identifier' ) {
|
|
|
|
|
|
|
|
const { parts, keypath } = flattenReference( attribute.value );
|
|
|
|
|
|
|
|
throw new Error( `Bindings on <:Window/> must be to top-level properties, e.g. '${parts.pop()}' rather than '${keypath}'` );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 +68,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' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handlerBody = new CodeBuilder();
|
|
|
|
|
|
|
|
if ( event === 'scroll' ) { // TODO other bidirectional bindings...
|
|
|
|
|
|
|
|
block.builders.create.addLine( `var ${lock} = false;` );
|
|
|
|
|
|
|
|
handlerBody.addLine( `${lock} = true;` );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handlerBody.addBlock( deindent`
|
|
|
|
|
|
|
|
${block.component}.set({
|
|
|
|
|
|
|
|
${props}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( event === 'scroll' ) {
|
|
|
|
|
|
|
|
handlerBody.addLine( `${lock} = false;` );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
block.builders.create.addBlock( deindent`
|
|
|
|
block.builders.create.addBlock( deindent`
|
|
|
|
var ${handlerName} = function ( event ) {
|
|
|
|
function ${handlerName} ( event ) {
|
|
|
|
${block.component}.set({
|
|
|
|
${handlerBody}
|
|
|
|
${props}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
window.addEventListener( '${event}', ${handlerName} );
|
|
|
|
window.addEventListener( '${event}', ${handlerName} );
|
|
|
|
` );
|
|
|
|
` );
|
|
|
@ -79,4 +101,52 @@ 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' } );
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// another special case. (I'm starting to think these are all special cases.)
|
|
|
|
|
|
|
|
if ( bindings.online ) {
|
|
|
|
|
|
|
|
const handlerName = block.getUniqueName( `onlinestatuschanged` );
|
|
|
|
|
|
|
|
block.builders.create.addBlock( deindent`
|
|
|
|
|
|
|
|
function ${handlerName} ( event ) {
|
|
|
|
|
|
|
|
component.set({ ${bindings.online}: navigator.onLine });
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener( 'online', ${handlerName} );
|
|
|
|
|
|
|
|
window.addEventListener( 'offline', ${handlerName} );
|
|
|
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// add initial value
|
|
|
|
|
|
|
|
generator.builders.metaBindings.addLine(
|
|
|
|
|
|
|
|
`this._state.${bindings.online} = navigator.onLine;`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.builders.destroy.addBlock( deindent`
|
|
|
|
|
|
|
|
window.removeEventListener( 'online', ${handlerName} );
|
|
|
|
|
|
|
|
window.removeEventListener( 'offline', ${handlerName} );
|
|
|
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|