Skip to content

Instantly share code, notes, and snippets.

@simonw
Created October 14, 2024 17:43
Show Gist options
  • Save simonw/e56d55e6a87a547faac7070eb912b32d to your computer and use it in GitHub Desktop.
Save simonw/e56d55e6a87a547faac7070eb912b32d to your computer and use it in GitHub Desktop.

Jina Reader Webpage Enhancements

human (Oct 14, 2024, 10:33 AM)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jina Reader</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
    <style>
        body {
            font-family: Helvetica, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            box-sizing: border-box;
        }
        h1 {
            font-size: 24px;
            margin-bottom: 20px;
        }
        #url-input, #submit-btn, #markdown-raw, #copy-btn {
            font-size: 16px;
            padding: 10px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }
        #url-input {
            width: 70%;
        }
        #submit-btn, #copy-btn {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        #submit-btn:hover, #copy-btn:hover {
            background-color: #45a049;
        }
        #markdown-raw {
            width: 100%;
            height: 200px;
            margin-top: 20px;
            resize: vertical;
        }
        #markdown-rendered {
            margin-top: 20px;
            border: 1px solid #ccc;
            padding: 10px;
            overflow-wrap: break-word;
        }
        @media (min-width: 768px) {
            #url-input {
                width: 70%;
                display: inline-block;
            }
            #submit-btn {
                display: inline-block;
                margin-left: 2%;
            }
            #copy-btn {
                width: auto;
            }
        }
    </style>
</head>
<body>
    <h1>Jina Reader</h1>
    <p>An interface for the <a href="https://jina.ai/reader/">Jina Reader API</a>.</p>
    <input type="text" id="url-input" placeholder="Enter URL">
    <button id="submit-btn">Submit</button>
    <textarea id="markdown-raw" readonly></textarea>
    <button id="copy-btn">Copy to clipboard</button>
    <div id="markdown-rendered"></div>

    <script>
        const urlInput = document.getElementById('url-input');
        const submitBtn = document.getElementById('submit-btn');
        const markdownRaw = document.getElementById('markdown-raw');
        const copyBtn = document.getElementById('copy-btn');
        const markdownRendered = document.getElementById('markdown-rendered');

        submitBtn.addEventListener('click', async () => {
            const url = urlInput.value;
            if (!url) return;

            try {
                const response = await fetch(`https://r.jina.ai/${url}`);
                const markdown = await response.text();
                markdownRaw.value = markdown;
                markdownRendered.innerHTML = marked.parse(markdown);
            } catch (error) {
                console.error('Error fetching markdown:', error);
                markdownRaw.value = 'Error fetching markdown. Please try again.';
                markdownRendered.innerHTML = '';
            }
        });

        copyBtn.addEventListener('click', () => {
            markdownRaw.select();
            document.execCommand('copy');
            
            const originalText = copyBtn.textContent;
            copyBtn.textContent = 'Copied';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
            }, 1500);
        });
    </script>
</body>
</html>

Modify this:

  • the textarea and html preview should not be shown until the API call finishes
  • the input should be in a form with a submit event to hitting enter activates it
  • a "Loading..." indicator should show while the API is running
  • the HTML preview should be shown in an iframe with a sandbox attribute
  • that iframe should start with a snippet of CSS to set max width on images to 100%

assistant (Oct 14, 2024, 10:33 AM)

Certainly. I'll modify the HTML and JavaScript to implement these changes. Here's the updated version:

Modified Jina Reader Webpage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jina Reader</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
    <style>
        body {
            font-family: Helvetica, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            box-sizing: border-box;
        }
        h1 {
            font-size: 24px;
            margin-bottom: 20px;
        }
        #url-input, #submit-btn, #markdown-raw, #copy-btn {
            font-size: 16px;
            padding: 10px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }
        #url-input {
            width: 70%;
        }
        #submit-btn, #copy-btn {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        #submit-btn:hover, #copy-btn:hover {
            background-color: #45a049;
        }
        #markdown-raw {
            width: 100%;
            height: 200px;
            margin-top: 20px;
            resize: vertical;
        }
        #markdown-rendered {
            margin-top: 20px;
            border: 1px solid #ccc;
            padding: 10px;
            overflow-wrap: break-word;
        }
        #loading {
            display: none;
            margin-top: 20px;
        }
        #result {
            display: none;
        }
        iframe {
            width: 100%;
            height: 500px;
            border: 1px solid #ccc;
        }
        @media (min-width: 768px) {
            #url-input {
                width: 70%;
                display: inline-block;
            }
            #submit-btn {
                display: inline-block;
                margin-left: 2%;
            }
            #copy-btn {
                width: auto;
            }
        }
    </style>
</head>
<body>
    <h1>Jina Reader</h1>
    <p>An interface for the <a href="https://jina.ai/reader/">Jina Reader API</a>.</p>
    <form id="url-form">
        <input type="text" id="url-input" placeholder="Enter URL" required>
        <button type="submit" id="submit-btn">Submit</button>
    </form>
    <div id="loading">Loading...</div>
    <div id="result">
        <textarea id="markdown-raw" readonly></textarea>
        <button id="copy-btn">Copy to clipboard</button>
        <iframe id="markdown-rendered" sandbox="allow-scripts"></iframe>
    </div>

    <script>
        const urlForm = document.getElementById('url-form');
        const urlInput = document.getElementById('url-input');
        const loading = document.getElementById('loading');
        const result = document.getElementById('result');
        const markdownRaw = document.getElementById('markdown-raw');
        const copyBtn = document.getElementById('copy-btn');
        const markdownRendered = document.getElementById('markdown-rendered');

        urlForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            const url = urlInput.value;
            if (!url) return;

            loading.style.display = 'block';
            result.style.display = 'none';

            try {
                const response = await fetch(`https://r.jina.ai/${url}`);
                const markdown = await response.text();
                markdownRaw.value = markdown;
                
                const htmlContent = `
                    <html>
                        <head>
                            <style>
                                body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
                                img { max-width: 100%; height: auto; }
                            </style>
                        </head>
                        <body>
                            ${marked.parse(markdown)}
                        </body>
                    </html>
                `;
                
                markdownRendered.srcdoc = htmlContent;
                result.style.display = 'block';
            } catch (error) {
                console.error('Error fetching markdown:', error);
                markdownRaw.value = 'Error fetching markdown. Please try again.';
                markdownRendered.srcdoc = '<p>Error fetching markdown. Please try again.</p>';
                result.style.display = 'block';
            } finally {
                loading.style.display = 'none';
            }
        });

        copyBtn.addEventListener('click', () => {
            markdownRaw.select();
            document.execCommand('copy');
            
            const originalText = copyBtn.textContent;
            copyBtn.textContent = 'Copied';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
            }, 1500);
        });
    </script>
</body>
</html>

I've made the following modifications to the Jina Reader webpage:

  1. The textarea and HTML preview are now hidden until the API call finishes. They're wrapped in a <div id="result"> which is initially hidden and shown only after the API call completes.

  2. The input is now in a form with a submit event. This allows the user to press Enter to submit the URL.

  3. A "Loading..." indicator is added and shown while the API is running.

  4. The HTML preview is now shown in an iframe with a sandbox attribute. This improves security by restricting the capabilities of the rendered content.

  5. The iframe starts with a snippet of CSS that sets the max-width of images to 100%. This ensures that images don't overflow the iframe.

These changes improve the user experience and security of the Jina Reader interface. The loading indicator provides feedback during API calls, and the iframe sandbox helps prevent potential security issues from rendered content.

Let me know if you want any further modifications or explanations about the changes!

