IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

localStorage remplace les items existants


Sujet :

JavaScript

  1. #1
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 203
    Points : 82
    Points
    82
    Par défaut localStorage remplace les items existants
    Bonjour,

    J'en ai marre que l'on me rajoute une couche de pub quand j'écoute la radio via une application alors j'ai décidé d'en créer une et tout fonctionne sauf l'ajout aux radios favorites via le locaStorage qui sauvegarde bien 1 radio mais si j'en sélectionne une autre, elle écrase la précédente :

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function updateFavoritesUI(favorites) {
      var favoritesContainer = document.getElementById('radios-favorites');
      favoritesContainer.innerHTML = ''; // Effacer le contenu actuel
     
      favorites.forEach(function (favorite) {
        // Créer et ajouter la nouvelle carte favori à l'interface utilisateur
        var newFavoriteCard = document.createElement('div');
        newFavoriteCard.classList.add('card', 'ps-0', 'pe-0', 'swiper-slide');
     
        var favoriteCardContent = `
          <div class="card__image">
            <img class="img-fluid" src="${favorite.image}" alt="Radio">
          </div>
          <div class="card__content">
            <span class="card__title mt-1">${favorite.title}</span>
            <audio data-src="${favorite.audioSrc}"></audio>
          </div>
        `;
     
        newFavoriteCard.innerHTML = favoriteCardContent;
        favoritesContainer.appendChild(newFavoriteCard);
      });
    }
     
    function saveFavoritesToStorage(favorites) {
      localStorage.setItem('radioFavorites', JSON.stringify(favorites));
    }
    Nom : localStorage.png
Affichages : 159
Taille : 19,8 Ko

    Je vous remercie pour votre aide

  2. #2
    Expert confirmé
    Avatar de Doksuri
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    2 467
    Détails du profil
    Informations personnelles :
    Âge : 54
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 467
    Points : 4 656
    Points
    4 656
    Par défaut
    comment fais-tu appel a saveFavoritesToStorage(favorites) ? favorites est-il correctement a jour ?
    dans l'idee, il faudrait faire quelque chose comme ca
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function saveFavoritesToStorage(newFavs) {
      const currentFavs = JSON.parse(localStorage.getItem('radioFavorites')) || [];
      currentFavs.push(newFavs);
      localStorage.setItem('radioFavorites', JSON.stringify(currentFavs));
    }

  3. #3
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 203
    Points : 82
    Points
    82
    Par défaut
    De cette façon :

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
      // Sélection de la balise parente contenant la classe .controls
      var controlsDiv = document.querySelector('.controls');
     
      // Création de l'élément input pour le contrôle du volume
      var volumeControl = document.createElement('input');
      volumeControl.type = 'range'; // Type de l'input pour le contrôle du volume
      volumeControl.min = '0'; // Valeur minimale du volume
      volumeControl.max = '1'; // Valeur maximale du volume
      volumeControl.step = '0.1'; // Incréments pour ajuster le volume
      volumeControl.value = '1'; // Valeur initiale du volume
      volumeControl.addEventListener('input', function () {
        audioPlayer.volume = parseFloat(this.value); // Met à jour le volume selon la valeur de l'input
      });
     
      // Sélection de la colonne spécifique pour les contrôles
      var controlsColumn = controlsDiv.querySelector('.col-6.controls');
     
      // Ajout de l'élément input à l'intérieur de la colonne spécifique .col.controls
      controlsColumn.appendChild(volumeControl);
     
     
     
      // Définition de la source audio par défaut
      audioPlayer.src = defaultRadioSrc;
     
      cards.forEach(function (card) {
        card.addEventListener('click', function () {
          const imageSrc = card.querySelector('.card__image img').getAttribute('src');
          const radioSrc = card.querySelector('audio').getAttribute('data-src');
          const radioName = card.querySelector('.card__title').textContent;
     
          // Mettre à jour la carte dans la section "Lecture en cours"
          currentStationImage.src = imageSrc;
          currentStationTitle.textContent = "";
          audioPlayer.src = radioSrc; // Mettre à jour la source seulement au clic
     
          // Afficher le bouton favori car une radio est sélectionnée
          updateFavoriteButtonOnRadioSelect();
        });
      });
     
     
      window.onload = function () {
        updateFavoriteButton(false);
      };
     
     
      playButton.addEventListener('click', function () {
        if (audioPlayer.src && audioPlayer.src !== '') {
          audioPlayer.play();
        } else {
          console.error('Aucune source audio définie');
        }
      });
     
      pauseButton.addEventListener('click', function () {
        audioPlayer.pause();
      });
    });
     
     
    var favoriteButton = document.getElementById('favorite-icon');
     
    // Fonction pour afficher ou masquer le bouton du cœur en fonction de la présence de radio
    function updateFavoriteButton(hasRadio) {
      var favoriteIcon = document.getElementById('favorite-icon');
     
      if (favoriteIcon) {
        favoriteIcon.style.display = hasRadio ? 'block' : 'none';
     
        if (hasRadio) {
          var isAlreadyInFavoris = checkIfInFavoris();
          favoriteIcon.innerHTML = isAlreadyInFavoris ? '<i class="bi bi-star-fill colorYellow" onclick="toggleFavorite()"></i>' : '<i class="bi bi-star colorYellow" onclick="toggleFavorite()"></i>';
        }
      }
    }
     
     
    function updateFavoriteButtonOnRadioSelect() {
      var hasRadio = audioPlayer.src && audioPlayer.src !== '';
      var favoriteIcon = document.getElementById('favorite-icon');
     
      if (favoriteIcon) {
        favoriteIcon.style.display = hasRadio ? 'block' : 'none';
     
        if (hasRadio) {
          var isAlreadyInFavoris = checkIfInFavoris();
          favoriteIcon.classList.remove('bi-star-fill', 'bi-star');
          favoriteIcon.classList.add(isAlreadyInFavoris ? 'bi-star-fill' : 'bi-star');
        }
      }
    }
     
     
     
    function ajouterAuxFavoris() {
      var favorisImage = document.querySelector('#current-station img[alt="radio favorite"]');
     
      if (favorisImage && audioPlayer.src && audioPlayer.src !== '') {
        var isAlreadyInFavoris = checkIfInFavoris();
     
        if (isAlreadyInFavoris) {
          removeFromFavoris();
          favorisImage.innerHTML = '<i class="bi bi-star"></i>';
        } else {
          addToFavoris();
          favorisImage.innerHTML = '<i class="bi bi-star-fill"></i>';
        }
      }
    }
     
     
     
    function toggleFavorite() {
      var isAlreadyInFavoris = checkIfInFavoris();
      var favoriteIcon = document.getElementById('favorite-icon');
     
      if (isAlreadyInFavoris) {
        removeFromFavoris();
        favoriteIcon.classList.remove('bi-star-fill');
        favoriteIcon.classList.add('bi-star');
      } else {
        addToFavoris();
        favoriteIcon.classList.remove('bi-star');
        favoriteIcon.classList.add('bi-star-fill');
      }
    }
     
     
     
     
    function checkIfInFavoris() {
      // Récupérer les détails de la radio actuellement sélectionnée
      var currentTitle = document.getElementById('current-title').textContent;
     
      // Vérifier si la radio est déjà dans les favoris
      var favorites = getFavoritesFromStorage();
      var isInFavoris = false;
     
      favorites.forEach(function (favorite) {
        if (favorite.title === currentTitle) {
          isInFavoris = true;
          return;
        }
      });
     
      return isInFavoris;
    }
     
    function addToFavoris() {
      // Ajouter la radio aux favoris
      var currentTitle = document.getElementById('current-title').textContent;
      var currentImage = document.getElementById('current-image').getAttribute('src');
      var currentAudioSrc = document.getElementById('audioPlayer').getAttribute('src');
     
      var newFavorite = {
        title: currentTitle,
        image: currentImage,
        audioSrc: currentAudioSrc
      };
     
      var favorites = getFavoritesFromStorage();
      favorites.push(newFavorite);
     
      saveFavoritesToStorage(favorites);
     
      // Mettre à jour l'interface utilisateur avec les favoris mis à jour
      updateFavoritesUI(favorites);
    }
     
    function removeFromFavoris() {
      // Supprimer la radio des favoris
      var currentTitle = document.getElementById('current-title').textContent;
     
      var favorites = getFavoritesFromStorage();
      var updatedFavorites = favorites.filter(function (favorite) {
        return favorite.title !== currentTitle;
      });
     
      saveFavoritesToStorage(updatedFavorites);
     
      updateFavoritesUI(updatedFavorites);
    }
     
     
    /* mémoriser les ajouts aux favoris*/
    function getFavoritesFromStorage() {
      const storedFavorites = localStorage.getItem('radioFavorites');
      return storedFavorites ? JSON.parse(storedFavorites) : [];
    }
     
    function saveFavoritesToStorage(favorites) {
      localStorage.setItem('radioFavorites', JSON.stringify(favorites));
    }

  4. #4
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 203
    Points : 82
    Points
    82
    Par défaut
    Citation Envoyé par Doksuri Voir le message
    comment fais-tu appel a saveFavoritesToStorage(favorites) ? favorites est-il correctement a jour ?
    dans l'idee, il faudrait faire quelque chose comme ca

    De cette façon, cela ajoute un tableau vide. J'ai fait une vidéo avec des couleurs pas terribles mais ça devrait aller : https://www.cjoint.com/c/NApsftPZf37

  5. #5
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 203
    Points : 82
    Points
    82
    Par défaut
    J'ai fait comme ça, mais cela donne ça :

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    [
        [
            {
                "title": "",
                "image": "img/RTL.webp",
                "audioSrc": "http://streaming.radio.rtl.fr/rtl-1-44-128?listen=webCggNCQgLDQUGBAcGBg"
            }
        ],
        [
            [
                {
                    "title": "",
                    "image": "img/RTL.webp",
                    "audioSrc": "http://streaming.radio.rtl.fr/rtl-1-44-128?listen=webCggNCQgLDQUGBAcGBg"
                }
            ],
            {
                "title": "",
                "image": "img/Latina.webp",
                "audioSrc": "http://start-latina.ice.infomaniak.ch/start-latina-high.mp3"
            }
        ],
        [
            [
                {
                    "title": "",
                    "image": "img/RTL.webp",
                    "audioSrc": "http://streaming.radio.rtl.fr/rtl-1-44-128?listen=webCggNCQgLDQUGBAcGBg"
                }
            ],
            [
                [
                    {
                        "title": "",
                        "image": "img/RTL.webp",
                        "audioSrc": "http://streaming.radio.rtl.fr/rtl-1-44-128?listen=webCggNCQgLDQUGBAcGBg"
                    }
                ],
                {
                    "title": "",
                    "image": "img/Latina.webp",
                    "audioSrc": "http://start-latina.ice.infomaniak.ch/start-latina-high.mp3"
                }
            ],
            {
                "title": "",
                "image": "img/RTL.webp",
                "audioSrc": "http://streaming.radio.rtl.fr/rtl-1-44-128?listen=webCggNCQgLDQUGBAcGBg"
            }
        ]
    ]
    Voici les fonctions :

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function saveFavoritesToStorage(newFavorite) {
      // Récupérer les favoris actuels depuis le stockage local
      var isAlreadyInFavoris = checkIfInFavoris();
      var storedFavorites = localStorage.getItem('radioFavorites');
      var favorites = storedFavorites ? JSON.parse(storedFavorites) : [];
      // Ajouter le nouveau favori à la liste
        if (!isAlreadyInFavoris) {
          favorites.push(newFavorite);
          // Sauvegarder la liste mise à jour dans le stockage local
          localStorage.setItem('radioFavorites', JSON.stringify(favorites));
        };
    }

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function checkIfInFavoris() {
      // Récupérer les détails de la radio actuellement sélectionnée
      var currentTitle = document.getElementById('current-title').textContent;
      // Vérifier si la radio est déjà dans les favoris
      var favorites = getFavoritesFromStorage();
      var isInFavoris = false;
      favorites.forEach(function (favorite) {
        if (favorite.title === currentTitle) {
          isInFavoris = true;
          return;
        }
      });
     
      return isInFavoris;
    }

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /* mémoriser les ajouts aux favoris*/
    function getFavoritesFromStorage() {
      const storedFavorites = localStorage.getItem('radioFavorites');
      return storedFavorites ? JSON.parse(storedFavorites) : [];
    }

  6. #6
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 679
    Points
    44 679
    Par défaut
    Bonjour,
    pourquoi vouloir tout mettre dans le même enregistrement ?
    Dans ton localStorage tu devrais retrouver quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    "RTL": {
      "title": "",
      "image": "img/RTL.webp",
      "audioSrc": "http://streaming.radio.rtl.fr/rtl-1-44-128?listen=webCggNCQgLDQUGBAcGBg"
    }
    "Latina": {
      "title": "",
      "image": "img/Latina.webp",
      "audioSrc": "http://start-latina.ice.infomaniak.ch/start-latina-high.mp3"
    }
    La gestion en devient simplissime.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const Store = {
      store: window.localStorage,
      removeItem: function(item) {
        this.store.removeItem(item);
      },
      readItem: function(item) {
        return JSON.parse(this.store.getItem(item));
      },
      addItem: function(item, value) {
        this.store.setItem(item, JSON.stringify(value));
      },
      existItem: function(item) {
        return !!this.store.read(item);
      },
    }
    donc pour récupérer des données sur une radio il suffit de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const data = Store.readItem("RTL");

  7. #7
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 203
    Points : 82
    Points
    82
    Par défaut
    Merci, c'est beaucoup plus clair pour moi comme ça et en attendant, j'ai fait une liste des dernières radios écoutées et tout fonctionne bien mais les données du local storage sont détruites à la fermeture du navigateur :

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////// DERNIERES RADIOS ECOUTEES //////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    const currentStationImage = document.getElementById('current-image');
     
    // Structure de données pour les dernières stations écoutées
    var dernieresStations = [];
     
    function ajouterADernieresEcoutees(title, image, audioSrc) {
      // Ajouter la nouvelle station au début de la liste
      dernieresStations.unshift({ title, image, audioSrc });
     
      // Limiter la taille de la liste à 10 (ou tout autre nombre souhaité)
      if (dernieresStations.length > 10) {
        dernieresStations.pop();
      }
     
      // Sauvegarder la liste mise à jour dans le localStorage
      localStorage.setItem('dernieresStationsEcoutees', JSON.stringify(dernieresStations));
    }
     
    // Fonction pour récupérer les dernières stations écoutées du localStorage
    function getDernieresStations() {
      const storedStations = localStorage.getItem('dernieresStationsEcoutees');
      return storedStations ? JSON.parse(storedStations) : [];
    }
     
    // Appeler cette fonction chaque fois qu'une station est écoutée
    function stationEcoutee(title = "Station par défaut", image = "img/defaut.webp", audioSrc = "audio/defaut.mp3") {
      ajouterADernieresEcoutees(title, image, audioSrc);
      updateDernieresStationsUI();
    }
     
    function updateDernieresStationsUI() {
      var dernieresStations = getDernieresStations();
      var dernieresStationsContainer = document.getElementById('dernieres-stations-container');
     
      // Vider le contenu actuel du conteneur
      dernieresStationsContainer.innerHTML = '';
     
      // Vérifier si la liste des stations est vide
      if (dernieresStations.length === 0) {
        // Afficher un message ou une icône indiquant qu'aucune station n'a été écoutée
        var emptyMessage = document.createElement('div');
        emptyMessage.classList.add('empty-stations-message');
        // emptyMessage.textContent = "Aucune station écoutée récemment. Les stations s'afficheront ici";
        emptyMessage.innerHTML = `
          <span class="icon-class"><i class="bi bi-star-fill colorYellow gros"></i></span>`;
        dernieresStationsContainer.appendChild(emptyMessage);
      } else {
        // Sinon, afficher les stations comme d'habitude
        dernieresStations.forEach(function (station) {
          var stationCard = document.createElement('div');
          stationCard.classList.add('cardFavoris', 'ps-0', 'pe-0', 'swiper-slide');
     
          // Utilisez l'image de la station ou une image par défaut si l'image de la station n'est pas disponible
          var imageSrc = station.image || 'img/13FM.webp'; // Chemin vers votre image par défaut
     
          var stationCardContent = `
            <div class="card__image">
              <img class="img-fluid" src="${imageSrc}" alt="Radio">
            </div>
            <div class="card__content">
              <span class="card__title mt-0">${station.title}</span>
              <audio data-src="${station.audioSrc}"></audio>
            </div>
          `;
     
          stationCard.innerHTML = stationCardContent;
          dernieresStationsContainer.appendChild(stationCard);
     
          stationCard.addEventListener('click', function () {
            currentStationImage.src = imageSrc;
            currentStationTitle.textContent = station.title;
            audioPlayer.src = station.audioSrc;
            audioPlayer.play(); // Jouer la station directement
          });
        });
     
      }
    }
     
    function jouerStation(audioSrc) {
      // Logique pour jouer la station
      console.log("Play :", audioSrc);
    }
     
     
    document.addEventListener("DOMContentLoaded", function () {
      updateDernieresStationsUI();
    });

    Nom : donneesNonPersistantes.png
