Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Petit prog pour esp32
#41
bonjour 

je voulais faire un peu pres la meme que ton html.
je donc récupérer le tiens pour faire quelques modif.
enregistrement de la config dans le localstorage.
ajustement du zoom par rapport taille ecran

https://drive.google.com/file/d/12HfRLeT...p=drivesdk

Code :
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard Multi-Interfaces</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: Arial, sans-serif;
            background: #222;
        }

        /* Styles pour le mode configuration */
        .config-mode {
            background-color: #f5f5f5 !important;
        }

        .config-container {
            display: none;
            max-width: 800px;
            margin: 50px auto;
            padding: 20px;
        }

        .config-mode .config-container {
            display: block;
        }

        .config-panel {
            background: white;
            padding: 30px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        h1 {
            color: #333;
            text-align: center;
            margin-bottom: 30px;
        }

        .ip-list {
            margin-bottom: 20px;
        }

        .ip-group {
            margin-bottom: 15px;
            padding: 15px;
            background-color: #f9f9f9;
            border-radius: 5px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .ip-number {
            font-weight: bold;
            color: #555;
            min-width: 30px;
        }

        input[type="text"] {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-size: 16px;
        }

        input[type="text"]:focus {
            outline: none;
            border-color: #4CAF50;
        }

        .remove-btn {
            background-color: #f44336;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }

        .remove-btn:hover {
            background-color: #d32f2f;
        }

        .add-btn {
            background-color: #2196F3;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 16px;
            margin-bottom: 20px;
            width: 100%;
        }

        .add-btn:hover {
            background-color: #1976D2;
        }

        .button-group {
            margin-top: 30px;
            display: flex;
            gap: 10px;
            justify-content: center;
        }

        button {
            padding: 12px 30px;
            border: none;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .save-btn {
            background-color: #4CAF50;
            color: white;
        }

        .save-btn:hover {
            background-color: #45a049;
        }

        .message {
            margin-top: 20px;
            padding: 10px;
            border-radius: 5px;
            text-align: center;
            display: none;
        }

        .success {
            background-color: #d4edda;
            color: #155724;
            border: 1px solid #c3e6cb;
        }

        .error {
            background-color: #f8d7da;
            color: #721c24;
            border: 1px solid #f5c6cb;
        }

        .layout-preview {
            margin-top: 20px;
            padding: 15px;
            background-color: #e3f2fd;
            border-radius: 5px;
            text-align: center;
            font-size: 14px;
            color: #1976D2;
        }

        .help-text {
            font-size: 12px;
            color: #666;
            margin-top: 15px;
            padding: 10px;
            background-color: #f0f0f0;
            border-radius: 5px;
            line-height: 1.6;
        }

        /* Styles pour le mode dashboard */
        .dashboard-container {
            display: none;
            height: 100vh;
            gap: 2px;
            background: #222;
        }

        .dashboard-mode .dashboard-container {
            display: grid;
        }

        .frame-container {
            position: relative;
            overflow: hidden;
            background: white;
        }

        .frame-wrapper {
            width: 100%;
            height: 100%;
            transform-origin: top left;
            transition: transform 0.3s ease;
        }

        iframe {
            width: 100%;
            height: 100%;
            border: none;
            background: white;
        }

        /* Icône de configuration fixe */
        .config-icon {
            position: fixed;
            top: 5px;
            left: 5px;
            z-index: 1000;
            color: rgba(255, 255, 255, 0.8);
            font-size: 5vw;
            cursor: pointer;
            transition: all 0.3s ease;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
            user-select: none;
            display: none;
        }

        .dashboard-mode .config-icon {
            display: block;
        }

        .config-icon:hover {
            color: #FF9800;
            transform: rotate(45deg) scale(1.1);
        }




        /* Fenêtre popup de configuration */
        .config-popup {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            z-index: 2000;
            overflow-y: auto;
        }

        .config-popup-content {
            background: white;
            margin: 50px auto;
            padding: 30px;
            border-radius: 10px;
            max-width: 800px;
            width: 90%;
            max-height: 80vh;
            overflow-y: auto;
            position: relative;
            animation: popupSlideIn 0.3s ease-out;
        }

@keyframes popupSlideIn {
            from {
                opacity: 0;
                transform: translateY(-50px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .close-popup {
            position: absolute;
            top: 15px;
            right: 20px;
            font-size: 30px;
            color: #999;
            cursor: pointer;
            transition: color 0.3s;
        }

        .close-popup:hover {
            color: #333;
        }

        /* Contrôles de zoom */
        .zoom-controls {
            position: absolute;
            top: 5px;
            right: 5px;
            background: rgba(0,0,0,0.8);
            padding: 5px;
            border-radius: 3px;
            z-index: 10;
            display: flex;
            gap: 5px;
        }

        .zoom-btn {
            width: 25px;
            height: 25px;
            border: none;
            background: #444;
            color: white;
            cursor: pointer;
            border-radius: 3px;
            font-size: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .zoom-btn:hover {
            background: #666;
        }

        .zoom-fit {
            background: #2196F3;
            width: auto;
            min-width: 25px;
            padding: 0 8px;
            font-size: 11px;
        }

        .zoom-fit:hover {
            background: #1976D2;
        }

        .zoom-value {
            color: white;
            font-family: Arial, sans-serif;
            font-size: 12px;
            min-width: 45px;
            text-align: center;
            display: flex;
            align-items: center;
        }

        /* Label optionnel */
        .frame-label {
            position: absolute;
            top: 5px;
            left: 5px;
            background: rgba(0,0,0,0.7);
            color: white;
            padding: 5px 10px;
            font-family: Arial, sans-serif;
            font-size: 12px;
            border-radius: 3px;
            z-index: 10;
            pointer-events: none;
            max-width: 70%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }


        /* Message d'accueil */
        .welcome-message {
            text-align: center;
            padding: 40px;
            background-color: #e3f2fd;
            border-radius: 10px;
            margin-bottom: 30px;
        }

        .welcome-message h2 {
            color: #1976D2;
            margin-bottom: 10px;
        }

        /* Message d'erreur iframe */
        .iframe-error {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: #f8d7da;
            color: #721c24;
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            max-width: 80%;
            z-index: 20;
            display: none;
        }

        .iframe-error h3 {
            margin: 0 0 10px 0;
            font-size: 16px;
        }

        .iframe-error p {
            margin: 5px 0;
            font-size: 14px;
        }

        .iframe-error code {
            background: rgba(0,0,0,0.1);
            padding: 2px 5px;
            border-radius: 3px;
            font-size: 12px;
        }


        /* Boutons d'action de configuration */
        .config-actions {
            display: flex;
            gap: 10px;
            margin-top: 20px;
            flex-wrap: wrap;
        }

        .clear-btn {
            background-color: #F44336;
        }

        .clear-btn:hover {
            background-color: #D32F2F;
        }
    </style>
</head>
<body class="config-mode">
    <!-- Icône de configuration fixe -->
    <div class="config-icon" onclick="openConfigPopup()" title="Configuration">
        ⚙️
    </div>

    <!-- Mode Configuration -->
    <div class="config-container">
        <div class="config-panel">
            <h1>Dashboard Multi-Interfaces</h1>

            <div id="welcomeMessage" class="welcome-message">
                <h2>Bienvenue !</h2>
                <p>
                    Configurez vos adresses ci-dessous pour commencer.
                </p>
            </div>

            <div id="ipList" class="ip-list"></div>

            <button class="add-btn" onclick="addIP()">+ Ajouter une interface</button>

            <div class="help-text">
                <strong>Formats acceptés :</strong><br>
                • IP : 192.168.1.100<br>
                • Domaine : example.com<br>
                • Sous-domaine : app.example.com<br>
                • URL complète : https://example.com/dashboard<br>
                • Port personnalisé : 192.168.1.100:8080 ou example.com:3000
            </div>

            <div id="layoutPreview" class="layout-preview"></div>

            <div class="button-group">
                <button class="save-btn" onclick="saveAndShowDashboard()">Sauvegarder et afficher</button>
            </div>

            <div class="config-actions">
                <button class="save-btn clear-btn" onclick="clearConfig()">?️ Effacer tout</button>
            </div>

            <div id="message" class="message"></div>
        </div>
    </div>

    <!-- Popup de configuration -->
    <div class="config-popup" id="configPopup">
        <div class="config-popup-content">
            <span class="close-popup" onclick="closeConfigPopup()">&times;</span>
            <h1>Configuration Dashboard</h1>

            <div id="popupIpList" class="ip-list"></div>

            <button class="add-btn" onclick="addIPPopup()">+ Ajouter une interface</button>

            <div class="help-text">
                <strong>Formats acceptés :</strong><br>
                • IP : 192.168.1.100<br>
                • Domaine : example.com<br>
                • Sous-domaine : app.example.com<br>
                • URL complète : https://example.com/dashboard<br>
                • Port personnalisé : 192.168.1.100:8080 ou example.com:3000
            </div>

            <div id="popupLayoutPreview" class="layout-preview"></div>

            <div class="button-group">
                <button class="save-btn" onclick="saveConfigFromPopup()">Sauvegarder et appliquer</button>
                <button class="save-btn" style="background-color: #666;" onclick="closeConfigPopup()">Annuler</button>
            </div>

            <div class="config-actions">
                <button class="save-btn clear-btn" onclick="clearConfig()">?️ Effacer tout</button>
            </div>

            <div id="popupMessage" class="message"></div>
        </div>
    </div>

    <!-- Mode Dashboard -->
    <div id="dashboardContainer" class="dashboard-container"></div>


    <script>
        // Configuration des adresses - Chargée depuis localStorage
        let addresses = [];
        let zoomLevels = {};
        let currentMode = 'config';
        let autoFitEnabled = true;
        let isPopupMode = false;

        // Clé de stockage localStorage
        const STORAGE_KEY = 'dashboard_config';

        // Initialisation
        window.onload = function() {
            loadConfig();

            if (addresses.length > 0 && addresses[0] !== '') {
                document.getElementById('welcomeMessage').style.display = 'none';
                // Aller directement au dashboard si configuré
                showDashboard();
            } else {
                renderIPList();
            }
        };

        // Charger la configuration depuis localStorage
        function loadConfig() {
            try {
                const savedConfig = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
                if (Array.isArray(savedConfig) && savedConfig.length > 0) {
                    addresses = savedConfig;
                } else {
                    addresses = [''];
                }
            } catch (e) {
                console.error('Erreur lors du chargement de la configuration:', e);
                addresses = [''];
            }
        }

        // Sauvegarder la configuration dans localStorage
        function saveConfig() {
            try {
                const cleanAddresses = addresses.filter(addr => addr.trim() !== '');
                localStorage.setItem(STORAGE_KEY, JSON.stringify(cleanAddresses));
                return true;
            } catch (e) {
                console.error('Erreur lors de la sauvegarde:', e);
                showMessage('Erreur lors de la sauvegarde de la configuration', 'error');
                return false;
            }
        }

        // Ouvrir la popup de configuration
        function openConfigPopup() {
            isPopupMode = true;
            addresses = [...addresses]; // Copie pour éviter les modifications directes
            renderIPListPopup();
            document.getElementById('configPopup').style.display = 'block';
            document.body.style.overflow = 'hidden'; // Désactiver le scroll du body
        }

        // Fermer la popup de configuration
        function closeConfigPopup() {
            isPopupMode = false;
            document.getElementById('configPopup').style.display = 'none';
            document.body.style.overflow = 'auto'; // Réactiver le scroll du body
            loadConfig(); // Recharger la config originale
        }

        // Afficher la liste des adresses (mode principal)
        function renderIPList() {
            const container = document.getElementById('ipList');
            renderIPListInContainer(container, false);
        }

        // Afficher la liste des adresses (popup)
        function renderIPListPopup() {
            const container = document.getElementById('popupIpList');
            renderIPListInContainer(container, true);
        }

        // Fonction générique pour rendre la liste d'IPs
        function renderIPListInContainer(container, isPopup) {
            container.innerHTML = '';

            addresses.forEach((address, index) => {
                const div = document.createElement('div');
                div.className = 'ip-group';
                div.innerHTML = `
                <span class="ip-number">${index + 1}.</span>
                <input type="text" id="${isPopup ? 'popup': ''}address${index}" value="${address}" placeholder="Ex: 192.168.1.100, example.com, https://app.example.com">
                ${addresses.length > 1 ? `<button class="remove-btn" onclick="${isPopup ? 'removeIPPopup': 'removeIP'}(${index})">Supprimer</button>`: ''}
                `;
                container.appendChild(div);
            });

            updateLayoutPreview(isPopup);
        }

        // Ajouter une adresse
        function addIP() {
            addresses.push('');
            renderIPList();
        }

        // Ajouter une adresse (popup)
        function addIPPopup() {
            addresses.push('');
            renderIPListPopup();
        }

        // Supprimer une adresse
        function removeIP(index) {
            addresses.splice(index, 1);
            renderIPList();
        }

        // Supprimer une adresse (popup)
        function removeIPPopup(index) {
            addresses.splice(index, 1);
            renderIPListPopup();
        }

        // Mettre à jour l'aperçu
        function updateLayoutPreview(isPopup = false) {
            const preview = document.getElementById(isPopup ? 'popupLayoutPreview': 'layoutPreview');
            const count = addresses.length;

            let layout = '';
            if (count === 1) {
                layout = 'Plein écran';
            } else if (count === 2) {
                layout = '2 colonnes côte à côte';
            } else if (count === 3) {
                layout = '1 grande vue à gauche + 2 petites à droite';
            } else if (count === 4) {
                layout = 'Grille 2x2';
            } else if (count <= 6) {
                layout = 'Grille 2x3';
            } else if (count <= 9) {
                layout = 'Grille 3x3';
            } else {
                layout = `Grille ${Math.ceil(Math.sqrt(count))}x${Math.ceil(count / Math.ceil(Math.sqrt(count)))}`;
            }

            preview.innerHTML = `<strong>Disposition :</strong> ${count} interface${count > 1 ? 's': ''} - ${layout}`;
        }

        // Sauvegarder la configuration depuis la popup
        function saveConfigFromPopup() {
            // Récupérer et valider les adresses depuis la popup
            const newAddresses = [];
            for (let i = 0; i < addresses.length; i++) {
                const addressValue = document.getElementById(`popupaddress${i}`).value.trim();
                if (addressValue) {
                    const validation = validateAndFormatAddress(addressValue);
                    if (!validation.valid) {
                        showMessage(`Adresse n°${i + 1} : ${validation.error}`, 'error', true);
                        return;
                    }
                    newAddresses.push(addressValue);
                }
            }

            if (newAddresses.length === 0) {
                showMessage('Ajoutez au moins une adresse valide', 'error', true);
                return;
            }

            addresses = newAddresses;

            if (saveConfig()) {
                showMessage('Configuration sauvegardée avec succès !', 'success', true);
                setTimeout(() => {
                    closeConfigPopup();
                    showDashboard();
                }, 1000);
            }
        }

        // Sauvegarder et afficher le dashboard (mode principal)
        function saveAndShowDashboard() {
            // Récupérer et valider les adresses
            const newAddresses = [];
            for (let i = 0; i < addresses.length; i++) {
                const addressInput = document.getElementById(`address${i}`);
                const addressValue = addressInput ? addressInput.value.trim(): addresses[i];

                if (addressValue) {
                    const validation = validateAndFormatAddress(addressValue);
                    if (!validation.valid) {
                        showMessage(`Adresse n°${i + 1} : ${validation.error}`, 'error');
                        return;
                    }
                    newAddresses.push(addressValue);
                }
            }

            if (newAddresses.length === 0) {
                showMessage('Ajoutez au moins une adresse valide', 'error');
                return;
            }

            addresses = newAddresses;

            if (saveConfig()) {
                showMessage('Configuration sauvegardée !', 'success');
                setTimeout(showDashboard, 500);
            }
        }

        // Effacer toute la configuration
        function clearConfig() {
            if (confirm('Êtes-vous sûr de vouloir effacer toute la configuration ?')) {
                localStorage.removeItem(STORAGE_KEY);
                addresses = [''];

                if (isPopupMode) {
                    renderIPListPopup();
                } else {
                    renderIPList();
                }

                showMessage('Configuration effacée', 'success', isPopupMode);
            }
        }

        // Valider et formater une adresse
        function validateAndFormatAddress(address) {
            address = address.trim();

            if (!address) {
                return {
                    valid: false,
                    error: "L'adresse ne peut pas être vide"
                };
            }

            if (address.match(/^https?:\/\//)) {
                return {
                    valid: true,
                    formatted: address,
                    display: address
                };
            }

            const ipPattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?::\d{1,5})?$/;
            if (ipPattern.test(address)) {
                return {
                    valid: true,
                    formatted: `http://${address}`,
                    display: address
                };
            }

            const domainPattern = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(:\d{1,5})?(\/.*)?$/;
            const localhostPattern = /^localhost(:\d{1,5})?(\/.*)?$/;

            if (domainPattern.test(address) || localhostPattern.test(address)) {
                return {
                    valid: true,
                    formatted: `http://${address}`,
                    display: address
                };
            }

            if (/^[a-zA-Z0-9-]+(:\d{1,5})?(\/.*)?$/.test(address)) {
                return {
                    valid: true,
                    formatted: `http://${address}`,
                    display: address
                };
            }

            return {
                valid: false,
                error: "Format d'adresse non valide"
            };
        }

        // Afficher un message
        function showMessage(text, type, inPopup = false) {
            const messageEl = document.getElementById(inPopup ? 'popupMessage': 'message');
            messageEl.textContent = text;
            messageEl.className = 'message ' + type;
            messageEl.style.display = 'block';

            setTimeout(() => {
                messageEl.style.display = 'none';
            }, 3000);
        }

        // Calculer la disposition
        function calculateGridLayout(count) {
            if (count === 1) return {
                cols: 1,
                rows: 1,
                special: 'single'
            };
            if (count === 2) return {
                cols: 2,
                rows: 1,
                special: 'two-columns'
            };
            if (count === 3) return {
                cols: 2,
                rows: 2,
                special: 'three-special'
            };
            if (count === 4) return {
                cols: 2,
                rows: 2,
                special: 'grid'
            };

            const cols = Math.ceil(Math.sqrt(count));
            const rows = Math.ceil(count / cols);
            return {
                cols,
                rows,
                special: 'grid'
            };
        }

        function calculateOptimalZoom(frameContainer) {
            const containerWidth = frameContainer.clientWidth;

            // Utiliser la largeur actuelle en tenant compte de l'orientation
            const referenceWidth = Math.max(window.innerWidth, window.innerHeight);

            const optimalZoom = containerWidth / referenceWidth;

            return Math.max(0.2, Math.min(2, optimalZoom));
        }



        // Appliquer le zoom automatique à une iframe
        function autoFitFrame(frameNum) {
            const frameContainer = document.querySelector(`#frame${frameNum}`).parentElement;
            const optimalZoom = calculateOptimalZoom(frameContainer);

            zoomLevels[frameNum] = optimalZoom;
            updateZoom(frameNum);
        }

        // Appliquer le zoom automatique à toutes les iframes
        function autoFitAll() {
            for (let i = 1; i <= addresses.length; i++) {
                autoFitFrame(i);
            }
        }

        // Afficher le dashboard
        function showDashboard() {
            // Valider les adresses
            const validatedAddresses = [];
            for (let i = 0; i < addresses.length; i++) {
                const validation = validateAndFormatAddress(addresses[i]);
                if (!validation.valid) {
                    showMessage(`Adresse n°${i + 1} : ${validation.error}`, 'error');
                    return;
                }
                validatedAddresses.push(validation);
            }

            // Construire le dashboard avec les adresses formatées
            buildDashboard(validatedAddresses);

            // Basculer en mode dashboard
            document.body.className = 'dashboard-mode';
            currentMode = 'dashboard';

            // Appliquer le zoom automatique après un délai
            setTimeout(() => {
                if (autoFitEnabled) {
                    for (let i = 1; i <= addresses.length; i++) {
                        autoFitFrame(i);
                    }
                }
            },
                500);
        }

        // Construire le dashboard
        function buildDashboard(validatedAddresses) {
            const container = document.getElementById('dashboardContainer');
            const layout = calculateGridLayout(validatedAddresses.length);

            // Appliquer les styles de grille
            if (layout.special === 'single') {
                container.style.gridTemplateColumns = '1fr';
                container.style.gridTemplateRows = '1fr';
            } else if (layout.special === 'two-columns') {
                container.style.gridTemplateColumns = '1fr 1fr';
                container.style.gridTemplateRows = '1fr';
            } else if (layout.special === 'three-special') {
                container.style.gridTemplateColumns = '1fr 1fr';
                container.style.gridTemplateRows = '1fr 1fr';
            } else {
                container.style.gridTemplateColumns = `repeat(${layout.cols}, 1fr)`;
                container.style.gridTemplateRows = `repeat(${layout.rows}, 1fr)`;
            }

            // Créer les conteneurs
            container.innerHTML = '';
            validatedAddresses.forEach((addressInfo, index) => {
                const frameDiv = document.createElement('div');
                frameDiv.className = 'frame-container';

                // Style spécial pour 3 interfaces
                if (layout.special === 'three-special' && index === 0) {
                    frameDiv.style.gridRow = 'span 2';
                }

                frameDiv.innerHTML = `
                <span class="frame-label" title="${addressInfo.display}">${addressInfo.display}</span>
                <div class="zoom-controls">
                <button class="zoom-btn" onclick="zoom(${index + 1}, -0.1)">−</button>
                <span class="zoom-value" id="zoom${index + 1}">100%</span>
                <button class="zoom-btn" onclick="zoom(${index + 1}, 0.1)">+</button>
                <button class="zoom-btn zoom-fit" onclick="autoFitFrame(${index + 1})" title="Ajuster à l'écran">FIT</button>
                </div>
                <div class="frame-wrapper" id="frame${index + 1}">
                <iframe
                src="${addressInfo.formatted}"
                sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-modals allow-downloads allow-presentation allow-top-navigation"
                referrerpolicy="no-referrer"
                id="iframe${index + 1}"
                onerror="handleIframeError(${index + 1}, '${addressInfo.display}')"
                ></iframe>
                </div>
                <div class="iframe-error" id="error${index + 1}">
                <h3>⚠️ Impossible de charger ${addressInfo.display}</h3>
                <p>Cette interface ne peut pas être affichée dans une iframe.</p>
                <p><small>Pour Home Assistant, ajoutez dans configuration.yaml :</small></p>
                <code>http:<br>&nbsp;&nbsp;use_x_frame_options: false</code>
                <p style="margin-top: 15px;">
                <a href="${addressInfo.formatted}" target="_blank" style="color: #0056b3;">Ouvrir dans un nouvel onglet →</a>
                </p>
                </div>
                `;

                container.appendChild(frameDiv);
            });

            // Initialiser les niveaux de zoom
            zoomLevels = {};
            for (let i = 1; i <= validatedAddresses.length; i++) {
                zoomLevels[i] = 1;
            }
        }

        // Retourner à la configuration
        function showConfig() {
            document.body.className = 'config-mode';
            currentMode = 'config';
            renderIPList();
        }

        // Fonctions de zoom
        function zoom(frameNum, delta) {
            zoomLevels[frameNum] = Math.max(0.2, Math.min(2, zoomLevels[frameNum] + delta));
            updateZoom(frameNum);
        }

        function updateZoom(frameNum) {
            const frame = document.getElementById(`frame${frameNum}`);
            const zoomDisplay = document.getElementById(`zoom${frameNum}`);
            const scale = zoomLevels[frameNum];

            frame.style.transform = `scale(${scale})`;
            frame.style.width = `${100 / scale}%`;
            frame.style.height = `${100 / scale}%`;
            zoomDisplay.textContent = `${Math.round(scale * 100)}%`;
        }

        // Gestion des erreurs d'iframe
        function handleIframeError(frameNum, address) {
            console.error(`Erreur de chargement pour l'iframe ${frameNum}: ${address}`);
            const errorDiv = document.getElementById(`error${frameNum}`);
            if (errorDiv) {
                errorDiv.style.display = 'block';
            }
        }

        // Détection des erreurs de chargement après un délai
        function checkIframeLoading() {
            if (currentMode === 'dashboard') {
                for (let i = 1; i <= addresses.length; i++) {
                    const iframe = document.getElementById(`iframe${i}`);
                    if (iframe) {
                        iframe.addEventListener('load', function() {
                            try {
                                // Tenter d'accéder au document pour vérifier si c'est bloqué
                                const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                                // Si on arrive ici, l'iframe est chargée correctement
                            } catch (e) {
                                // Erreur de cross-origin, probablement bloqué
                                console.warn(`L'iframe ${i} pourrait être bloquée par des politiques de sécurité`);
                            }
                        });
                    }
                }
            }
        }

        // Gestion du redimensionnement de la fenêtre
        window.addEventListener('resize', function() {
            if (currentMode === 'dashboard' && autoFitEnabled) {
                // Réappliquer le zoom automatique après redimensionnement
                setTimeout(() => {
                    for (let i = 1; i <= addresses.length; i++) {
                        autoFitFrame(i);
                    }
                },
                    100);
            }
        });

        // Fermer la popup avec Escape
        window.addEventListener('keydown', function(e) {
            if (e.key === 'Escape' && document.getElementById('configPopup').style.display === 'block') {
                closeConfigPopup();
            }
        });

        // Fermer la popup en cliquant en dehors
        document.getElementById('configPopup').addEventListener('click', function(e) {
            if (e.target === this) {
                closeConfigPopup();
            }
        });

        // Appeler la vérification après le chargement du dashboard
        setTimeout(checkIframeLoading, 1000);



    </script>
</body>
</html>
Répondre


Messages dans ce sujet
Petit prog pour esp32 - par lucky - 27-05-2025, 09:04 PM
RE: Petit prog pour esp32 - par Sgb31 - 28-05-2025, 07:51 AM
RE: Petit prog pour esp32 - par lucky - 28-05-2025, 08:03 AM
RE: Petit prog pour esp32 - par Sgb31 - 28-05-2025, 09:52 AM
RE: Petit prog pour esp32 - par Serge111 - 28-05-2025, 03:09 PM
RE: Petit prog pour esp32 - par grostoto - 28-05-2025, 07:57 PM
RE: Petit prog pour esp32 - par lucky - 28-05-2025, 08:07 PM
RE: Petit prog pour esp32 - par grostoto - 28-05-2025, 09:48 PM
RE: Petit prog pour esp32 - par lucky - 28-05-2025, 10:03 PM
RE: Petit prog pour esp32 - par grostoto - 28-05-2025, 10:07 PM
RE: Petit prog pour esp32 - par lucky - 29-05-2025, 08:21 AM
RE: Petit prog pour esp32 - par Philmaz - 29-05-2025, 05:32 PM
RE: Petit prog pour esp32 - par lucky - 29-05-2025, 06:03 PM
RE: Petit prog pour esp32 - par Philmaz - 29-05-2025, 07:45 PM
RE: Petit prog pour esp32 - par grostoto - 29-05-2025, 06:08 PM
RE: Petit prog pour esp32 - par lucky - 29-05-2025, 06:17 PM
RE: Petit prog pour esp32 - par grostoto - 29-05-2025, 07:49 PM
RE: Petit prog pour esp32 - par lucky - 29-05-2025, 08:14 PM
RE: Petit prog pour esp32 - par grostoto - 29-05-2025, 09:01 PM
RE: Petit prog pour esp32 - par lucky - 29-05-2025, 09:51 PM
RE: Petit prog pour esp32 - par Philmaz - 29-05-2025, 10:32 PM
RE: Petit prog pour esp32 - par grostoto - 29-05-2025, 11:21 PM
RE: Petit prog pour esp32 - par Philmaz - 30-05-2025, 07:26 AM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 07:41 AM
RE: Petit prog pour esp32 - par grostoto - 30-05-2025, 08:02 AM
RE: Petit prog pour esp32 - par Philmaz - 30-05-2025, 08:19 AM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 08:26 AM
RE: Petit prog pour esp32 - par Philmaz - 30-05-2025, 08:29 AM
RE: Petit prog pour esp32 - par Philmaz - 30-05-2025, 09:01 AM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 09:02 AM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 09:00 AM
RE: Petit prog pour esp32 - par grostoto - 30-05-2025, 09:11 AM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 03:26 PM
RE: Petit prog pour esp32 - par PhDV61 - 30-05-2025, 09:12 AM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 09:26 AM
RE: Petit prog pour esp32 - par bernard62 - 30-05-2025, 12:12 PM
RE: Petit prog pour esp32 - par glu3 - 30-05-2025, 02:21 PM
RE: Petit prog pour esp32 - par pdunet - 30-05-2025, 02:29 PM
RE: Petit prog pour esp32 - par lucky - 30-05-2025, 05:33 PM
RE: Petit prog pour esp32 - par grostoto - 30-05-2025, 07:50 PM
RE: Petit prog pour esp32 - par 59jag - 30-05-2025, 10:03 PM
RE: Petit prog pour esp32 - par lucky - 31-05-2025, 08:03 AM
RE: Petit prog pour esp32 - par lucky - 31-05-2025, 08:04 AM
RE: Petit prog pour esp32 - par 59jag - 31-05-2025, 09:22 AM
RE: Petit prog pour esp32 - par Sgb31 - 31-05-2025, 09:35 AM
RE: Petit prog pour esp32 - par lucky - 31-05-2025, 12:01 PM
RE: Petit prog pour esp32 - par pdunet - Il y a 16 minutes

Atteindre :


Utilisateur(s) parcourant ce sujet : GPL, 3 visiteur(s)