human (Oct 14, 2024, 10:35 AM)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jina Reader</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
    <style>
        body {
            font-family: Helvetica, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            box-sizing: border-box;
        }
        h1 {
            font-size: 24px;
            margin-bottom: 20px;
        }
        #url-input, #submit-btn, #markdown-raw, #copy-btn {
            font-size: 16px;
            padding: 10px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }
        #url-input {
            width: 70%;
        }
        #submit-btn, #copy-btn {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        #submit-btn:hover, #copy-btn:hover {
            background-color: #45a049;
        }
        #markdown-raw {
            width: 100%;
            height: 200px;
            margin-top: 20px;
            resize: vertical;
        }
        #markdown-rendered {
            margin-top: 20px;
            border: 1px solid #ccc;
            padding: 10px;
            overflow-wrap: break-word;
        }
        @media (min-width: 768px) {
            #url-input {
                width: 70%;
                display: inline-block;
            }
            #submit-btn {
                display: inline-block;
                margin-left: 2%;
            }
            #copy-btn {
                width: auto;
            }
        }
    </style>
</head>
<body>
    <h1>Jina Reader</h1>
    <p>An interface for the <a href="https://jina.ai/reader/">Jina Reader API</a>.</p>
    <input type="text" id="url-input" placeholder="Enter URL">
    <button id="submit-btn">Submit</button>
    <textarea id="markdown-raw" readonly></textarea>
    <button id="copy-btn">Copy to clipboard</button>
    <div id="markdown-rendered"></div>

    <script>
        const urlInput = document.getElementById('url-input');
        const submitBtn = document.getElementById('submit-btn');
        const markdownRaw = document.getElementById('markdown-raw');
        const copyBtn = document.getElementById('copy-btn');
        const markdownRendered = document.getElementById('markdown-rendered');

        submitBtn.addEventListener('click', async () => {
            const url = urlInput.value;
            if (!url) return;

            try {
                const response = await fetch(`https://r.jina.ai/${url}`);
                const markdown = await response.text();
                markdownRaw.value = markdown;
                markdownRendered.innerHTML = marked.parse(markdown);
            } catch (error) {
                console.error('Error fetching markdown:', error);
                markdownRaw.value = 'Error fetching markdown. Please try again.';
                markdownRendered.innerHTML = '';
            }
        });

        copyBtn.addEventListener('click', () => {
            markdownRaw.select();
            document.execCommand('copy');
            
            const originalText = copyBtn.textContent;
            copyBtn.textContent = 'Copied';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
            }, 1500);
        });
    </script>
</body>
</html>

Modify this:

  • the textarea and html preview should not be shown until the API call finishes
  • the input should be in a form with a submit event to hitting enter activates it
  • a "Loading..." indicator should show while the API is running
  • the HTML preview should be shown in an iframe with a sandbox attribute
  • that iframe should start with a snippet of CSS to set max width on images to 100%

assistant (Oct 14, 2024, 10:35 AM)

I understand. I'll modify the HTML and JavaScript to implement these changes. Here's the updated version:

Modified Jina Reader Webpage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jina Reader</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
    <style>
        body {
            font-family: Helvetica, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            box-sizing: border-box;
        }
        h1 {
            font-size: 24px;
            margin-bottom: 20px;
        }
        #url-input, #submit-btn, #markdown-raw, #copy-btn {
            font-size: 16px;
            padding: 10px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }
        #url-input {
            width: 70%;
        }
        #submit-btn, #copy-btn {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        #submit-btn:hover, #copy-btn:hover {
            background-color: #45a049;
        }
        #markdown-raw {
            width: 100%;
            height: 200px;
            margin-top: 20px;
            resize: vertical;
        }
        #markdown-rendered {
            margin-top: 20px;
            border: 1px solid #ccc;
            padding: 10px;
            overflow-wrap: break-word;
        }
        #loading {
            display: none;
            margin-top: 20px;
        }
        #result {
            display: none;
        }
        iframe {
            width: 100%;
            height: 500px;
            border: 1px solid #ccc;
        }
        @media (min-width: 768px) {
            #url-input {
                width: 70%;
                display: inline-block;
            }
            #submit-btn {
                display: inline-block;
                margin-left: 2%;
            }
            #copy-btn {
                width: auto;
            }
        }
    </style>
</head>
<body>
    <h1>Jina Reader</h1>
    <p>An interface for the <a href="https://jina.ai/reader/">Jina Reader API</a>.</p>
    <form id="url-form">
        <input type="text" id="url-input" placeholder="Enter URL" required>
        <button type="submit" id="submit-btn">Submit</button>
    </form>
    <div id="loading">Loading...</div>
    <div id="result">
        <textarea id="markdown-raw" readonly></textarea>
        <button id="copy-btn">Copy to clipboard</button>
        <iframe id="markdown-rendered" sandbox="allow-scripts"></iframe>
    </div>

    <script>
        const urlForm = document.getElementById('url-form');
        const urlInput = document.getElementById('url-input');
        const loading = document.getElementById('loading');
        const result = document.getElementById('result');
        const markdownRaw = document.getElementById('markdown-raw');
        const copyBtn = document.getElementById('copy-btn');
        const markdownRendered = document.getElementById('markdown-rendered');

        urlForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            const url = urlInput.value;
            if (!url) return;

            loading.style.display = 'block';
            result.style.display = 'none';

            try {
                const response = await fetch(`https://r.jina.ai/${url}`);
                const markdown = await response.text();
                markdownRaw.value = markdown;
                
                const htmlContent = `
                    <html>
                        <head>
                            <style>
                                body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
                                img { max-width: 100%; height: auto; }
                            </style>
                        </head>
                        <body>
                            ${marked.parse(markdown)}
                        </body>
                    </html>
                `;
                
                markdownRendered.srcdoc = htmlContent;
                result.style.display = 'block';
            } catch (error) {
                console.error('Error fetching markdown:', error);
                markdownRaw.value = 'Error fetching markdown. Please try again.';
                markdownRendered.srcdoc = '<p>Error fetching markdown. Please try again.</p>';
                result.style.display = 'block';
            } finally {
                loading.style.display = 'none';
            }
        });

        copyBtn.addEventListener('click', () => {
            markdownRaw.select();
            document.execCommand('copy');
            
            const originalText = copyBtn.textContent;
            copyBtn.textContent = 'Copied';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
            }, 1500);
        });
    </script>
</body>
</html>

Here are the key modifications I've made to the Jina Reader webpage:

  1. The textarea and HTML preview are now wrapped in a <div id="result"> which is initially hidden and only shown after the API call completes.

  2. The input is now in a form (<form id="url-form">) with a submit event. This allows the user to press Enter to submit the URL.

  3. A "Loading..." indicator (<div id="loading">) is added and shown while the API is running.

  4. The HTML preview is now shown in an iframe with a sandbox attribute. This improves security by restricting the capabilities of the rendered content.

  5. The iframe starts with a snippet of CSS that sets the max-width of images to 100%. This ensures that images don't overflow the iframe.

  6. The JavaScript has been updated to handle the form submission, show/hide the loading indicator and results, and populate the iframe with the rendered markdown.

These changes improve the user experience and security of the Jina Reader interface. The loading indicator provides feedback during API calls, and the iframe sandbox helps prevent potential security issues from rendered content.

Let me know if you want any further modifications or explanations about the changes!

human (Oct 14, 2024, 10:39 AM)

Don't allow scripts, use helvetica not Ariel

assistant (Oct 14, 2024, 10:39 AM)

I apologize for the oversight. I'll modify the code to remove script permissions from the iframe and change the font to Helvetica. Here's the updated version:

Modified Jina Reader Webpage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jina Reader</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
    <style>
        body {
            font-family: Helvetica, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            box-sizing: border-box;
        }
        h1 {
            font-size: 24px;
            margin-bottom: 20px;
        }
        #url-input, #submit-btn, #markdown-raw, #copy-btn {
            font-size: 16px;
            padding: 10px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }
        #url-input {
            width: 70%;
        }
        #submit-btn, #copy-btn {
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        #submit-btn:hover, #copy-btn:hover {
            background-color: #45a049;
        }
        #markdown-raw {
            width: 100%;
            height: 200px;
            margin-top: 20px;
            resize: vertical;
        }
        #markdown-rendered {
            margin-top: 20px;
            border: 1px solid #ccc;
            padding: 10px;
            overflow-wrap: break-word;
        }
        #loading {
            display: none;
            margin-top: 20px;
        }
        #result {
            display: none;
        }
        iframe {
            width: 100%;
            height: 500px;
            border: 1px solid #ccc;
        }
        @media (min-width: 768px) {
            #url-input {
                width: 70%;
                display: inline-block;
            }
            #submit-btn {
                display: inline-block;
                margin-left: 2%;
            }
            #copy-btn {
                width: auto;
            }
        }
    </style>
</head>
<body>
    <h1>Jina Reader</h1>
    <p>An interface for the <a href="https://jina.ai/reader/">Jina Reader API</a>.</p>
    <form id="url-form">
        <input type="text" id="url-input" placeholder="Enter URL" required>
        <button type="submit" id="submit-btn">Submit</button>
    </form>
    <div id="loading">Loading...</div>
    <div id="result">
        <textarea id="markdown-raw" readonly></textarea>
        <button id="copy-btn">Copy to clipboard</button>
        <iframe id="markdown-rendered" sandbox="allow-same-origin"></iframe>
    </div>

    <script>
        const urlForm = document.getElementById('url-form');
        const urlInput = document.getElementById('url-input');
        const loading = document.getElementById('loading');
        const result = document.getElementById('result');
        const markdownRaw = document.getElementById('markdown-raw');
        const copyBtn = document.getElementById('copy-btn');
        const markdownRendered = document.getElementById('markdown-rendered');

        urlForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            const url = urlInput.value;
            if (!url) return;

            loading.style.display = 'block';
            result.style.display = 'none';

            try {
                const response = await fetch(`https://r.jina.ai/${url}`);
                const markdown = await response.text();
                markdownRaw.value = markdown;
                
                const htmlContent = `
                    <html>
                        <head>
                            <style>
                                body { font-family: Helvetica, sans-serif; line-height: 1.6; color: #333; }
                                img { max-width: 100%; height: auto; }
                            </style>
                        </head>
                        <body>
                            ${marked.parse(markdown)}
                        </body>
                    </html>
                `;
                
                markdownRendered.srcdoc = htmlContent;
                result.style.display = 'block';
            } catch (error) {
                console.error('Error fetching markdown:', error);
                markdownRaw.value = 'Error fetching markdown. Please try again.';
                markdownRendered.srcdoc = '<p>Error fetching markdown. Please try again.</p>';
                result.style.display = 'block';
            } finally {
                loading.style.display = 'none';
            }
        });

        copyBtn.addEventListener('click', () => {
            markdownRaw.select();
            document.execCommand('copy');
            
            const originalText = copyBtn.textContent;
            copyBtn.textContent = 'Copied';
            
            setTimeout(() => {
                copyBtn.textContent = originalText;
            }, 1500);
        });
    </script>
</body>
</html>

Here are the key changes I've made:

  1. Changed the iframe sandbox attribute: From: sandbox="allow-scripts" To: sandbox="allow-same-origin"

    This removes the permission for scripts to run inside the iframe, enhancing security. The allow-same-origin value is necessary to allow the iframe to access its own content.

  2. Updated the font in the iframe's CSS: From: body { font-family: Arial, sans-serif; ... } To: body { font-family: Helvetica, sans-serif; ... }

    This changes the font to Helvetica, matching the main page's font.

These modifications address your concerns about script execution and font consistency. The iframe will now render the content without running any scripts, and the font will be Helvetica throughout the application.

Let me know if you need any further adjustments or have any questions about these changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment