feat: Get multipage sites working with link modifications
This commit is contained in:
28
example_sites/ipfs.freeconcept/index.html
Normal file
28
example_sites/ipfs.freeconcept/index.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>IPFS.freeconcept</title>
|
||||||
|
<link rel="icon" href="https://woodburn.au/favicon.png" type="image/png">
|
||||||
|
|
||||||
|
<!-- OpenGraph meta tags -->
|
||||||
|
<meta property="og:title" content="IPFS.freeconcept">
|
||||||
|
<meta property="og:description" content="Example multipage website stored on IPFS">
|
||||||
|
<meta property="og:image" content="https://ipfs.woodburn.au/og.png">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body style="background-color: black; color: blueviolet;text-align: center;">
|
||||||
|
<h1>IPFS.freeconcept</h1>
|
||||||
|
<p>This is a demo website with multiple pages running on IPFS.</p>
|
||||||
|
<p>It is designed to showcase the capabilities of IPFS and Handshake domains.</p>
|
||||||
|
<p>Have a look at this other page <a href="test.html" style="color: white;">test.html</a></p>
|
||||||
|
|
||||||
|
<img src="https://ipfs.woodburn.au/og.png" alt="Fire Portal" style="max-width: 100%; max-height: 750px;">
|
||||||
|
|
||||||
|
<div style="position: absolute; bottom: 25px; left: 0; width: 100%; text-align: center;">
|
||||||
|
<a href="https://nathan.woodburn.au" style="color: white;" target="_blank">© Nathan.Woodburn/</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
28
example_sites/ipfs.freeconcept/test.html
Normal file
28
example_sites/ipfs.freeconcept/test.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>IPFS.freeconcept</title>
|
||||||
|
<link rel="icon" href="https://woodburn.au/favicon.png" type="image/png">
|
||||||
|
|
||||||
|
<!-- OpenGraph meta tags -->
|
||||||
|
<meta property="og:title" content="IPFS.freeconcept">
|
||||||
|
<meta property="og:description" content="Example multipage website stored on IPFS">
|
||||||
|
<meta property="og:image" content="https://ipfs.woodburn.au/og.png">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body style="background-color: black; color: blueviolet;text-align: center;">
|
||||||
|
<h1>IPFS.freeconcept</h1>
|
||||||
|
<p>This is a demo subpage running on IPFS.</p>
|
||||||
|
<p>It is designed to showcase the capabilities of IPFS and Handshake domains.</p>
|
||||||
|
<p>This demonstrates how a folder can be used to store multipage websites</p>
|
||||||
|
|
||||||
|
<img src="https://ipfs.woodburn.au/og.png" alt="Fire Portal" style="max-width: 100%; max-height: 750px;">
|
||||||
|
|
||||||
|
<div style="position: absolute; bottom: 25px; left: 0; width: 100%; text-align: center;">
|
||||||
|
<a href="https://nathan.woodburn.au" style="color: white;" target="_blank">© Nathan.Woodburn/</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -123,6 +123,7 @@
|
|||||||
<p>Examples:</p>
|
<p>Examples:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#" class="example-link" data-domain="ipfs.act/">ipfs.act/</a> - Example Page created by <b>Nathan.Woodburn/</b></li>
|
<li><a href="#" class="example-link" data-domain="ipfs.act/">ipfs.act/</a> - Example Page created by <b>Nathan.Woodburn/</b></li>
|
||||||
|
<li><a href="#" class="example-link" data-domain="ipfs.freeconcept/">ipfs.freeconcept/</a> - Example Multipage website created by <b>Nathan.Woodburn/</b></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
77
server.js
77
server.js
@@ -53,6 +53,51 @@ function injectTrackingScript(content, mimeType) {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to make links absolute in HTML content
|
||||||
|
function makeLinksAbsolute(content, mimeType, domain, subPath = '') {
|
||||||
|
if (!mimeType || !mimeType.includes('text/html')) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
let htmlContent = content.toString();
|
||||||
|
const baseUrl = `/${domain}`;
|
||||||
|
|
||||||
|
// Create base directory for proper path resolution
|
||||||
|
let basePath = '/';
|
||||||
|
if (subPath) {
|
||||||
|
// Remove file part if present
|
||||||
|
const pathParts = subPath.split('/');
|
||||||
|
if (pathParts.length > 1 && !subPath.endsWith('/')) {
|
||||||
|
pathParts.pop();
|
||||||
|
}
|
||||||
|
basePath = `/${pathParts.join('/')}/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to resolve paths
|
||||||
|
const resolvePath = (href) => {
|
||||||
|
if (href.startsWith('/')) {
|
||||||
|
// Absolute path within the site - make it absolute to our gateway
|
||||||
|
return `${baseUrl}${href}`;
|
||||||
|
} else if (!href.match(/^(https?:|mailto:|tel:|#|javascript:|data:)/)) {
|
||||||
|
// Relative path - resolve it against current directory
|
||||||
|
return `${baseUrl}${basePath}${href}`;
|
||||||
|
}
|
||||||
|
return href; // Already absolute or special protocol
|
||||||
|
};
|
||||||
|
|
||||||
|
// Replace href attributes (like <a href="...">)
|
||||||
|
htmlContent = htmlContent.replace(/href=["'](.*?)["']/g, (match, href) => {
|
||||||
|
return `href="${resolvePath(href)}"`;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace src attributes (like <img src="...">)
|
||||||
|
htmlContent = htmlContent.replace(/src=["'](.*?)["']/g, (match, src) => {
|
||||||
|
return `src="${resolvePath(src)}"`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return htmlContent;
|
||||||
|
}
|
||||||
|
|
||||||
// Status endpoint
|
// Status endpoint
|
||||||
app.get('/api/status', (req, res) => {
|
app.get('/api/status', (req, res) => {
|
||||||
res.json({ status: 'online', version: '1.0.0' });
|
res.json({ status: 'online', version: '1.0.0' });
|
||||||
@@ -98,8 +143,12 @@ app.get('/:domain', async (req, res, next) => {
|
|||||||
res.setHeader('Content-Type', content.mimeType);
|
res.setHeader('Content-Type', content.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject tracking script if content is HTML
|
// Process HTML content: make links absolute and inject tracking script
|
||||||
const processedContent = injectTrackingScript(content.data, content.mimeType);
|
let processedContent = content.data;
|
||||||
|
if (content.mimeType && content.mimeType.includes('text/html')) {
|
||||||
|
processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, '');
|
||||||
|
processedContent = injectTrackingScript(processedContent, content.mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the content
|
// Return the content
|
||||||
res.send(processedContent);
|
res.send(processedContent);
|
||||||
@@ -155,8 +204,12 @@ app.get('/:domain/*', async (req, res, next) => {
|
|||||||
res.setHeader('Content-Type', content.mimeType);
|
res.setHeader('Content-Type', content.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject tracking script if content is HTML
|
// Process HTML content: make links absolute and inject tracking script
|
||||||
const processedContent = injectTrackingScript(content.data, content.mimeType);
|
let processedContent = content.data;
|
||||||
|
if (content.mimeType && content.mimeType.includes('text/html')) {
|
||||||
|
processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, subPath);
|
||||||
|
processedContent = injectTrackingScript(processedContent, content.mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the content
|
// Return the content
|
||||||
res.send(processedContent);
|
res.send(processedContent);
|
||||||
@@ -206,8 +259,12 @@ app.get('/hns/:domain/*', async (req, res) => {
|
|||||||
res.setHeader('Content-Type', content.mimeType);
|
res.setHeader('Content-Type', content.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject tracking script if content is HTML
|
// Process HTML content: make links absolute and inject tracking script
|
||||||
const processedContent = injectTrackingScript(content.data, content.mimeType);
|
let processedContent = content.data;
|
||||||
|
if (content.mimeType && content.mimeType.includes('text/html')) {
|
||||||
|
processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, subPath);
|
||||||
|
processedContent = injectTrackingScript(processedContent, content.mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the content
|
// Return the content
|
||||||
res.send(processedContent);
|
res.send(processedContent);
|
||||||
@@ -255,8 +312,12 @@ app.get('/hns/:domain', async (req, res) => {
|
|||||||
res.setHeader('Content-Type', content.mimeType);
|
res.setHeader('Content-Type', content.mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject tracking script if content is HTML
|
// Process HTML content: make links absolute and inject tracking script
|
||||||
const processedContent = injectTrackingScript(content.data, content.mimeType);
|
let processedContent = content.data;
|
||||||
|
if (content.mimeType && content.mimeType.includes('text/html')) {
|
||||||
|
processedContent = makeLinksAbsolute(processedContent, content.mimeType, domain, '');
|
||||||
|
processedContent = injectTrackingScript(processedContent, content.mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the content
|
// Return the content
|
||||||
res.send(processedContent);
|
res.send(processedContent);
|
||||||
|
|||||||
Reference in New Issue
Block a user