Affichages : 98
Taille : 259,8 Ko
    Images attachées Images attachées  

  8. #8
    Membre éclairé
    Homme Profil pro
    Urbaniste
    Inscrit en
    Août 2023
    Messages
    386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Urbaniste

    Informations forums :
    Inscription : Août 2023
    Messages : 386
    Points : 798
    Points
    798
    Par défaut
    Bonjour,

    local storage sont détruites à la fermeture du navigateur
    D'une manière générale, et j'avais déjà noté cela quand tu partageais un dump de la valeur favoris du localStorage,

    ton code semble péniblement trop compliqué et il me semble que tu t'y perds.

    Regardes, plus haut tu as posté ton code JS, 194 lignes de code alors qu'il n'est même pas complet.

    Avec alpine.js, c'est le nombre de ligne HTML+JS dont j'ai besoin pour reproduire dans les grandes lignes ton interface.

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    <html>
    <head>
        <link href="assets/index.css" rel="stylesheet" type="text/css" />
        <meta name="viewport" content="width=device-width" />
        <script src="/assets/alpine-3.13.3.js" defer></script>
    </head>
    <body>
        <main>
            <header x-data :class="{'recents': $store.recents.has()}">
                <h1>Mes radios</h1>
                <div>
                    <template x-for="radio in $store.recents.items">
                        <img :src="$store.radios.pic(radio)" :alt="$store.radios.alt(radio)"
                        @click.prevent="$store.active.toggle(radio); $store.audio.toggle(radio);"  />
                    </template>
                </div>
            </header>
            <section x-data
                :class="{'active': $store.active.has() , 'recents': $store.recents.has(), 'loading': $store.radios.loading}"
                >
                <div>
                    <input type="text" placeholder="recherche" x-model="$store.radios.search" />
                </div>
                <div>
                    <template x-for="radio in $store.radios.list($store.radios.search)">
                        <div 
                            @click.prevent="$store.active.toggle(radio); $store.recents.add(radio); $store.audio.toggle($store.active.radio);" 
                            :class="$store.active.is(radio) && 'active'">
                            <h2 x-text="radio.name"></h2>
                            <img :src="$store.radios.pic(radio)" :alt="$store.radios.alt(radio)" />
                        </div>
                    </template>
                </div>
            </section>
            <footer x-data :class="{'active': $store.active.has()}">
                <div class="pic">
                    <img :src="$store.radios.pic($store.active.radio)"
                        :alt="$store.radios.alt($store.active.radio)" />
                </div>
                <div x-data="$store.audio" class="audio">
                    <span :class="{'disabled': !$store.active.has()}"
                        @click.prevent="$store.active.radio && $store.audio.play($store.active.radio);" 
                        >&#x23F5;</span>
                    <span :class="{'disabled': !$store.active.has()}"
                        @click.prevent="$store.active.radio && $store.audio.pause();" 
                        >&#x23F8;</span>
                    <input type="range" x-model="volume" min="0" max="100" @input="update()" />
                    <audio x-ref="audio" src="/media/cc0-audio/t-rex-roar.mp3"></audio>
                </div>
            </footer>
        </main>
        <script>
            document.addEventListener('alpine:init', () => {
                // Alpine.data(...)
     
                const storage = ((store) => {
                    return {
                        set(n, v)  {
                            try {
                                store.setItem(n, JSON.stringify(v));
                            }catch(ex) {
                                console.error(ex);
                            }
                        },
                        get(n)  {
                            const d = store.getItem(n);
                            try {
                                return JSON.parse(d);
                            }catch(ex) {
                                console.error(ex);
                            }
                            return null;
                        }
                    }
                })(localStorage)
     
                Alpine.directive('json', (el, { expression }, { evaluateLater, effect }) => {
                    const vget = evaluateLater(expression)
                    effect(() => {
                        vget((v) => {
                            el.textContent = JSON.stringify(v)
                        })
                    })
                })
     
                Alpine.store('radios', {
                    loading: true,
                    search: "",
                    list(search) {
                        this.loading = true;
                        var that = this;
                        if(search && search.length>2) {
                            return new Promise((resolve, reject)=>{
                                fetch('/api/search?search='+search).then((r)=>{
                                    resolve(r.json())
                                }).catch(reject).finally(()=>{
                                    that.loading = false;
                                });
                            })
                        }
                        return new Promise((resolve, reject)=>{
                            fetch('/api/all').then((r)=>{
                                resolve(r.json())
                            }).catch(reject).finally(()=>{
                                that.loading = false;
                            });
                        })
                    },
                    alt(radio) {
                        if(radio.logo) {
                            return radio.logo.alternativeText || "";
                        }
                    },
                    pic(radio) {
                        let img = "none.jpg";
                        if (radio.logo) {
                            const formats = radio.logo.formats;
                            const small = formats.filter((f)=>{
                                return f.kind==="small"
                            });
                            if(small.length>0){
                                img = small[0].url;
                            }else if(formats.length>0){
                                img = formats[0].url;
                            }
                        }
                        return '/radios/imgs/'+ img;
                    },
                });
     
                Alpine.store('active', {
                    radio: {},
                    is(radio){
                        return this.radio.name===radio.name;
                    },
                    has(){
                        return !!this.radio.name;
                    },
                    set(radio){
                        this.radio=radio;
                    },
                    toggle(radio){
                        if(this.radio.name===radio.name){
                            this.radio={};
                        }else{
                            this.radio=radio;
                        }
                    },
                });
     
                Alpine.store('recents', {
                    items: [],
                    max: 5,
                    init() {
                        this.items = storage.get("recents") || [];
                    },
                    has() {
                        return this.items.length>0;
                    },
                    add(radio) {
                        const c = this.items.findIndex((e)=>{return e.name===radio.name;});
                        if(c===-1) {
                            this.items.unshift(radio)
                            if(this.items.length>this.max) {
                                this.items.pop();
                            }
                            storage.set("recents", this.items);
                        }
                    },
                });
            
                Alpine.store('audio', {
                    volume: 0,
                    paused: true,
                    init() {
                        this.volume = storage.get("volume") || 0;
                        Alpine.nextTick(()=>{
                            this.$refs.audio.volume = this.volume/100; 
                        })
                    },
                    initialized(){
                        console.log("initialized")
                    },
                    pause() {
                        if(this.$refs.audio.src){
                            this.$refs.audio.pause();
                        }
                        this.paused = true;
                    },
                    play(radio) {
                        if(this.$refs.audio.src){
                            this.$refs.audio.pause();
                        }
                        this.$refs.audio.src = radio.streams_url[0].url;
                        this.$refs.audio.play();
                        this.paused = false;
                    },
                    toggle(radio) {
                        if(!radio.name){
                            this.pause();
                            return 
                        }
                        const src = this.$refs.audio.src  || "";
                        const c= radio.streams_url.findIndex((e)=>{
                            return e.url===src;
                        });
                        if(c===-1){
                            this.play(radio);
                        }else if(this.paused) {
                            this.$refs.audio.play();
                            this.paused = false;
                        }else {
                            this.pause();
                        }
                    },
                    update() {
                        this.$refs.audio.volume = this.volume/100; 
                        storage.set("volume", this.volume);
                    },
                });
            
            })
        </script>
    </body>
    </html>

    En fait, ici, c'est le CSS qui est le plus long ...
    Code CSS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    *{
        box-sizing: border-box;
    }
    html{
        height: 100vh;
        font-family: sans-serif;
        overflow: hidden;
    }
    body{
        margin:0;
        padding: 0;
        min-height: 100vh;
    }
    body > main {
        height: 100vh;
    }
    body > main > header,
    body > main > footer{
        width: 100%;
    }
     
    :root{
        --header-height: 75px;
        --footer-height: 75px;
        --header-height-expand: 120px;
        --footer-height-expand: 150px;
        --transition-duration: 600ms;
    }
    body > main > header{
        background: #08043e;
        height: var(--header-height);
    }
    body > main > section{
        position: absolute;
        top: var(--header-height);
        left:0;
        height: calc(100% - calc(var(--header-height) + var(--footer-height)));
        transition: height var(--transition-duration);
    }
    body > main > footer{
        position: absolute;
        bottom:0;
        left:0;
        height: var(--footer-height);
    }
     
     
    body > main > footer.active{
        height: var(--footer-height-expand);
    }
    body > main > header.recents{
        height: var(--header-height-expand);
    }
    body > main > section.active{
        height: calc(100% - calc(var(--header-height) + var(--footer-height-expand)));
    }
    body > main > section.recents{
        top: var(--header-height-expand);
        height: calc(100% - calc(var(--header-height-expand) + var(--footer-height)));
    }
    body > main > section.recents.active{
        height: calc(100% - calc(var(--header-height-expand) + var(--footer-height-expand)));
    }
     
    body > main > header{
        display:grid;
        transition: height var(--transition-duration);
    }
    body > main > header > h1{
        color: white;
        font-size: x-large;
        text-transform: uppercase;
        padding:0;
        margin:0;
        width:100%;
    }
    body > main > header > div{
        width:80%;
        margin-left: 10%;
        text-align:center;
        opacity: 0;
        transition: opacity var(--transition-duration);
    }
    body > main > header.recents > div{
        opacity: 1;
    }
    body > main > header > div > img{
        width: 40px;
        display:inline-block;
        margin-left:15px;
        cursor:pointer;
    }
    body > main > header > div > img:first-of-type{
        margin-left:0px;
    }
     
    body > main > footer{
        background: radial-gradient(ellipse at center 160%, 
        rgba(255,255,255,1) 0%, rgba(139,154,176,1) 0%, 
        rgba(8,4,62,1) 100%);
        transition:  height var(--transition-duration);
    }
    body > main > footer > div.audio {
        background-color: black;
        color: white;
        border-radius: 5px;
        border: 3px solid gray;
        padding: 10px;
        width: 80%;
        margin:auto;
     
        position:absolute;
        bottom:15px;
        left: 10%;
     
        display: grid;
        gap: 10px; 
        grid-template-columns: 1fr 1fr 10fr;
    }
    body > main > footer > div.audio > span{
        font-size: xx-large;
        line-height: 10px;
        text-align: center;
        display: inline-block;
        cursor: pointer;
    }
    body > main > footer > div.pic{
        transition: height var(--transition-duration), 
                    opacity var(--transition-duration), 
                    margin-top var(--transition-duration);
        height: 0px;
        opacity: 0;
        text-align:center;
        margin-top: 0px;
    }
    body > main > footer.active > div.pic{
        margin-top: 15px;
        height: 50px;
        opacity: 1;
        transition: height 0ms, opacity 0ms;
    }
    body > main > footer > div.pic > img{
        height: 0px;
        transition: height var(--transition-duration);
    }
    body > main > footer.active > div.pic > img{
        height: 50px;
    }
     
     
    body > main > section{
        overflow: scroll;
        background-color: #fff;
        padding: 30px;
        width: 100%;
    }
     
    body > main > section > div:first-child{
        margin-bottom: 30px;
    }
    body > main > section > div:first-child >input[type="text"]{
        width: 100%;
        padding: 10px;
    }
     
    body > main > section > div:last-child{
        display: grid;
        grid-template-columns: repeat(var(--main-grid-cols), 1fr);
        gap:40px;
    }
    body > main > section > div:last-child > div {
        display:inline-block;
        text-align: center;
        cursor: pointer;
        padding: 10px;
        box-shadow: 0px 0px 10px grey;
        height: 140px;
    }
    body > main > section > div:last-child > div  > h2{
        margin:0;
        padding: 0;
        font-size: medium;
    }
    body > main > section > div:last-child  > div > img{
        max-width: 70%;
        max-height: 70%;
    }
     
    :root{
        --main-grid-cols: 8;
    }
     
    @media (max-width: 1199.98px) { 
        :root{
            --main-grid-cols: 6;
        }
    }
     
    @media (max-width: 991.98px) { 
        :root{
            --main-grid-cols: 5;
        }
    }
     
    @media (max-width: 767.98px) { 
        :root{
            --main-grid-cols: 3;
        }
        body > main > footer > div {
            grid-template-columns: 2fr 2fr 8fr;
        }
    }
     
    @media (max-width: 575.98px) {
        :root{
            --main-grid-cols: 2;
        }
        body > main > footer > div {
            grid-template-columns: 2fr 2fr 8fr;
        }
    }
     
     
     
    body > main > footer audio{
        position: absolute;
        top: 120%;
        left: -120%;
    }
     
     
     
     
     
    /* SEE https://nosmoking.developpez.com/demos/css/range-slider-custom.html */
    body > main > footer > div > input[type="range"]{
        -webkit-appearance: none;
        appearance: none;
        background: transparent;
        cursor: pointer;
        margin:0;
        padding: 0;
    }
     
    /* la zone de déplacement */
    /* webkit */
    body > main > footer > div > input[type=range]::-webkit-slider-runnable-track {
        background: #053a5f;
        height: 0.5rem;
    }
    body > main > footer > div > input[type=range]::-webkit-slider-thumb {
        border: 1px solid #053a5f;
        outline: 3px solid #053a5f;
        outline-offset: 0.125rem;
    }
     
    /* firefox */
    input[type=range]::-moz-range-track {
        background: #053a5f;
        height: 0.5rem;
    }
    /* le curseur */
    input[type=range]::-moz-range-thumb {
        border: 1px solid #053a5f;
        outline: 3px solid #053a5f;
        outline-offset: 0.125rem;
    }
    /* barre progression avant */
    input[type=range]::-moz-range-progress {
        height: 0;
        background: transparent;
    }
     
    /* IE EDGE */
    /* la zone de déplacement */
    input[type=range]::-ms-track {
        background: #053a5f;
        height: 0.5rem;
    }
    /* le curseur */
    input[type=range]::-ms-thumb {
        border: 1px solid #053a5f;
        outline: 3px solid #053a5f;
        outline-offset: 0.125rem;
    }
    /* la tooltip de la valeur */
    input[type=range]::-ms-tooltip {
        display: none;
    }
    /* barre progression avant */
    input[type=range]::-ms-fill-lower {
        background: transparent;
    }
    /* barre progression après */
    input[type=range]::-ms-fill-upper {
        background: transparent;
    }
     
    input[type="range"]:focus {
        outline: none;
    }

    Pourtant il est pas terrible mon css.

    Au passage, on ne dit pas favorites, pas en français du moins.

    Peux tu partager tes assets logo+json de radio ?

    Bonne journée.

  9. #9
    Modérateur

    Avatar de NoSmoking
    Homme Profil pro
    Inscrit en
    Janvier 2011
    Messages
    17 075
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Janvier 2011
    Messages : 17 075
    Points : 44 679
    Points
    44 679
    Par défaut
    On voit dans ton code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Structure de données pour les dernières stations écoutées
    var dernieresStations = [];
    c'est cette variable que tu utilises notamment dans la fonction ajouterADernieresEcoutees.

    Pourquoi ne pas initialiser le tableau au chargement de la page attendu que cette variable est globale.

    D'autre part on note dans une de tes fonctions
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var dernieresStations = getDernieresStations();
    et là attention ce ne sont pas les mêmes variables.

    Est-ce qu'il n'y aurait pas une confusion à ce niveau ?

  10. #10
    Membre régulier
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 203
    Points : 82
    Points
    82
    Par défaut
    Merci, je vais changer un peu tout ça.

Discussions similaires

  1. changer le texte de tous les Items dans un mainmenu
    Par C.M dans le forum Composants VCL
    Réponses: 7
    Dernier message: 25/07/2004, 13h19
  2. [TListView] Déplacer / Arranger les items
    Par Ingham dans le forum Composants VCL
    Réponses: 4
    Dernier message: 14/07/2004, 15h52
  3. [langage] remplacer les caractères d'une chaine
    Par perlaud dans le forum Langage
    Réponses: 14
    Dernier message: 12/05/2004, 11h05
  4. Comment espacer les Items d'un TMainMenu ?
    Par JojoLaFripouille dans le forum Composants VCL
    Réponses: 3
    Dernier message: 27/08/2003, 15h57
  5. Recuper les items de ListBox d'une autre application [API?]
    Par Shamanisator dans le forum API, COM et SDKs
    Réponses: 3
    Dernier message: 27/09/2002, 12h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo