From e66257a6f66bf905d82c8df6e4e4d1a1509e0810 Mon Sep 17 00:00:00 2001 From: navewindre Date: Wed, 11 Feb 2026 06:12:26 +0100 Subject: click callback for auto navigation, rendering fixes --- web/renderer/index.js | 30 ++++++++++++++++++++++++++---- web/src/blog.tsx | 4 ++-- web/src/jsx.tsx | 32 ++++++++++++++++++++++++++++++++ web/src/pkg.tsx | 4 ++-- web/src/sidebar.tsx | 6 +++--- 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/web/renderer/index.js b/web/renderer/index.js index 497d245..2829275 100644 --- a/web/renderer/index.js +++ b/web/renderer/index.js @@ -46,13 +46,13 @@ let cache = async ( req, res ) => { console.log( "caching page: " + target ); fs.writeFileSync( file, html ); - await page.close(); const headers = r.headers(); + await page.close(); res.writeHead( 200, { - 'content-type': headers['content-type'], - 'date': headers['date'], - 'etag': headers['etag'], + 'content-type': headers['content-type'] || "text/html", + 'date': headers['date'] || "", + 'etag': headers['etag'] || "", } ); res.end( html ); @@ -62,12 +62,34 @@ let cache = async ( req, res ) => { } } +let allowedExt = [ + ".html", + ".xml", + ".css", + ".ico", + ".js", + "/" +]; + app.get( "/", cache ); app.get( /\/$/, cache ); app.get( /#$/, cache ); app.get( /^\/[^.]*$/, cache ); app.use( async ( req, res ) => { let url = new URL( req.url, host ); + let found = 0; + for( let ext of allowedExt ) { + if( url.pathname.endsWith( ext ) ) { + found = 1; + break; + } + } + + if( !found ) { + res.status( 403 ); + return res.end( "forbidden" ); + } + const r = await fetch( url.href ); if( r.ok ) { diff --git a/web/src/blog.tsx b/web/src/blog.tsx index 1fcfec2..738dd7c 100644 --- a/web/src/blog.tsx +++ b/web/src/blog.tsx @@ -53,11 +53,11 @@ function BlogEntry( props: any ) { ../ } { entry.name != "../" && !entry.isdir && - JSX.navigate( urlForHref( entry.name, entry.isdir ) ) } class="package-entry-link"> + {entry.name.replace( /_/g, " " )} } { entry.name != "../" && entry.isdir && - JSX.navigate( urlForHref( entry.name, entry.isdir ) ) } class="package-entry-link"> + {entry.name} } diff --git a/web/src/jsx.tsx b/web/src/jsx.tsx index 749e93f..1243398 100644 --- a/web/src/jsx.tsx +++ b/web/src/jsx.tsx @@ -78,6 +78,7 @@ export function onPostNavigate( callback: Function ) { onpostnavigate = callback; } + /** * replaces the root element with the route component **/ @@ -126,6 +127,17 @@ export function navigateParams( route: string, params: any ) { onpostnavigate(); } +/** + * convenience function to pass to href elements + **/ +export function href( e: Event ) { + const el = $( e.target ); + if( el.is( 'a' ) ) { + e.preventDefault(); + navigate( el.attr( 'href' ) ); + } +} + /** * wrapper for history.pushState **/ @@ -302,3 +314,23 @@ export function createFragment( props: any ) { function setTitle() { document.title = defaultTitle; } + +document.addEventListener( "click", e => { + let a = ( e.target ) as HTMLAnchorElement; + if( !a ) + return; + if( a.origin !== location.origin ) + return; + + e.preventDefault(); + if( !a.onclick ) { + if( routeForPath( a.pathname ) ) + return navigate( a.pathname ); + + const hasExt = /\.[a-zA-Z0-9]{1,8}$/.test( a.href ); + if( hasExt ) + location.href = a.href; + else + navigate( err404page ); + } +} ); diff --git a/web/src/pkg.tsx b/web/src/pkg.tsx index b1f38c9..95ea242 100644 --- a/web/src/pkg.tsx +++ b/web/src/pkg.tsx @@ -32,11 +32,11 @@ function PackageEntry( props: any ) { ../ } { entry.name != "../" && !entry.isdir && - + {entry.name} } { entry.name != "../" && entry.isdir && - JSX.navigate( urlForHref( entry.name, entry.isdir ) ) } class="package-entry-link"> + {entry.name} } diff --git a/web/src/sidebar.tsx b/web/src/sidebar.tsx index 6ada6f9..9fa6b71 100644 --- a/web/src/sidebar.tsx +++ b/web/src/sidebar.tsx @@ -89,21 +89,21 @@ export function Sidebar() {