human (Nov 14, 2024, 05:53 PM)
Build me an HTML page that adds an iframe with sandbox=allow-scripts on it and then injects code into that iframe that implements a page with a simple API explorer tool - it provides a URL bar and a Submit button and a big pre tag that gets populated with pretty-printed JSON after the API URL is submitted
Here's the catch: because it is in an iframe sandbox it cannot make HTTP calls itself. Instead, it should use postMessage to its parent window with a JSON blob describing the HTTP call it needs to make - the method and the URL - and the parent page should catch that message, make the API call using fetch() and then send the resulting JSON back to the child frame
assistant (Nov 14, 2024, 05:53 PM)
I'll help you build this API explorer tool with a sandboxed iframe setup. This is a good candidate for creating an HTML artifact.
<!DOCTYPE html>
<html>
<head>
<title>API Explorer</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
background: #f0f0f0;
}
iframe {
width: 100%;
height: 600px;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
}
</style>
</head>
<body>
<iframe id="explorerFrame" sandbox="allow-scripts"></iframe>
<script>
// Create the HTML content for the iframe
const iframeContent = `
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.input-group {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
input[type="text"] {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
button {
padding: 8px 16px;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #0052a3;
}
pre {
background: #f5f5f5;
padding: 20px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.error {
color: #cc0000;
}
</style>
</head>
<body>
<div class="container">
<h1>API Explorer</h1>
<div class="input-group">
<input type="text" id="urlInput" placeholder="Enter API URL" value="https://api.example.com/data">
<button onclick="makeRequest()">Submit</button>
</div>
<pre id="output">// Response will appear here</pre>
</div>
<script>
function makeRequest() {
const url = document.getElementById('urlInput').value;
const output = document.getElementById('output');
// Send message to parent window
window.parent.postMessage({
type: 'api-request',
url: url,
method: 'GET'
}, '*');
output.textContent = 'Loading...';
}
// Listen for response from parent
window.addEventListener('message', function(event) {
const output = document.getElementById('output');
if (event.data.type === 'api-response') {
if (event.data.error) {
output.textContent = 'Error: ' + event.data.error;
output.classList.add('error');
} else {
output.textContent = JSON.stringify(event.data.response, null, 2);
output.classList.remove('error');
}
}
});
</script>
</body>
</html>
`;
// Set up the iframe with the content
const iframe = document.getElementById('explorerFrame');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframeContent);
// Listen for messages from the iframe
window.addEventListener('message', async function(event) {
if (event.data.type === 'api-request') {
try {
const response = await fetch(event.data.url, {
method: event.data.method
});
const data = await response.json();
// Send response back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
response: data
}, '*');
} catch (error) {
// Send error back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
error: error.message
}, '*');
}
}
});
</script>
</body>
</html>
I've created an HTML page that implements the API explorer tool with the following features:
- A parent page containing a sandboxed iframe with
allow-scripts
- The iframe contains:
- A URL input field
- A Submit button
- A pre-formatted output area for displaying JSON responses
- Clean, modern styling
- Communication flow:
- When the Submit button is clicked, the iframe sends a postMessage to the parent with the URL and method
- The parent catches this message, makes the actual fetch() call
- The parent sends the response back to the iframe using postMessage
- The iframe displays the pretty-printed JSON response
The solution includes error handling and a nice user interface. To use it:
- Enter an API URL in the input field
- Click Submit
- The response will appear in the formatted output area below
If there's an error (like an invalid URL or failed request), it will be displayed in red.
Would you like me to explain any part of the implementation in more detail or make any adjustments to the functionality?
human (Nov 14, 2024, 05:56 PM)
I edited it to be like this.Now add a second bit of clever postMessage JavaScript so the child window can tell the parent window what size the iframe should be when it resizes
paste.txt
<!DOCTYPE html>
<html>
<head>
<title>API Explorer</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
background: #f0f0f0;
}
iframe {
width: 100%;
height: 600px;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
}
</style>
</head>
<body>
<iframe id="explorerFrame" sandbox="allow-scripts"></iframe>
<script>
// Create the HTML content for the iframe
const iframeContent = `
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.input-group {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
input[type="text"] {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
button {
padding: 8px 16px;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #0052a3;
}
pre {
background: #f5f5f5;
padding: 20px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.error {
color: #cc0000;
}
</style>
</head>
<body>
<div class="container">
<h1>API Explorer</h1>
<div class="input-group">
<input type="text" id="urlInput" placeholder="Enter API URL" value="https://api.example.com/data">
<button onclick="makeRequest()">Submit</button>
</div>
<pre id="output">// Response will appear here</pre>
</div>
<script>
function makeRequest() {
const url = document.getElementById('urlInput').value;
const output = document.getElementById('output');
// Send message to parent window
window.parent.postMessage({
type: 'api-request',
url: url,
method: 'GET'
}, '*');
output.textContent = 'Loading...';
}
// Listen for response from parent
window.addEventListener('message', function(event) {
const output = document.getElementById('output');
if (event.data.type === 'api-response') {
if (event.data.error) {
output.textContent = 'Error: ' + event.data.error;
output.classList.add('error');
} else {
output.textContent = JSON.stringify(event.data.response, null, 2);
output.classList.remove('error');
}
}
});
SCUB
</body>
</html>
`.replace('SCUB', '</' + 'script>');
// Set up the iframe with the content
const iframe = document.getElementById('explorerFrame');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframeContent);
// Listen for messages from the iframe
window.addEventListener('message', async function(event) {
if (event.data.type === 'api-request') {
try {
const response = await fetch(event.data.url, {
method: event.data.method
});
const data = await response.json();
// Send response back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
response: data
}, '*');
} catch (error) {
// Send error back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
error: error.message
}, '*');
}
}
});
</script>
</body>
</html>
assistant (Nov 14, 2024, 05:56 PM)
I'll modify the code to add dynamic iframe resizing through postMessage communication. The child frame will measure its content and notify the parent whenever the size changes.
<!DOCTYPE html>
<html>
<head>
<title>API Explorer</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
background: #f0f0f0;
}
iframe {
width: 100%;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
transition: height 0.2s ease;
}
</style>
</head>
<body>
<iframe id="explorerFrame" sandbox="allow-scripts"></iframe>
<script>
// Create the HTML content for the iframe
const iframeContent = `
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.input-group {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
input[type="text"] {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
button {
padding: 8px 16px;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #0052a3;
}
pre {
background: #f5f5f5;
padding: 20px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.error {
color: #cc0000;
}
</style>
</head>
<body>
<div class="container">
<h1>API Explorer</h1>
<div class="input-group">
<input type="text" id="urlInput" placeholder="Enter API URL" value="https://api.example.com/data">
<button onclick="makeRequest()">Submit</button>
</div>
<pre id="output">// Response will appear here</pre>
</div>
<script>
function updateParentHeight() {
const height = document.documentElement.scrollHeight;
window.parent.postMessage({
type: 'resize',
height: height
}, '*');
}
// Call initially and set up resize observer
updateParentHeight();
const resizeObserver = new ResizeObserver(() => {
updateParentHeight();
});
resizeObserver.observe(document.body);
function makeRequest() {
const url = document.getElementById('urlInput').value;
const output = document.getElementById('output');
// Send message to parent window
window.parent.postMessage({
type: 'api-request',
url: url,
method: 'GET'
}, '*');
output.textContent = 'Loading...';
}
// Listen for response from parent
window.addEventListener('message', function(event) {
const output = document.getElementById('output');
if (event.data.type === 'api-response') {
if (event.data.error) {
output.textContent = 'Error: ' + event.data.error;
output.classList.add('error');
} else {
output.textContent = JSON.stringify(event.data.response, null, 2);
output.classList.remove('error');
}
// Content has changed, update height
updateParentHeight();
}
});
SCUB
</body>
</html>
`.replace('SCUB', '</' + 'script>');
// Set up the iframe with the content
const iframe = document.getElementById('explorerFrame');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframeContent);
// Listen for messages from the iframe
window.addEventListener('message', async function(event) {
if (event.data.type === 'api-request') {
try {
const response = await fetch(event.data.url, {
method: event.data.method
});
const data = await response.json();
// Send response back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
response: data
}, '*');
} catch (error) {
// Send error back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
error: error.message
}, '*');
}
} else if (event.data.type === 'resize') {
// Update iframe height when child requests it
iframe.style.height = event.data.height + 'px';
}
});
</script>
</body>
</html>
I've made the following changes to implement dynamic iframe resizing:
-
In the parent window:
- Removed the fixed height from the iframe CSS
- Added a smooth transition for height changes
- Added handling for 'resize' type messages from the child
-
In the child window:
- Added a
updateParentHeight()
function that measures the document height and sends it to the parent - Added a ResizeObserver to detect content size changes
- Called
updateParentHeight()
on initial load and after API responses - The height is calculated using
document.documentElement.scrollHeight
- Added a
The iframe will now automatically adjust its height when:
- The page initially loads
- The content changes after an API response
- Any dynamic content causes the page to resize
The ResizeObserver ensures we catch all size changes, even ones we didn't explicitly trigger. The transition CSS property makes the height changes smooth rather than jarring.
human (Nov 14, 2024, 05:58 PM)
I'm seeing this warning
TypeError: URL constructor: null is not a valid URL.
assistant (Nov 14, 2024, 05:58 PM)
That warning is occurring because we're not validating the URL before making the fetch request. Let's add URL validation in both the child iframe (for immediate feedback) and the parent (as a safety check).
<!DOCTYPE html>
<html>
<head>
<title>API Explorer</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
background: #f0f0f0;
}
iframe {
width: 100%;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
transition: height 0.2s ease;
}
</style>
</head>
<body>
<iframe id="explorerFrame" sandbox="allow-scripts"></iframe>
<script>
// Create the HTML content for the iframe
const iframeContent = `
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.input-group {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
input[type="text"] {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
input[type="text"].error {
border-color: #cc0000;
}
button {
padding: 8px 16px;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #0052a3;
}
button:disabled {
background: #cccccc;
cursor: not-allowed;
}
pre {
background: #f5f5f5;
padding: 20px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.error {
color: #cc0000;
}
</style>
</head>
<body>
<div class="container">
<h1>API Explorer</h1>
<div class="input-group">
<input
type="text"
id="urlInput"
placeholder="Enter API URL"
value="https://api.example.com/data"
oninput="validateUrl(this.value)"
>
<button id="submitBtn" onclick="makeRequest()">Submit</button>
</div>
<pre id="output">// Response will appear here</pre>
</div>
<script>
// Initialize UI elements
const urlInput = document.getElementById('urlInput');
const submitBtn = document.getElementById('submitBtn');
const output = document.getElementById('output');
function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (_) {
return false;
}
}
function validateUrl(value) {
const valid = isValidUrl(value);
urlInput.classList.toggle('error', !valid);
submitBtn.disabled = !valid;
if (!valid && value !== '') {
output.textContent = 'Please enter a valid URL (must start with http:// or https://)';
output.classList.add('error');
} else {
output.textContent = '// Response will appear here';
output.classList.remove('error');
}
return valid;
}
function updateParentHeight() {
const height = document.documentElement.scrollHeight;
window.parent.postMessage({
type: 'resize',
height: height
}, '*');
}
// Call initially and set up resize observer
updateParentHeight();
const resizeObserver = new ResizeObserver(() => {
updateParentHeight();
});
resizeObserver.observe(document.body);
function makeRequest() {
const url = urlInput.value;
if (!validateUrl(url)) {
return;
}
// Send message to parent window
window.parent.postMessage({
type: 'api-request',
url: url,
method: 'GET'
}, '*');
output.textContent = 'Loading...';
output.classList.remove('error');
}
// Initial URL validation
validateUrl(urlInput.value);
// Listen for response from parent
window.addEventListener('message', function(event) {
if (event.data.type === 'api-response') {
if (event.data.error) {
output.textContent = 'Error: ' + event.data.error;
output.classList.add('error');
} else {
output.textContent = JSON.stringify(event.data.response, null, 2);
output.classList.remove('error');
}
// Content has changed, update height
updateParentHeight();
}
});
SCUB
</body>
</html>
`.replace('SCUB', '</' + 'script>');
// Set up the iframe with the content
const iframe = document.getElementById('explorerFrame');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframeContent);
// Listen for messages from the iframe
window.addEventListener('message', async function(event) {
if (event.data.type === 'api-request') {
try {
// Double-check URL validity in parent as well
const url = new URL(event.data.url);
const response = await fetch(url.href, {
method: event.data.method
});
const data = await response.json();
// Send response back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
response: data
}, '*');
} catch (error) {
// Send error back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
error: error.message
}, '*');
}
} else if (event.data.type === 'resize') {
// Update iframe height when child requests it
iframe.style.height = event.data.height + 'px';
}
});
</script>
</body>
</html>
I've made several improvements to handle URL validation:
-
Added a
validateUrl()
function in the child iframe that:- Uses the URL constructor to validate URLs
- Shows visual feedback when the URL is invalid
- Disables the submit button for invalid URLs
- Shows an error message explaining the URL must start with http:// or https://
-
Added real-time validation:
- Validates on input change
- Validates before making requests
- Shows red border on invalid URL input
- Disables submit button when URL is invalid
-
Added double-check validation in the parent window:
- Creates a new URL object before fetching
- Uses the normalized
url.href
for the fetch call - Properly catches and reports URL-related errors
-
Improved the UI:
- Added disabled state styling for the submit button
- Added error state styling for the input field
- Added helpful error messages
- Maintains all previous functionality for resizing and API calls
Now the URL validation happens in real-time and provides good visual feedback to the user, and you shouldn't see that TypeError anymore.
human (Nov 14, 2024, 05:59 PM)
the iframe should get shorter if a new response comes back that is shorter
assistant (Nov 14, 2024, 05:59 PM)
Yes, good catch! The iframe needs to shrink when new content is smaller. The ResizeObserver should handle this, but let's make absolutely sure by improving the height calculation.
Find this:
function updateParentHeight() {
const height = document.documentElement.scrollHeight;
window.parent.postMessage({
type: 'resize',
height: height
}, '*');
}
Replace with this:
function updateParentHeight() {
// Reset any minimum height that might prevent shrinking
document.body.style.minHeight = '0px';
// Get the actual content height
const height = Math.max(
document.body.scrollHeight,
document.body.offsetHeight,
document.documentElement.scrollHeight,
document.documentElement.offsetHeight
);
window.parent.postMessage({
type: 'resize',
height: height
}, '*');
}
I've improved the height calculation to:
- Reset any minimum height that might prevent shrinking
- Take the maximum of various height measurements to ensure we capture the true content height
- This will now properly shrink when new content is shorter than previous content
Let's also make sure the parent iframe handles the resize smoothly:
Find this:
transition: height 0.2s ease;
Replace with this:
transition: height 0.2s ease-out;
min-height: 200px; /* Ensure a minimum height */
I've made these additional improvements:
- Added a minimum height to the iframe so it never collapses completely
- Changed the transition timing function to ease-out for smoother shrinking
- The iframe will now smoothly animate to both larger and smaller sizes while never getting too small
These changes should ensure the iframe properly resizes both up and down based on its content, with smooth transitions in both directions.
human (Nov 14, 2024, 06:01 PM)
it's not resizing well - add a bunch of console.log statements
Set default URL to https://datasette.io/content/stats.json
Use a form and a submit button such that hitting enter submits it
assistant (Nov 14, 2024, 06:01 PM)
I'll add detailed logging and make those improvements to help debug the resizing issue.
<!DOCTYPE html>
<html>
<head>
<title>API Explorer</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
background: #f0f0f0;
}
iframe {
width: 100%;
border: 1px solid #ccc;
border-radius: 4px;
background: white;
transition: height 0.2s ease-out;
min-height: 200px;
}
</style>
</head>
<body>
<iframe id="explorerFrame" sandbox="allow-scripts"></iframe>
<script>
// Create the HTML content for the iframe
const iframeContent = `
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
form {
margin-bottom: 20px;
}
.input-group {
display: flex;
gap: 8px;
}
input[type="text"] {
flex: 1;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
input[type="text"].error {
border-color: #cc0000;
}
button {
padding: 8px 16px;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #0052a3;
}
button:disabled {
background: #cccccc;
cursor: not-allowed;
}
pre {
background: #f5f5f5;
padding: 20px;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
margin: 0;
}
.error {
color: #cc0000;
}
</style>
</head>
<body>
<div class="container">
<h1>API Explorer</h1>
<form id="apiForm" onsubmit="makeRequest(event)">
<div class="input-group">
<input
type="text"
id="urlInput"
placeholder="Enter API URL"
value="https://datasette.io/content/stats.json"
oninput="validateUrl(this.value)"
>
<button type="submit" id="submitBtn">Submit</button>
</div>
</form>
<pre id="output">// Response will appear here</pre>
</div>
<script>
// Initialize UI elements
const urlInput = document.getElementById('urlInput');
const submitBtn = document.getElementById('submitBtn');
const output = document.getElementById('output');
let lastHeight = 0;
function isValidUrl(string) {
try {
new URL(string);
return true;
} catch (_) {
return false;
}
}
function validateUrl(value) {
console.log('Validating URL:', value);
const valid = isValidUrl(value);
urlInput.classList.toggle('error', !valid);
submitBtn.disabled = !valid;
if (!valid && value !== '') {
output.textContent = 'Please enter a valid URL (must start with http:// or https://)';
output.classList.add('error');
} else {
output.textContent = '// Response will appear here';
output.classList.remove('error');
}
updateParentHeight();
return valid;
}
function updateParentHeight() {
// Reset any minimum height
document.body.style.minHeight = '0px';
// Get various height measurements
const bodyScroll = document.body.scrollHeight;
const bodyOffset = document.body.offsetHeight;
const htmlScroll = document.documentElement.scrollHeight;
const htmlOffset = document.documentElement.offsetHeight;
// Get the maximum height
const height = Math.max(bodyScroll, bodyOffset, htmlScroll, htmlOffset);
console.log('Height measurements:', {
bodyScroll,
bodyOffset,
htmlScroll,
htmlOffset,
finalHeight: height,
lastHeight
});
if (height !== lastHeight) {
console.log('Sending new height to parent:', height);
window.parent.postMessage({
type: 'resize',
height: height
}, '*');
lastHeight = height;
}
}
// Call initially and set up resize observer
updateParentHeight();
const resizeObserver = new ResizeObserver((entries) => {
console.log('ResizeObserver triggered:', entries[0].contentRect);
updateParentHeight();
});
resizeObserver.observe(document.body);
function makeRequest(event) {
if (event) {
event.preventDefault();
}
const url = urlInput.value;
console.log('Making request to:', url);
if (!validateUrl(url)) {
return;
}
// Send message to parent window
window.parent.postMessage({
type: 'api-request',
url: url,
method: 'GET'
}, '*');
output.textContent = 'Loading...';
output.classList.remove('error');
updateParentHeight();
}
// Initial URL validation
validateUrl(urlInput.value);
// Listen for response from parent
window.addEventListener('message', function(event) {
console.log('Received message from parent:', event.data);
if (event.data.type === 'api-response') {
if (event.data.error) {
output.textContent = 'Error: ' + event.data.error;
output.classList.add('error');
} else {
const formatted = JSON.stringify(event.data.response, null, 2);
console.log('Setting response, length:', formatted.length);
output.textContent = formatted;
output.classList.remove('error');
}
// Content has changed, update height
updateParentHeight();
}
});
SCUB
</body>
</html>
`.replace('SCUB', '</' + 'script>');
// Set up the iframe with the content
const iframe = document.getElementById('explorerFrame');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURIComponent(iframeContent);
// Listen for messages from the iframe
window.addEventListener('message', async function(event) {
console.log('Parent received message:', event.data);
if (event.data.type === 'api-request') {
try {
// Double-check URL validity in parent as well
const url = new URL(event.data.url);
console.log('Parent making fetch request to:', url.href);
const response = await fetch(url.href, {
method: event.data.method
});
const data = await response.json();
console.log('Parent received response, size:', JSON.stringify(data).length);
// Send response back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
response: data
}, '*');
} catch (error) {
console.error('Parent encountered error:', error);
// Send error back to iframe
iframe.contentWindow.postMessage({
type: 'api-response',
error: error.message
}, '*');
}
} else if (event.data.type === 'resize') {
console.log('Parent setting iframe height:', event.data.height);
iframe.style.height = event.data.height + 'px';
}
});
</script>
</body>
</html>
I've made several improvements:
-
Added extensive console.log statements throughout to track:
- Height calculations and changes
- Message passing between parent and child
- Response sizes
- ResizeObserver triggers
- URL validation
- Error states
-
Changed to a proper form with onsubmit handler so Enter key works
-
Changed default URL to https://datasette.io/content/stats.json
-
Added tracking of lastHeight to avoid unnecessary resize messages
-
Improved height calculation logging to show all measurements
-
Added margin: 0 to the pre element to avoid extra space
-
Added more detailed timing and size logging for responses
The console logs should help us identify why the resizing isn't working properly. When you run it now, you should see detailed logs about:
- Initial size calculations
- Size changes when content updates
- All height measurements being considered
- When resize messages are sent and received
This should help pinpoint where the resizing logic might be failing.