from this original code, add the UI logic to handle multiple selectors and modify the logic to handle the fetch and process such that only one fetch is done for multiple (if any) selector application.



Ul Logic for "Selectors/Regex" and "Use regex?" Columns:
1. Multiple Selectors/Regex Options:
• Selectors Container: Each row has a "Selectors/Regex" column, which includes a container (<div class="selector-container"> ) to hold multiple selector/regex inputs. These inputs allow users to specify different CSS selectors or regular expressions for scraping data from the web.
• Dynamic Field Addition: By default, one input field is available for entering a selector or regex. Users can add more selectors by clicking the "+" button next to the initial input. Each new selector input is dynamically added to the container using JavaScript.
2. Switch for Regex:
• Checkbox for Regex Option: Next to each selector input in the "Use regex?" column, there is a corresponding checkbox wrapped in a styled switch UI (<label class="regex-switch"> ). This checkbox determines whether the current selector input should be treated as a regular expression.
• Dynamic Regex Switches: Similar to the selectors, regex switches are dynamically added each time a new selector input field is created. They align with their respective selectors, allowing users to specify whether each selector is a regular expression or not.
3. Interactive Buttons:

• Add Selector Button: Each selector input has a "+" button. Clicking this button calls the addSelectorField() function, which inserts additional input fields and regex checkboxes into their respective containers, allowing users to specify multiple selectors/regex patterns within a single record entry.

• Remove Selector Button: When more than one selector exists, a "-" button becomes available. Clicking this button removes the specific selector and its corresponding regex checkbox, providing functionality to manage unnecessary entries efficiently.

4. Data Structure:

• Data Storage: When a new record is added, each selector along with its regex status is stored as an object in the selectors array. The structure is something like: { value: 'selector or pattern', isRegex:
true/false 3. These configurations are saved in local storage under the scrapeRecords key.
5. Execution Logic:

• Concurrent Execution: When the scraping process is executed, all selectors defined for a particular record are used. Each selector can either perform CSS selection on the document parsed from the target URL or match using a regex pattern, depending on the user's settings in the corresponding checkbox.

6. also make sure that if the last row - minus button was click, ensure the new last row of text field is update to have that + button to always allow user to add (the bug is that if the last row is removed, user can no longer added)

apply to the following code:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Scraping Tool</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #e0e0e0;
            display: flex;
            justify-content: center;
            align-items: flex-start;
            flex-direction: column;
            min-height: 100vh;
            width: 100%;
            box-sizing: border-box;
        }

        h1 {
            color: #333;
            text-align: center;
            width: 100%;
            margin: 20px 0;
        }

        .table-container {
            width: 100%;
            max-width: 1200px;
            margin: 0 auto;
            background-color: #e0e0e0;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            box-shadow: inset 1px 1px 2px #d1d1d1, inset -1px -1px 2px #ffffff;
            border-radius: 12px;
            overflow: hidden;
        }

        th,
        td {
            padding: 12px;
            text-align: left;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
        }

        th {
            background-color: #e0e0e0;
            box-shadow: inset 1px 1px 2px #d1d1d1, inset -1px -1px 2px #ffffff;
            color: #555;
        }

        td {
            background-color: #e0e0e0;
            color: #333;
        }

        input[type="text"] {
            width: calc(100% - 16px);
            padding: 8px;
            border: none;
            border-radius: 8px;
            box-shadow: inset 2px 2px 5px #bebebe, inset -2px -2px 5px #ffffff;
            background-color: #e0e0e0;
        }

        button {
            padding: 10px 15px;
            border: none;
            border-radius: 8px;
            background-color: #e0e0e0;
            box-shadow: 5px 5px 10px #bebebe, -5px -5px 10px #ffffff;
            cursor: pointer;
            font-size: 14px;
            margin-right: 5px;
        }

        button:hover {
            box-shadow: inset 2px 2px 5px #bebebe, inset -2px -2px 5px #ffffff;
        }

        .debug-panel,
        .result-panel {
            position: fixed;
            top: 8%;
            left: 50%;
            transform: translateX(-50%);
            width: 80%;
            max-height: 400px;
            overflow-y: auto;
            background-color: #e0e0e0;
            box-shadow: 8px 8px 20px #bebebe, -8px -8px 20px #ffffff;
            border-radius: 10px;
            padding: 20px;
            display: none;
            z-index: 1000;
        }

        .close-btn {
            float: right;
            cursor: pointer;
            font-weight: bold;
            color: #333;
        }

        .overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.3);
            display: none;
            z-index: 999;
        }

        .auto-fetch-switch-container,
        .regex-toggle-container {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
            width: 100%;
            max-width: 1200px;
            box-sizing: border-box;
        }

        .switch-label-container {
            display: flex;
            align-items: center;
        }

        .auto-fetch-switch-label,
        .regex-switch-label {
            margin-right: 10px;
            color: #333;
            font-weight: bold;
        }

        .auto-fetch-switch,
        .regex-switch {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 25px;
        }

        .auto-fetch-switch input,
        .regex-switch input {
            display: none;
        }

        .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 34px;
        }

        .slider:before {
            position: absolute;
            content: "";
            height: 20px;
            width: 20px;
            left: 3px;
            bottom: 2px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }

        input:checked+.slider {
            background-color: #2196F3;
        }

        input:checked+.slider:before {
            transform: translateX(24px);
        }

        .request-access-link {
            color: #2196F3;
            font-weight: bold;
            text-decoration: none;
        }

        .result-link {
            color: #2196F3;
            cursor: pointer;
            text-decoration: underline;
        }

        .import-export-container {
            position: fixed;
            top: 10px;
            right: 10px;
            display: flex;
            gap: 10px;
            z-index: 1001;
        }

        .hidden-input {
            display: none;
        }
    </style>
</head>

<body>
    <div class="import-export-container">
        <button onclick="exportData()">Export</button>
        <button onclick="document.getElementById('import-file').click()">Import</button>
        <button onclick="clearAllData()">Clear All</button>
        <input type="file" id="import-file" class="hidden-input" accept=".json" onchange="importData(event)">
    </div>

    <h1>Web Scraping Tool</h1>
    <div class="table-container">
        <div class="auto-fetch-switch-container">
            <div class="switch-label-container">
                <span class="auto-fetch-switch-label">Auto Fetch on Load</span>
                <label class="auto-fetch-switch">
                    <input type="checkbox" id="auto-fetch-switch" onchange="toggleAutoFetch(this.checked)">
                    <span class="slider"></span>
                </label>
            </div>
            <a href="https://cors-anywhere.herokuapp.com/corsdemo" class="request-access-link" target="_blank">Not working? Request access here</a>
        </div>
        <table>
            <thead>
                <tr>
                    <th>Name</th>
                    <th>URL</th>
                    <th>Selector/Regex</th>
                    <th>Use regex?</th>
                    <th>Results</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody id="scrape-table-body">
                <tr>
                    <td><input type="text" id="new-name" placeholder="Enter name"></td>
                    <td><input type="text" id="new-url" placeholder="Enter URL"></td>
                    <td><input type="text" id="new-selector" placeholder="Enter Selector or Regex"></td>
                    <td>
                        <label class="regex-switch">
                            <input type="checkbox" id="new-regex">
                            <span class="slider"></span>
                        </label>
                    </td>
                    <td colspan="2"><button onclick="addNewRecord()">✚</button></td>
                </tr>
            </tbody>
        </table>
    </div>

    <div id="overlay" class="overlay" onclick="closePanels()"></div>
    <div id="debug-panel" class="debug-panel">
        <span class="close-btn" onclick="toggleDebugPanel(null, true)">×</span>
        <pre id="debug-content"></pre>
    </div>
    <div id="result-panel" class="result-panel">
        <span class="close-btn" onclick="toggleResultPanel(null, true)">×</span>
        <pre id="result-content"></pre>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        const recordsKey = 'scrapeRecords';
        const autoFetchKey = 'autoFetch';
        const maxResultLength = 50;

        document.addEventListener('DOMContentLoaded', () => {
            const autoFetchState = localStorage.getItem(autoFetchKey);
            const autoFetch = (autoFetchState === 'true');
            const autoFetchSwitch = document.getElementById('auto-fetch-switch');
            autoFetchSwitch.checked = autoFetch;
            loadRecords(autoFetch);
        });

        // Function to export data to JSON (only user input data)
        function exportData() {
            const records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            const userEntries = records.map(({ name, url, selector, isRegex }) => ({ name, url, selector, isRegex }));
            const blob = new Blob([JSON.stringify(userEntries, null, 2)], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'scrape_records.json';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
        }

        // Function to import data from JSON
        function importData(event) {
            const file = event.target.files[0];
            if (!file) return;

            const reader = new FileReader();
            reader.onload = function(evt) {
                const data = JSON.parse(evt.target.result);
                localStorage.setItem(recordsKey, JSON.stringify(data));
                document.location.reload();
            };
            reader.readAsText(file);
        }

        // Function to clear all records
        function clearAllData() {
            localStorage.removeItem(recordsKey);
            document.location.reload();
        }

        function toggleAutoFetch(isEnabled) {
            localStorage.setItem(autoFetchKey, isEnabled);
            if (isEnabled) {
                executeAllRecords();
            }
        }

        function loadRecords(autoFetch) {
            const records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            records.forEach((record, index) => {
                addTableRow(record, index);
                if (autoFetch) {
                    executeRecord(index);
                }
            });
        }

        function addTableRow({ name, url, selector, isRegex }, index) {
            const tableBody = document.getElementById('scrape-table-body');
            const row = document.createElement('tr');

            row.innerHTML = `
                <td><input type="text" value="${name}" onchange="updateRecord(${index}, 'name', this.value)" onkeydown="checkEnter(event, ${index})"></td>
                <td><input type="text" value="${url}" onchange="updateRecord(${index}, 'url', this.value)" onkeydown="checkEnter(event, ${index})"></td>
                <td><input type="text" value="${escapeHtml(selector)}" onchange="updateRecord(${index}, 'selector', this.value)" onkeydown="checkEnter(event, ${index})"></td>
                <td>
                    <label class="regex-switch">
                        <input type="checkbox" id="regex-${index}" onchange="updateRecord(${index}, 'isRegex', this.checked)" ${isRegex ? 'checked' : ''}>
                        <span class="slider"></span>
                    </label>
                </td>
                <td id="result-${index}"></td>
                <td>
                    <button onclick="executeRecord(${index})">▶️</button>
                    <button onclick="removeRecord(${index})">🗑️</button>
                    <button onclick="toggleDebugPanel(${index}, false)">ℹ️</button>
                </td>
            `;
            tableBody.insertBefore(row, tableBody.lastElementChild);
        }

        function checkEnter(event, index) {
            if (event.key === 'Enter') {
                executeRecord(index);
            }
        }

        function addNewRecord() {
            const name = document.getElementById('new-name').value;
            const url = document.getElementById('new-url').value;
            const selector = document.getElementById('new-selector').value;
            const isRegex = document.getElementById('new-regex').checked;

            if (!name || !url || !selector) {
                alert('All fields are required!');
                return;
            }

            const record = { name, url, selector, isRegex };
            let records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            records.push(record);
            localStorage.setItem(recordsKey, JSON.stringify(records));

            const index = records.length - 1;
            addTableRow(record, index);
            executeRecord(index);

            document.getElementById('new-name').value = '';
            document.getElementById('new-url').value = '';
            document.getElementById('new-selector').value = '';
            document.getElementById('new-regex').checked = false;
        }

        function executeRecord(index) {
            const records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            const { url, selector, isRegex } = records[index];
            document.getElementById(`result-${index}`).textContent = '⏳';
            executeScraping(url, selector, isRegex, index);
        }

        function executeScraping(url, selector, isRegex, index) {
            const proxy = 'https://cors-anywhere.herokuapp.com/';
            const options = {
                headers: {
                    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
                    'Accept-Language': 'en-US,en;q=0.9'
                }
            };

            axios.get(proxy + url, options)
                .then(response => {
                    let resultText = 'No matches';
                    if (isRegex) {
                        try {
                            const regex = new RegExp(selector);
                            const match = regex.exec(response.data);
                            resultText = match ? match[0] : 'No matches';
                        } catch (e) {
                            console.error('Invalid regex:', e);
                            resultText = 'Invalid regex';
                        }
                    } else {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.data, 'text/html');
                        const resultElement = doc.querySelector(selector);
                        resultText = resultElement ? resultElement.textContent.trim() : 'No matches';
                    }

                    document.getElementById(`result-${index}`).textContent = resultText.substring(0, maxResultLength) + (resultText.length > maxResultLength ? '...' : '');
                })
                .catch(error => {
                    console.error(`Error fetching the URL: ${url}`, error);
                    document.getElementById(`result-${index}`).textContent = 'Error occurred';
                });
        }

        function updateRecord(index, field, value) {
            const records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            records[index][field] = value;
            localStorage.setItem(recordsKey, JSON.stringify(records));
        }

        function removeRecord(index) {
            let records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            records.splice(index, 1);
            localStorage.setItem(recordsKey, JSON.stringify(records));
            document.location.reload();
        }

        function toggleDebugPanel(index, close = false) {
            const debugPanel = document.getElementById('debug-panel');
            const debugContent = document.getElementById('debug-content');
            const overlay = document.getElementById('overlay');

            if (close || index === null) {
                debugPanel.style.display = 'none';
                overlay.style.display = 'none';
                debugContent.innerHTML = '';
                return;
            }

            const debugText = `No additional debug information available.`;
            debugPanel.style.display = 'block';
            overlay.style.display = 'block';
            debugContent.textContent = debugText;
        }

        function toggleResultPanel(index, close = false) {
            const resultPanel = document.getElementById('result-panel');
            const resultContent = document.getElementById('result-content');
            const overlay = document.getElementById('overlay');

            if (close || index === null) {
                resultPanel.style.display = 'none';
                overlay.style.display = 'none';
                resultContent.innerHTML = '';
                return;
            }

            const resultText = 'No Result Data';
            resultPanel.style.display = 'block';
            overlay.style.display = 'block';
            resultContent.textContent = resultText;
        }

        function closePanels() {
            toggleDebugPanel(null, true);
            toggleResultPanel(null, true);
        }

        function escapeHtml(text) {
            const map = {
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#039;'
            };
            return text.replace(/[&<>"']/g, function (m) { return map[m]; });
        }

        function executeAllRecords() {
            const records = JSON.parse(localStorage.getItem(recordsKey)) || [];
            records.forEach((_, index) => {
                executeRecord(index);
            });
        }
    </script>
</body>

</html>