Composants
Modèles
Attributs
Intégrations
Testeur de site
Code personnalisé

Scripts des membres

Une solution basée sur les attributs pour ajouter des fonctionnalités à votre site Webflow.
Il suffit de copier un peu de code, d'ajouter quelques attributs et le tour est joué.

Nous vous remercions ! Votre demande a bien été reçue !
Oups ! Un problème s'est produit lors de l'envoi du formulaire.
Besoin d'aide avec MemberScripts ?

Tous les clients de Memberstack peuvent demander de l'aide dans le Slack 2.0. Veuillez noter qu'il ne s'agit pas de fonctionnalités officielles et que le support ne peut être garanti.

Marketing
Champs personnalisés

#67 - Pré-remplir le formulaire en fonction des paramètres de l'URL

Remplir facilement les entrées à l'aide de paramètres URL.


<!-- 💙 MEMBERSCRIPT #67 v0.1 💙 PREFILL INPUTS WITH URL PARAMETERS -->
<script>
  // Function to get URL parameters
  function getURLParams() {
    const urlParams = new URLSearchParams(window.location.search);
    return Object.fromEntries(urlParams.entries());
  }

  // Function to prefill inputs based on URL parameters
  function prefillInputs() {
    const urlParams = getURLParams();
    const inputElements = document.querySelectorAll('[ms-code-prefill-param]');
    inputElements.forEach((inputElement) => {
      const paramKey = inputElement.getAttribute('ms-code-prefill-param');
      if (paramKey && urlParams[paramKey]) {
        inputElement.value = urlParams[paramKey];
      }
    });
  }

  // Call the function to prefill inputs when the page loads
  prefillInputs();
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #67 v0.1 💙 PREFILL INPUTS WITH URL PARAMETERS -->
<script>
  // Function to get URL parameters
  function getURLParams() {
    const urlParams = new URLSearchParams(window.location.search);
    return Object.fromEntries(urlParams.entries());
  }

  // Function to prefill inputs based on URL parameters
  function prefillInputs() {
    const urlParams = getURLParams();
    const inputElements = document.querySelectorAll('[ms-code-prefill-param]');
    inputElements.forEach((inputElement) => {
      const paramKey = inputElement.getAttribute('ms-code-prefill-param');
      if (paramKey && urlParams[paramKey]) {
        inputElement.value = urlParams[paramKey];
      }
    });
  }

  // Call the function to prefill inputs when the page loads
  prefillInputs();
</script>
Voir le Memberscript
Marketing

#66 - Liens d'invitation pour l'identification des membres

Créer des liens d'invitation/de référence personnalisés et uniques.


<!-- 💙 MEMBERSCRIPT #66 v0.1 💙 MEMBER ID INVITE LINKS -->
<script>
  // Function to get the member ID from local storage
  function getMemberIDFromLocalStorage() {
    // Assuming "_ms-mem" is the key that holds the member object in local storage
    const memberObject = JSON.parse(localStorage.getItem("_ms-mem"));
    if (memberObject && memberObject.id) {
      return memberObject.id;
    }
    return null;
  }

  // Function to update the invite link with the member ID as a URL parameter
  function updateInviteLink() {
    const inviteLinkElement = document.querySelector('[ms-code-invite-link]');
    if (inviteLinkElement) {
      const inviteLinkBase = inviteLinkElement.getAttribute('ms-code-invite-link');
      const memberID = getMemberIDFromLocalStorage();
      if (memberID) {
        const inviteLinkWithID = `${inviteLinkBase}?inviteCode=${memberID}`;
        inviteLinkElement.textContent = inviteLinkWithID;
        inviteLinkElement.href = inviteLinkWithID; // If it's an anchor link
      }
    }
  }

  // Call the function to update the invite link when the page loads
  updateInviteLink();
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #66 v0.1 💙 MEMBER ID INVITE LINKS -->
<script>
  // Function to get the member ID from local storage
  function getMemberIDFromLocalStorage() {
    // Assuming "_ms-mem" is the key that holds the member object in local storage
    const memberObject = JSON.parse(localStorage.getItem("_ms-mem"));
    if (memberObject && memberObject.id) {
      return memberObject.id;
    }
    return null;
  }

  // Function to update the invite link with the member ID as a URL parameter
  function updateInviteLink() {
    const inviteLinkElement = document.querySelector('[ms-code-invite-link]');
    if (inviteLinkElement) {
      const inviteLinkBase = inviteLinkElement.getAttribute('ms-code-invite-link');
      const memberID = getMemberIDFromLocalStorage();
      if (memberID) {
        const inviteLinkWithID = `${inviteLinkBase}?inviteCode=${memberID}`;
        inviteLinkElement.textContent = inviteLinkWithID;
        inviteLinkElement.href = inviteLinkWithID; // If it's an anchor link
      }
    }
  }

  // Call the function to update the invite link when the page loads
  updateInviteLink();
</script>
Voir le Memberscript
Marketing
Modaux

#65 - Fenêtre contextuelle d'intention de sortie

Montrer aux visiteurs une fenêtre contextuelle lorsque leur souris quitte le haut de la page.


<!-- 💙 MEMBERSCRIPT #65 v0.1 💙 EXIT INTENT POPUP -->
<script>
const CookieService = {
    setCookie(name, value, days) {
        const date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        const expires = days ? '; expires=' + date.toUTCString() : '';
        document.cookie = name + '=' + (value || '')  + expires + ';';
    },

    getCookie(name) {
        const cookieValue = document.cookie
            .split('; ')
            .find(row => row.startsWith(name))
            ?.split('=')[1];
        return cookieValue || null;
    }
};

const exitPopup = document.querySelector('[ms-code-popup="exit-intent"]');

const mouseEvent = e => {
    const shouldShowExitIntent = 
        !e.toElement && 
        !e.relatedTarget &&
        e.clientY < 10;

    if (shouldShowExitIntent) {
        document.removeEventListener('mouseout', mouseEvent);
        exitPopup.style.display = 'flex';
        CookieService.setCookie('exitIntentShown', true, 30);
    }
};

if (!CookieService.getCookie('exitIntentShown')) {
    document.addEventListener('mouseout', mouseEvent);
    document.addEventListener('keydown', exit);
    exitPopup.addEventListener('click', exit);
}
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #65 v0.1 💙 EXIT INTENT POPUP -->
<script>
const CookieService = {
    setCookie(name, value, days) {
        const date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        const expires = days ? '; expires=' + date.toUTCString() : '';
        document.cookie = name + '=' + (value || '')  + expires + ';';
    },

    getCookie(name) {
        const cookieValue = document.cookie
            .split('; ')
            .find(row => row.startsWith(name))
            ?.split('=')[1];
        return cookieValue || null;
    }
};

const exitPopup = document.querySelector('[ms-code-popup="exit-intent"]');

const mouseEvent = e => {
    const shouldShowExitIntent = 
        !e.toElement && 
        !e.relatedTarget &&
        e.clientY < 10;

    if (shouldShowExitIntent) {
        document.removeEventListener('mouseout', mouseEvent);
        exitPopup.style.display = 'flex';
        CookieService.setCookie('exitIntentShown', true, 30);
    }
};

if (!CookieService.getCookie('exitIntentShown')) {
    document.addEventListener('mouseout', mouseEvent);
    document.addEventListener('keydown', exit);
    exitPopup.addEventListener('click', exit);
}
</script>
Voir le Memberscript
Visibilité conditionnelle
Champs personnalisés

#64 - Logique du formulaire radio

Affiche les éléments du jeu en fonction de la radio sélectionnée.


<!-- 💙 MEMBERSCRIPT #64 v0.1 💙 RADIO FORM LOGIC -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
    // initially hide all divs with 'ms-code-more-info' attribute
    $("div[ms-code-more-info]").hide();

    // listen for change events on all radios with 'ms-code-radio-option' attribute
    $("input[ms-code-radio-option]").change(function() {
        // hide all divs again
        $("div[ms-code-more-info]").hide();

        // get the value of the selected radio button
        var selectedValue = $(this).attr("ms-code-radio-option");

        // find the div with the 'ms-code-more-info' attribute that matches the selected value and show it
        $("div[ms-code-more-info=" + selectedValue + "]").show();
    });
});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #64 v0.1 💙 RADIO FORM LOGIC -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
    // initially hide all divs with 'ms-code-more-info' attribute
    $("div[ms-code-more-info]").hide();

    // listen for change events on all radios with 'ms-code-radio-option' attribute
    $("input[ms-code-radio-option]").change(function() {
        // hide all divs again
        $("div[ms-code-more-info]").hide();

        // get the value of the selected radio button
        var selectedValue = $(this).attr("ms-code-radio-option");

        // find the div with the 'ms-code-more-info' attribute that matches the selected value and show it
        $("div[ms-code-more-info=" + selectedValue + "]").show();
    });
});
</script>
Voir le Memberscript
Champs personnalisés

#63 - Sélecteur d'intervalle de dates

Créer une plage de dates dans Webflow !


<!-- 💙 MEMBERSCRIPT #62 v0.1 💙 DATE RANGE PICKER -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<style>
  .daterangepicker td.active {
    background-color: #006cfa !important ;
  }
</style>
<script type="text/javascript">
$(function() {

  $('input[ms-code-input="date-range"]').daterangepicker({
      "opens": "center",
      "locale": {
        "format": "MM/DD/YYYY",
        "separator": " - ",
        "applyLabel": "Apply",
        "cancelLabel": "Cancel",
        "fromLabel": "From",
        "toLabel": "To",
        "customRangeLabel": "Custom",
        "weekLabel": "W",
        "daysOfWeek": [
            "Su",
            "Mo",
            "Tu",
            "We",
            "Th",
            "Fr",
            "Sa"
        ],
        "monthNames": [
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December"
        ],
    },
  });

  $('input[name="datefilter"]').on('apply.daterangepicker', function(ev, picker) {
      $(this).val(picker.startDate.format('MM/DD/YYYY') + ' - ' + picker.endDate.format('MM/DD/YYYY'));
  });

  $('input[name="datefilter"]').on('cancel.daterangepicker', function(ev, picker) {
      $(this).val('');
  });

});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #62 v0.1 💙 DATE RANGE PICKER -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<style>
  .daterangepicker td.active {
    background-color: #006cfa !important ;
  }
</style>
<script type="text/javascript">
$(function() {

  $('input[ms-code-input="date-range"]').daterangepicker({
      "opens": "center",
      "locale": {
        "format": "MM/DD/YYYY",
        "separator": " - ",
        "applyLabel": "Apply",
        "cancelLabel": "Cancel",
        "fromLabel": "From",
        "toLabel": "To",
        "customRangeLabel": "Custom",
        "weekLabel": "W",
        "daysOfWeek": [
            "Su",
            "Mo",
            "Tu",
            "We",
            "Th",
            "Fr",
            "Sa"
        ],
        "monthNames": [
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December"
        ],
    },
  });

  $('input[name="datefilter"]').on('apply.daterangepicker', function(ev, picker) {
      $(this).val(picker.startDate.format('MM/DD/YYYY') + ' - ' + picker.endDate.format('MM/DD/YYYY'));
  });

  $('input[name="datefilter"]').on('cancel.daterangepicker', function(ev, picker) {
      $(this).val('');
  });

});
</script>
Voir le Memberscript
Marketing
UX
JSON

#62 - Bouton "Upvote

Ajouter la fonctionnalité "upvote" au CMS Webflow.


<!-- 💙 MEMBERSCRIPT #62 v0.2 💙 UPVOTE FORM -->
<script> 
  document.addEventListener('DOMContentLoaded', function() {
    const memberstack = window.$memberstackDom;
    const upvoteButtons = document.querySelectorAll('[ms-code="upvote-button"]');
    const upvoteForms = document.querySelectorAll('[ms-code="upvote-form"]');
    const upvotedValues = document.querySelectorAll('[ms-code="upvoted-value"]');
    const upvoteCounts = document.querySelectorAll('[ms-code="upvote-count"]');
    let clickTimeout; // Variable to store the timer
    let lastClickedButton = null; // Variable to store the last clicked button

    // Function to handle upvote button click
    function handleUpvoteButtonClick(event) {
      event.preventDefault();
      const button = event.currentTarget;

      // Clear the timer if the same button is clicked
      if (button === lastClickedButton) {
        clearTimeout(clickTimeout);
      }
      
      lastClickedButton = button; // Store the reference to the currently clicked button

      // Set a new timer
      clickTimeout = setTimeout(function() {
        const form = button.closest('form');
        const cmsId = button.getAttribute('data-cms-id');
        const upvotedValue = form.querySelector('[ms-code="upvoted-value"]');
        const upvoteCount = form.querySelector('[ms-code="upvote-count"]');

        if (button.classList.contains('is-true')) {
          // Remove upvote
          button.classList.remove('is-true');
          upvotedValue.value = 'false';
          upvoteCount.textContent = parseInt(upvoteCount.textContent) - 1;

          memberstack.getMemberJSON()
            .then(function(memberData) {
              if (memberData.data && memberData.data.upvotes) {
                const upvotes = memberData.data.upvotes;
                const index = upvotes.indexOf(cmsId);
                if (index !== -1) {
                  upvotes.splice(index, 1);
                  memberstack.updateMemberJSON({ json: memberData.data });
                }
              }
            })
            .catch(function(error) {
              console.error('Error retrieving/updating member data:', error);
            });
        } else {
          // Add upvote
          button.classList.add('is-true');
          upvotedValue.value = 'true';
          upvoteCount.textContent = parseInt(upvoteCount.textContent) + 1;

          memberstack.getMemberJSON()
            .then(function(memberData) {
              memberData.data = memberData.data || {};
              memberData.data.upvotes = memberData.data.upvotes || [];
              memberData.data.upvotes.push(cmsId);
              memberstack.updateMemberJSON({ json: memberData.data });
            })
            .catch(function(error) {
              console.error('Error retrieving/updating member data:', error);
            });
        }

        // Make the API call
        fetch(form.action, {
          method: form.method,
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
          },
          body: new URLSearchParams(new FormData(form))
        })
          .then(function(response) {
            if (response.ok) {
              // Handle successful API response
              return response.json();
            } else {
              // Handle API error
              throw new Error('API Error');
            }
          })
          .then(function(data) {
            // Handle API response to update vote count
            upvoteCount.textContent = data.upvoteCount; // Replace with the actual property holding the updated vote count
          })
          .catch(function(error) {
            console.error('API Error:', error);
          });
      }, 200); // 0.2 seconds
    }

    // Attach event listeners to upvote buttons
    upvoteButtons.forEach(function(button) {
      button.addEventListener('click', handleUpvoteButtonClick);
    });

    // Check if member has upvotes on page load
    memberstack.getMemberJSON()
      .then(function(memberData) {
        if (memberData.data && memberData.data.upvotes) {
          const upvotes = memberData.data.upvotes;
          upvoteButtons.forEach(function(button) {
            const cmsId = button.getAttribute('data-cms-id');
            if (upvotes.includes(cmsId)) {
              button.classList.add('is-true');
              const form = button.closest('form');
              const upvotedValue = form.querySelector('[ms-code="upvoted-value"]');
              upvotedValue.value = 'true';
            }
          });
        }
      })
      .catch(function(error) {
        console.error('Error retrieving member data:', error);
      });
  });
</script>
v0.2

<!-- 💙 MEMBERSCRIPT #62 v0.2 💙 UPVOTE FORM -->
<script> 
  document.addEventListener('DOMContentLoaded', function() {
    const memberstack = window.$memberstackDom;
    const upvoteButtons = document.querySelectorAll('[ms-code="upvote-button"]');
    const upvoteForms = document.querySelectorAll('[ms-code="upvote-form"]');
    const upvotedValues = document.querySelectorAll('[ms-code="upvoted-value"]');
    const upvoteCounts = document.querySelectorAll('[ms-code="upvote-count"]');
    let clickTimeout; // Variable to store the timer
    let lastClickedButton = null; // Variable to store the last clicked button

    // Function to handle upvote button click
    function handleUpvoteButtonClick(event) {
      event.preventDefault();
      const button = event.currentTarget;

      // Clear the timer if the same button is clicked
      if (button === lastClickedButton) {
        clearTimeout(clickTimeout);
      }
      
      lastClickedButton = button; // Store the reference to the currently clicked button

      // Set a new timer
      clickTimeout = setTimeout(function() {
        const form = button.closest('form');
        const cmsId = button.getAttribute('data-cms-id');
        const upvotedValue = form.querySelector('[ms-code="upvoted-value"]');
        const upvoteCount = form.querySelector('[ms-code="upvote-count"]');

        if (button.classList.contains('is-true')) {
          // Remove upvote
          button.classList.remove('is-true');
          upvotedValue.value = 'false';
          upvoteCount.textContent = parseInt(upvoteCount.textContent) - 1;

          memberstack.getMemberJSON()
            .then(function(memberData) {
              if (memberData.data && memberData.data.upvotes) {
                const upvotes = memberData.data.upvotes;
                const index = upvotes.indexOf(cmsId);
                if (index !== -1) {
                  upvotes.splice(index, 1);
                  memberstack.updateMemberJSON({ json: memberData.data });
                }
              }
            })
            .catch(function(error) {
              console.error('Error retrieving/updating member data:', error);
            });
        } else {
          // Add upvote
          button.classList.add('is-true');
          upvotedValue.value = 'true';
          upvoteCount.textContent = parseInt(upvoteCount.textContent) + 1;

          memberstack.getMemberJSON()
            .then(function(memberData) {
              memberData.data = memberData.data || {};
              memberData.data.upvotes = memberData.data.upvotes || [];
              memberData.data.upvotes.push(cmsId);
              memberstack.updateMemberJSON({ json: memberData.data });
            })
            .catch(function(error) {
              console.error('Error retrieving/updating member data:', error);
            });
        }

        // Make the API call
        fetch(form.action, {
          method: form.method,
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
          },
          body: new URLSearchParams(new FormData(form))
        })
          .then(function(response) {
            if (response.ok) {
              // Handle successful API response
              return response.json();
            } else {
              // Handle API error
              throw new Error('API Error');
            }
          })
          .then(function(data) {
            // Handle API response to update vote count
            upvoteCount.textContent = data.upvoteCount; // Replace with the actual property holding the updated vote count
          })
          .catch(function(error) {
            console.error('API Error:', error);
          });
      }, 200); // 0.2 seconds
    }

    // Attach event listeners to upvote buttons
    upvoteButtons.forEach(function(button) {
      button.addEventListener('click', handleUpvoteButtonClick);
    });

    // Check if member has upvotes on page load
    memberstack.getMemberJSON()
      .then(function(memberData) {
        if (memberData.data && memberData.data.upvotes) {
          const upvotes = memberData.data.upvotes;
          upvoteButtons.forEach(function(button) {
            const cmsId = button.getAttribute('data-cms-id');
            if (upvotes.includes(cmsId)) {
              button.classList.add('is-true');
              const form = button.closest('form');
              const upvotedValue = form.querySelector('[ms-code="upvoted-value"]');
              upvotedValue.value = 'true';
            }
          });
        }
      })
      .catch(function(error) {
        console.error('Error retrieving member data:', error);
      });
  });
</script>
Voir le Memberscript
Visibilité conditionnelle

#61 - Affichage de l'élément si la case est cochée

Créer une visibilité conditionnelle basée sur un champ de type case à cocher.


<!-- 💙 MEMBERSCRIPT #61 v0.1 💙 SHOW ELEMENT IF CHECKBOX IS CHECKED -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script>
$(document).ready(function() {
    // Initially hide all elements with the 'ms-code-checkbox-display' attribute
    $("[ms-code-checkbox-display]").hide();

    // When a checkbox with 'ms-code-checkbox-input' attribute is clicked, perform the following
    $("[ms-code-checkbox-input]").click(function() {
        // Get the value of the 'ms-code-checkbox-input' attribute
        var checkboxVal = $(this).attr('ms-code-checkbox-input');
        
        // Find the corresponding element with the 'ms-code-checkbox-display' attribute and same value
        var displayElement = $("[ms-code-checkbox-display=" + checkboxVal + "]");

        // If this checkbox is checked, show the corresponding element
        if ($(this).is(":checked")) {
            displayElement.show();
        } else {
            // If this checkbox is unchecked, hide the corresponding element
            displayElement.hide();
        }
    });
});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #61 v0.1 💙 SHOW ELEMENT IF CHECKBOX IS CHECKED -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script>
$(document).ready(function() {
    // Initially hide all elements with the 'ms-code-checkbox-display' attribute
    $("[ms-code-checkbox-display]").hide();

    // When a checkbox with 'ms-code-checkbox-input' attribute is clicked, perform the following
    $("[ms-code-checkbox-input]").click(function() {
        // Get the value of the 'ms-code-checkbox-input' attribute
        var checkboxVal = $(this).attr('ms-code-checkbox-input');
        
        // Find the corresponding element with the 'ms-code-checkbox-display' attribute and same value
        var displayElement = $("[ms-code-checkbox-display=" + checkboxVal + "]");

        // If this checkbox is checked, show the corresponding element
        if ($(this).is(":checked")) {
            displayElement.show();
        } else {
            // If this checkbox is unchecked, hide the corresponding element
            displayElement.hide();
        }
    });
});
</script>
Voir le Memberscript
Champs personnalisés
UX

#60 - Augmentation/diminution de la valeur de sélection

Créer des boutons précédent et suivant pour un champ de sélection.


<!-- 💙 MEMBERSCRIPT #60 v0.1 💙 INCREASE/DECREASE SELECT VALUE -->
<script>
    var select = document.querySelector('[ms-code-select="input"]');
    var prev = document.querySelector('[ms-code-select="prev"]');
    var next = document.querySelector('[ms-code-select="next"]');

    function updateButtons() {
        prev.style.opacity = select.selectedIndex === 0 ? '0.5' : '1';
        next.style.opacity = select.selectedIndex === select.options.length - 1 ? '0.5' : '1';
    }

    prev.addEventListener('click', function() {
        if (select.selectedIndex > 0) {
            select.selectedIndex--;
        }
        updateButtons();
    });

    next.addEventListener('click', function() {
        if (select.selectedIndex < select.options.length - 1) {
            select.selectedIndex++;
        }
        updateButtons();
    });

    updateButtons();
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #60 v0.1 💙 INCREASE/DECREASE SELECT VALUE -->
<script>
    var select = document.querySelector('[ms-code-select="input"]');
    var prev = document.querySelector('[ms-code-select="prev"]');
    var next = document.querySelector('[ms-code-select="next"]');

    function updateButtons() {
        prev.style.opacity = select.selectedIndex === 0 ? '0.5' : '1';
        next.style.opacity = select.selectedIndex === select.options.length - 1 ? '0.5' : '1';
    }

    prev.addEventListener('click', function() {
        if (select.selectedIndex > 0) {
            select.selectedIndex--;
        }
        updateButtons();
    });

    next.addEventListener('click', function() {
        if (select.selectedIndex < select.options.length - 1) {
            select.selectedIndex++;
        }
        updateButtons();
    });

    updateButtons();
</script>
Voir le Memberscript
UX
Marketing

#59 - Redémarrer le GIF au survol de la page

Commencer un GIF depuis le début au survol de la page.


<!-- 💙 MEMBERSCRIPT #59 v0.1 💙 RESTART GIF -->
<script>
    document.addEventListener('DOMContentLoaded', (event) => {
        const hoverElements = document.querySelectorAll('[data-gif-hover]');
        hoverElements.forEach((element) => {
            element.addEventListener('mouseover', function() {
                const gifNum = this.getAttribute('data-gif-hover');
                const gifElement = document.querySelector(`[data-gif="${gifNum}"]`);
                if (gifElement) {
                    const gifSrc = gifElement.getAttribute('src');
                    gifElement.setAttribute('src', '');
                    gifElement.setAttribute('src', gifSrc);
                }
            });
        });
    });
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #59 v0.1 💙 RESTART GIF -->
<script>
    document.addEventListener('DOMContentLoaded', (event) => {
        const hoverElements = document.querySelectorAll('[data-gif-hover]');
        hoverElements.forEach((element) => {
            element.addEventListener('mouseover', function() {
                const gifNum = this.getAttribute('data-gif-hover');
                const gifElement = document.querySelector(`[data-gif="${gifNum}"]`);
                if (gifElement) {
                    const gifSrc = gifElement.getAttribute('src');
                    gifElement.setAttribute('src', '');
                    gifElement.setAttribute('src', gifSrc);
                }
            });
        });
    });
</script>
Voir le Memberscript
Champs personnalisés
UX

#58 - Entrées du curseur de gamme de prix

Créez une entrée de fourchette de prix avec des entrées individuelles pour le minimum et le maximum.


<!-- 💙 MEMBERSCRIPT #58 v0.1 💙 RANGE SLIDER INPUT -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/js/ion.rangeSlider.min.js"></script>
<style>
    .irs {
      font-family: inherit;
    }
</style>
<script>
    $(document).ready(function() {
        var rangeSlider = $('[ms-code-input="range-slider"]');
        var priceFromInput = $('[ms-code-input="price-from"]');
        var priceToInput = $('[ms-code-input="price-to"]');
        
        // Set the default range values
        var defaultFrom = 20000;
        var defaultTo = 50000;

        rangeSlider.ionRangeSlider({
            skin: "round", // You can also try "flat", "big", "modern", "sharp", or "square". Default styles can be overridden with CSS.
            type: "double",
            grid: true,
            min: 0,
            max: 100000,
            from: defaultFrom,
            to: defaultTo,
            prefix: "$",
            onStart: function(data) {
                priceFromInput.val(data.from);
                priceToInput.val(data.to);
            },
            onChange: function(data) {
                priceFromInput.val(data.from);
                priceToInput.val(data.to);
            }
        });

        // Get the initial range values and update the inputs
        var initialRange = rangeSlider.data("ionRangeSlider");
        var initialData = initialRange.result;
        priceFromInput.val(initialData.from);
        priceToInput.val(initialData.to);

        // Update the range slider and inputs when the inputs lose focus
        priceFromInput.on("blur", function() {
            var value = $(this).val();
            var toValue = priceToInput.val();
            
            // Perform validation
            if (
                value < initialRange.options.min ||
                value > initialRange.options.max ||
                value >= toValue ||
                value > initialData.to // Check if fromValue is higher than the current toValue
            ) {
                value = defaultFrom;
            }

            rangeSlider.data("ionRangeSlider").update({
                from: value
            });
            priceFromInput.val(value);
        });

        priceToInput.on("blur", function() {
            var value = $(this).val();
            var fromValue = priceFromInput.val();
            
            // Perform validation
            if (
                value < initialRange.options.min ||
                value > initialRange.options.max ||
                value <= fromValue ||
                value < initialData.from // Check if toValue is lower than the current fromValue
            ) {
                value = defaultTo;
            }

            rangeSlider.data("ionRangeSlider").update({
                to: value
            });
            priceToInput.val(value);
        });
    });
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #58 v0.1 💙 RANGE SLIDER INPUT -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/css/ion.rangeSlider.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.3.1/js/ion.rangeSlider.min.js"></script>
<style>
    .irs {
      font-family: inherit;
    }
</style>
<script>
    $(document).ready(function() {
        var rangeSlider = $('[ms-code-input="range-slider"]');
        var priceFromInput = $('[ms-code-input="price-from"]');
        var priceToInput = $('[ms-code-input="price-to"]');
        
        // Set the default range values
        var defaultFrom = 20000;
        var defaultTo = 50000;

        rangeSlider.ionRangeSlider({
            skin: "round", // You can also try "flat", "big", "modern", "sharp", or "square". Default styles can be overridden with CSS.
            type: "double",
            grid: true,
            min: 0,
            max: 100000,
            from: defaultFrom,
            to: defaultTo,
            prefix: "$",
            onStart: function(data) {
                priceFromInput.val(data.from);
                priceToInput.val(data.to);
            },
            onChange: function(data) {
                priceFromInput.val(data.from);
                priceToInput.val(data.to);
            }
        });

        // Get the initial range values and update the inputs
        var initialRange = rangeSlider.data("ionRangeSlider");
        var initialData = initialRange.result;
        priceFromInput.val(initialData.from);
        priceToInput.val(initialData.to);

        // Update the range slider and inputs when the inputs lose focus
        priceFromInput.on("blur", function() {
            var value = $(this).val();
            var toValue = priceToInput.val();
            
            // Perform validation
            if (
                value < initialRange.options.min ||
                value > initialRange.options.max ||
                value >= toValue ||
                value > initialData.to // Check if fromValue is higher than the current toValue
            ) {
                value = defaultFrom;
            }

            rangeSlider.data("ionRangeSlider").update({
                from: value
            });
            priceFromInput.val(value);
        });

        priceToInput.on("blur", function() {
            var value = $(this).val();
            var fromValue = priceFromInput.val();
            
            // Perform validation
            if (
                value < initialRange.options.min ||
                value > initialRange.options.max ||
                value <= fromValue ||
                value < initialData.from // Check if toValue is lower than the current fromValue
            ) {
                value = defaultTo;
            }

            rangeSlider.data("ionRangeSlider").update({
                to: value
            });
            priceToInput.val(value);
        });
    });
</script>
Voir le Memberscript
Champs personnalisés

#57 - Saisie de l'heure

Ajoutez un sélecteur de temps à votre formulaire et pré-remplissez l'heure dans un champ.


<!-- 💙 MEMBERSCRIPT #57 v0.1 💙 TIME PICKER -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<link rel="stylesheet" href="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.css">
<script src="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.js"> </script>
<script>
$(document).ready(function() {
    var tpSpinbox = new tui.TimePicker(document.querySelector('[ms-code-timepicker="box"]'), {
        inputType: 'spinbox',
        showMeridiem: true // If you don't use AM/PM remove this line
    });

    // Setup an event handler for when the time is selected
    tpSpinbox.on('change', function() {
        // Get the selected time
        var hour = tpSpinbox.getHour();
        var minute = tpSpinbox.getMinute();

        var selectedTime = hour + ':' + (minute < 10 ? '0' : '') + minute;

        // Update the value of the input element
        document.querySelector('[ms-code-timepicker="input"]').value = selectedTime;
    });
});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #57 v0.1 💙 TIME PICKER -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<link rel="stylesheet" href="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.css">
<script src="https://uicdn.toast.com/tui.time-picker/latest/tui-time-picker.js"> </script>
<script>
$(document).ready(function() {
    var tpSpinbox = new tui.TimePicker(document.querySelector('[ms-code-timepicker="box"]'), {
        inputType: 'spinbox',
        showMeridiem: true // If you don't use AM/PM remove this line
    });

    // Setup an event handler for when the time is selected
    tpSpinbox.on('change', function() {
        // Get the selected time
        var hour = tpSpinbox.getHour();
        var minute = tpSpinbox.getMinute();

        var selectedTime = hour + ':' + (minute < 10 ? '0' : '') + minute;

        // Update the value of the input element
        document.querySelector('[ms-code-timepicker="input"]').value = selectedTime;
    });
});
</script>
Voir le Memberscript
Champs personnalisés

#56 - Paires d'options d'entrée

Combinez les valeurs de plusieurs entrées dans un seul champ.


<!-- 💙 MEMBERSCRIPT #56 v0.1 💙 INPUT OPTION PAIRS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script>
$(document).ready(function() {
    var groups = {};

    // Get all inputs with the attribute ms-code-combine-inputs
    var inputs = $('input[ms-code-combine-inputs], select[ms-code-combine-inputs]');

    // For each input
    inputs.each(function() {
        // Split the attribute value at the dash
        var parts = $(this).attr('ms-code-combine-inputs').split('-');

        // If the group doesn't exist yet, create it
        if (!groups[parts[0]]) {
            groups[parts[0]] = {
                targets: [],
                values: [],
            };
        }

        // If it's a target, add it to the targets
        if (parts[1] == 'target') {
            groups[parts[0]].targets.push($(this));
        } else {
            // It's an input, add it to the values and attach a listener
            groups[parts[0]].values.push($(this));

            $(this).on('input change', function() {
                // On input or change, combine all values with a space in between
                // and set the targets' value
                var combinedValue = '';
                $.each(groups[parts[0]].values, function(index, value) {
                    combinedValue += $(this).val();
                    if (index < groups[parts[0]].values.length - 1) {
                        combinedValue += ' '; // Add a space between values
                    }
                });

                $.each(groups[parts[0]].targets, function() {
                    $(this).val(combinedValue);
                });
            });
        }
    });
});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #56 v0.1 💙 INPUT OPTION PAIRS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script>
$(document).ready(function() {
    var groups = {};

    // Get all inputs with the attribute ms-code-combine-inputs
    var inputs = $('input[ms-code-combine-inputs], select[ms-code-combine-inputs]');

    // For each input
    inputs.each(function() {
        // Split the attribute value at the dash
        var parts = $(this).attr('ms-code-combine-inputs').split('-');

        // If the group doesn't exist yet, create it
        if (!groups[parts[0]]) {
            groups[parts[0]] = {
                targets: [],
                values: [],
            };
        }

        // If it's a target, add it to the targets
        if (parts[1] == 'target') {
            groups[parts[0]].targets.push($(this));
        } else {
            // It's an input, add it to the values and attach a listener
            groups[parts[0]].values.push($(this));

            $(this).on('input change', function() {
                // On input or change, combine all values with a space in between
                // and set the targets' value
                var combinedValue = '';
                $.each(groups[parts[0]].values, function(index, value) {
                    combinedValue += $(this).val();
                    if (index < groups[parts[0]].values.length - 1) {
                        combinedValue += ' '; // Add a space between values
                    }
                });

                $.each(groups[parts[0]].targets, function() {
                    $(this).val(combinedValue);
                });
            });
        }
    });
});
</script>
Voir le Memberscript
Champs personnalisés

#55 - Modifier le style des cases à cocher

Modifier les styles d'un autre élément lorsqu'une case est cochée.


<!-- 💙 MEMBERSCRIPT #55 v0.1 💙 UPDATE CHECKBOX PARENT STYLES -->
<script>
// Wait for the DOM content to load
document.addEventListener('DOMContentLoaded', function() {
  // Get all the checkbox elements
  var checkboxes = document.querySelectorAll('[ms-code-checkbox="check"]');

  // Iterate over each checkbox element
  checkboxes.forEach(function(checkbox) {
    // Get the boolean wrap element associated with the current checkbox
    var booleanWrap = checkbox.closest('[ms-code-checkbox="wrap"]');

    // Function to update the boolean wrap class based on checkbox state
    function updateBooleanWrapClass() {
      if (checkbox.checked) {
        booleanWrap.classList.add('checked');
      } else {
        booleanWrap.classList.remove('checked');
      }
    }

    // Check the initial value of the checkbox
    updateBooleanWrapClass();

    // Add an event listener to the checkbox to handle changes
    checkbox.addEventListener('change', function() {
      updateBooleanWrapClass();
    });
  });
});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #55 v0.1 💙 UPDATE CHECKBOX PARENT STYLES -->
<script>
// Wait for the DOM content to load
document.addEventListener('DOMContentLoaded', function() {
  // Get all the checkbox elements
  var checkboxes = document.querySelectorAll('[ms-code-checkbox="check"]');

  // Iterate over each checkbox element
  checkboxes.forEach(function(checkbox) {
    // Get the boolean wrap element associated with the current checkbox
    var booleanWrap = checkbox.closest('[ms-code-checkbox="wrap"]');

    // Function to update the boolean wrap class based on checkbox state
    function updateBooleanWrapClass() {
      if (checkbox.checked) {
        booleanWrap.classList.add('checked');
      } else {
        booleanWrap.classList.remove('checked');
      }
    }

    // Check the initial value of the checkbox
    updateBooleanWrapClass();

    // Add an event listener to the checkbox to handle changes
    checkbox.addEventListener('change', function() {
      updateBooleanWrapClass();
    });
  });
});
</script>
Voir le Memberscript
Champs personnalisés
UX

#54 - Logique des champs de formulaire à cases à cocher

Bloquer d'autres champs/éléments si une case n'est pas cochée.


<!-- 💙 MEMBERSCRIPT #54 v0.1 💙 CHECKBOX FIELD FORM LOGIC -->
<style>
  .disabled {
    pointer-events: none;
    opacity: 0.5;
  }
</style>
<script>
// Wait for the DOM content to load
document.addEventListener('DOMContentLoaded', function() {
  // Get all the trigger checkboxes
  var triggerCheckboxes = document.querySelectorAll('[ms-code-field-logic-trigger]');

  // Iterate over each trigger checkbox
  triggerCheckboxes.forEach(function(checkbox) {
    // Get the value of the trigger checkbox's attribute
    var triggerValue = checkbox.getAttribute('ms-code-field-logic-trigger');

    // Function to update the target elements' class based on checkbox state
    function updateTargetElementsClass() {
      // Find the associated target elements based on the attribute value
      var targetElements = document.querySelectorAll('[ms-code-field-logic-target="' + triggerValue + '"]');

      // Check the new value of the trigger checkbox
      if (!checkbox.checked) {
        // Add the "disabled" class to each target element
        targetElements.forEach(function(targetElement) {
          targetElement.classList.add('disabled');
        });
      } else {
        // Remove the "disabled" class from each target element
        targetElements.forEach(function(targetElement) {
          targetElement.classList.remove('disabled');
        });
      }
    }

    // Check the initial value of the trigger checkbox
    updateTargetElementsClass();

    // Add an event listener to the trigger checkbox to handle changes
    checkbox.addEventListener('change', function() {
      updateTargetElementsClass();
    });
  });
});
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #54 v0.1 💙 CHECKBOX FIELD FORM LOGIC -->
<style>
  .disabled {
    pointer-events: none;
    opacity: 0.5;
  }
</style>
<script>
// Wait for the DOM content to load
document.addEventListener('DOMContentLoaded', function() {
  // Get all the trigger checkboxes
  var triggerCheckboxes = document.querySelectorAll('[ms-code-field-logic-trigger]');

  // Iterate over each trigger checkbox
  triggerCheckboxes.forEach(function(checkbox) {
    // Get the value of the trigger checkbox's attribute
    var triggerValue = checkbox.getAttribute('ms-code-field-logic-trigger');

    // Function to update the target elements' class based on checkbox state
    function updateTargetElementsClass() {
      // Find the associated target elements based on the attribute value
      var targetElements = document.querySelectorAll('[ms-code-field-logic-target="' + triggerValue + '"]');

      // Check the new value of the trigger checkbox
      if (!checkbox.checked) {
        // Add the "disabled" class to each target element
        targetElements.forEach(function(targetElement) {
          targetElement.classList.add('disabled');
        });
      } else {
        // Remove the "disabled" class from each target element
        targetElements.forEach(function(targetElement) {
          targetElement.classList.remove('disabled');
        });
      }
    }

    // Check the initial value of the trigger checkbox
    updateTargetElementsClass();

    // Add an event listener to the trigger checkbox to handle changes
    checkbox.addEventListener('change', function() {
      updateTargetElementsClass();
    });
  });
});
</script>
Voir le Memberscript
JSON

#53 - Mettre à jour des éléments JSON avec un formulaire

Permettez à vos membres de modifier les détails de leurs éléments JSON.


<!-- 💙 MEMBERSCRIPT #53 v0.1 💙 UPDATE JSON ITEMS WITH A FORM -->
<script>
  document.addEventListener("DOMContentLoaded", function() {
    const memberstack = window.$memberstackDom;

    // Add click event listener to the document
    document.addEventListener("click", async function(event) {
      const target = event.target;

      // Check if the clicked element has ms-code-edit-item attribute
      const editItem = target.closest('[ms-code-edit-item="prompt"]');
      if (editItem) {
        // Get the item key from the closest ancestor element with ms-code-item-key attribute
        const key = editItem.closest('[ms-code-item-key]').getAttribute('ms-code-item-key');

        // Retrieve the current member JSON data
        const member = await memberstack.getMemberJSON();

        // SET THE TARGET - EDIT ME
        let targetObject = member.data.projects; // Update this line with the desired target location

        if (member.data && targetObject && targetObject[key]) {
          // Get the form element with the ms-code-edit-item="form" attribute
          const form = document.querySelector('form[ms-code-edit-item="form"]');

          if (form) {
            // Loop through the form fields
            for (const field of form.elements) {
              const jsonName = field.getAttribute('ms-code-json-name');
              if (jsonName && targetObject[key].hasOwnProperty(jsonName)) {
                // Pre-fill the form field with the corresponding value from the JSON item
                field.value = targetObject[key][jsonName];
              }
            }

            // Get the modal element with the ms-code-edit-item="modal" attribute
            const modal = document.querySelector('[ms-code-edit-item="modal"]');
            if (modal) {
              // Set the display property of the modal to flex
              modal.style.display = 'flex';
            }

            // Add submit event listener to the form
            form.addEventListener("submit", async function(event) {
              event.preventDefault(); // Prevent the form from submitting normally

              // Create an object to hold the updated values
              const updatedValues = {};

              // Loop through the form fields
              for (const field of form.elements) {
                const jsonName = field.getAttribute('ms-code-json-name');
                if (jsonName) {
                  // Update the corresponding value in the updatedValues object
                  updatedValues[jsonName] = field.value;
                }
              }

              // Update the target object with the new values
              targetObject[key] = { ...targetObject[key], ...updatedValues };

              // Update the member JSON using the Memberstack SDK
              await memberstack.updateMemberJSON({
                json: member.data
              });

              // Optional: Display a success message or perform any other desired action
              console.log('Member JSON updated successfully');
            });
          } else {
            console.error('Form element not found');
          }
        } else {
          console.error(`Could not find item with key: ${key}`);
        }
      }
    });
  });
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #53 v0.1 💙 UPDATE JSON ITEMS WITH A FORM -->
<script>
  document.addEventListener("DOMContentLoaded", function() {
    const memberstack = window.$memberstackDom;

    // Add click event listener to the document
    document.addEventListener("click", async function(event) {
      const target = event.target;

      // Check if the clicked element has ms-code-edit-item attribute
      const editItem = target.closest('[ms-code-edit-item="prompt"]');
      if (editItem) {
        // Get the item key from the closest ancestor element with ms-code-item-key attribute
        const key = editItem.closest('[ms-code-item-key]').getAttribute('ms-code-item-key');

        // Retrieve the current member JSON data
        const member = await memberstack.getMemberJSON();

        // SET THE TARGET - EDIT ME
        let targetObject = member.data.projects; // Update this line with the desired target location

        if (member.data && targetObject && targetObject[key]) {
          // Get the form element with the ms-code-edit-item="form" attribute
          const form = document.querySelector('form[ms-code-edit-item="form"]');

          if (form) {
            // Loop through the form fields
            for (const field of form.elements) {
              const jsonName = field.getAttribute('ms-code-json-name');
              if (jsonName && targetObject[key].hasOwnProperty(jsonName)) {
                // Pre-fill the form field with the corresponding value from the JSON item
                field.value = targetObject[key][jsonName];
              }
            }

            // Get the modal element with the ms-code-edit-item="modal" attribute
            const modal = document.querySelector('[ms-code-edit-item="modal"]');
            if (modal) {
              // Set the display property of the modal to flex
              modal.style.display = 'flex';
            }

            // Add submit event listener to the form
            form.addEventListener("submit", async function(event) {
              event.preventDefault(); // Prevent the form from submitting normally

              // Create an object to hold the updated values
              const updatedValues = {};

              // Loop through the form fields
              for (const field of form.elements) {
                const jsonName = field.getAttribute('ms-code-json-name');
                if (jsonName) {
                  // Update the corresponding value in the updatedValues object
                  updatedValues[jsonName] = field.value;
                }
              }

              // Update the target object with the new values
              targetObject[key] = { ...targetObject[key], ...updatedValues };

              // Update the member JSON using the Memberstack SDK
              await memberstack.updateMemberJSON({
                json: member.data
              });

              // Optional: Display a success message or perform any other desired action
              console.log('Member JSON updated successfully');
            });
          } else {
            console.error('Form element not found');
          }
        } else {
          console.error(`Could not find item with key: ${key}`);
        }
      }
    });
  });
</script>
Voir le Memberscript
UX

#52 - Redirection de page retardée

Rediriger les membres vers une nouvelle page avec un délai facultatif.


<!-- 💙 MEMBERSCRIPT #52 v0.1 💙 DELAYED REDIRECT TO NEW PAGE -->
<script>
  const redirectToNewPage = function() {
    setTimeout(function() {
      window.location.href = "/your-page";
    }, 1000); // Delay in milliseconds
  };

  redirectToNewPage();
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #52 v0.1 💙 DELAYED REDIRECT TO NEW PAGE -->
<script>
  const redirectToNewPage = function() {
    setTimeout(function() {
      window.location.href = "/your-page";
    }, 1000); // Delay in milliseconds
  };

  redirectToNewPage();
</script>
Voir le Memberscript
UX

#51 - Afficher les métadonnées des membres

Affichez les métadonnées des membres de manière dynamique sur votre site web.


<!-- 💙 MEMBERSCRIPT #51 v0.2 💙 DISPLAY MEMBER METADATA -->
<script>
  function replaceTextWithMetadata(metadata) {
    var els = Array.from(document.querySelectorAll('[ms-code-member-meta]'));
    els.forEach((el) => {
      const key = el.getAttribute('ms-code-member-meta');
      const value = metadata[key];
      if (value !== undefined) {
        el.innerHTML = value;
        el.value = value;
        el.src = value;
      }
    });
  }

  const memberstack = window.$memberstackDom;
  memberstack.getCurrentMember()
    .then(({ data: member }) => {
      if (member && member.metaData) {
        replaceTextWithMetadata(member.metaData);
      }
    })
    .catch((error) => {
      console.error('Error retrieving member data:', error);
    });
</script>
v0.2

<!-- 💙 MEMBERSCRIPT #51 v0.2 💙 DISPLAY MEMBER METADATA -->
<script>
  function replaceTextWithMetadata(metadata) {
    var els = Array.from(document.querySelectorAll('[ms-code-member-meta]'));
    els.forEach((el) => {
      const key = el.getAttribute('ms-code-member-meta');
      const value = metadata[key];
      if (value !== undefined) {
        el.innerHTML = value;
        el.value = value;
        el.src = value;
      }
    });
  }

  const memberstack = window.$memberstackDom;
  memberstack.getCurrentMember()
    .then(({ data: member }) => {
      if (member && member.metaData) {
        replaceTextWithMetadata(member.metaData);
      }
    })
    .catch((error) => {
      console.error('Error retrieving member data:', error);
    });
</script>
Voir le Memberscript
JSON
UX

#50 - Mode sombre inter-appareils

Option de mode sombre persistant qui continue à fonctionner sur les différents appareils de vos membres.

Code de la tête

Put this in the <head> section of your site.


<!-- 💙 MEMBERSCRIPT #50 HEAD CODE v0.1 💙 CROSS-DEVICE DARK MODE -->
<script> 
  document.addEventListener('DOMContentLoaded', function() {
    const themePreference = localStorage.getItem('themePreference');
    if (themePreference === 'dark') {
      document.body.classList.add('dark');
    }
  });
</script>

Code du corps

Put this in the </body> section of your site.


<!-- 💙 MEMBERSCRIPT #50 BODY CODE v0.1 💙 CROSS-DEVICE DARK MODE -->
<script>
  document.addEventListener('DOMContentLoaded', function() {
    const darkModeToggle = document.querySelector('[ms-code-dark-mode="toggle"]');
    const bodyElement = document.querySelector('.body');

    // Function to check if theme preference is saved in member JSON
    function checkThemePreference() {
      const memberstack = window.$memberstackDom;
      memberstack.getMemberJSON()
        .then(function(memberData) {
          const themePreference = memberData.data?.themePreference;
          if (themePreference === 'dark') {
            enableDarkMode();
          } else {
            disableDarkMode();
          }
        })
        .catch(function(error) {
          console.error('Error retrieving member data:', error);
        });
    }

    // Function to enable dark mode
    function enableDarkMode() {
      darkModeToggle.classList.add('dark');
      bodyElement.classList.add('dark');
      updateThemePreference('dark');
    }

    // Function to disable dark mode
    function disableDarkMode() {
      darkModeToggle.classList.remove('dark');
      bodyElement.classList.remove('dark');
      updateThemePreference('light');
    }

    // Function to update theme preference in member JSON
    function updateThemePreference(themePreference) {
      const memberstack = window.$memberstackDom;
      memberstack.getMemberJSON()
        .then(function(memberData) {
          memberData.data = memberData.data || {};
          memberData.data.themePreference = themePreference;
          memberstack.updateMemberJSON({ json: memberData.data })
            .then(function() {
              localStorage.setItem('themePreference', themePreference);
            })
            .catch(function(error) {
              console.error('Error updating member data:', error);
            });
        })
        .catch(function(error) {
          console.error('Error retrieving member data:', error);
        });
    }

    // Event listener for dark mode toggle
    darkModeToggle.addEventListener('click', function() {
      if (darkModeToggle.classList.contains('dark')) {
        disableDarkMode();
      } else {
        enableDarkMode();
      }
    });

    // Apply transition duration and timing to all elements
    const transitionDuration = '0.0s';
    const transitionTiming = 'ease';
    const elementsToTransition = [darkModeToggle, bodyElement];
    elementsToTransition.forEach(function(element) {
      element.style.transitionDuration = transitionDuration;
      element.style.transitionTimingFunction = transitionTiming;
    });

    // Check theme preference on page load
    const savedThemePreference = localStorage.getItem('themePreference');
    if (savedThemePreference === 'dark') {
      enableDarkMode();
    } else {
      disableDarkMode();
    }
    checkThemePreference();
  });
</script>
v0.1

Code de la tête

Put this in the <head> section of your site.


<!-- 💙 MEMBERSCRIPT #50 HEAD CODE v0.1 💙 CROSS-DEVICE DARK MODE -->
<script> 
  document.addEventListener('DOMContentLoaded', function() {
    const themePreference = localStorage.getItem('themePreference');
    if (themePreference === 'dark') {
      document.body.classList.add('dark');
    }
  });
</script>

Code du corps

Put this in the </body> section of your site.


<!-- 💙 MEMBERSCRIPT #50 BODY CODE v0.1 💙 CROSS-DEVICE DARK MODE -->
<script>
  document.addEventListener('DOMContentLoaded', function() {
    const darkModeToggle = document.querySelector('[ms-code-dark-mode="toggle"]');
    const bodyElement = document.querySelector('.body');

    // Function to check if theme preference is saved in member JSON
    function checkThemePreference() {
      const memberstack = window.$memberstackDom;
      memberstack.getMemberJSON()
        .then(function(memberData) {
          const themePreference = memberData.data?.themePreference;
          if (themePreference === 'dark') {
            enableDarkMode();
          } else {
            disableDarkMode();
          }
        })
        .catch(function(error) {
          console.error('Error retrieving member data:', error);
        });
    }

    // Function to enable dark mode
    function enableDarkMode() {
      darkModeToggle.classList.add('dark');
      bodyElement.classList.add('dark');
      updateThemePreference('dark');
    }

    // Function to disable dark mode
    function disableDarkMode() {
      darkModeToggle.classList.remove('dark');
      bodyElement.classList.remove('dark');
      updateThemePreference('light');
    }

    // Function to update theme preference in member JSON
    function updateThemePreference(themePreference) {
      const memberstack = window.$memberstackDom;
      memberstack.getMemberJSON()
        .then(function(memberData) {
          memberData.data = memberData.data || {};
          memberData.data.themePreference = themePreference;
          memberstack.updateMemberJSON({ json: memberData.data })
            .then(function() {
              localStorage.setItem('themePreference', themePreference);
            })
            .catch(function(error) {
              console.error('Error updating member data:', error);
            });
        })
        .catch(function(error) {
          console.error('Error retrieving member data:', error);
        });
    }

    // Event listener for dark mode toggle
    darkModeToggle.addEventListener('click', function() {
      if (darkModeToggle.classList.contains('dark')) {
        disableDarkMode();
      } else {
        enableDarkMode();
      }
    });

    // Apply transition duration and timing to all elements
    const transitionDuration = '0.0s';
    const transitionTiming = 'ease';
    const elementsToTransition = [darkModeToggle, bodyElement];
    elementsToTransition.forEach(function(element) {
      element.style.transitionDuration = transitionDuration;
      element.style.transitionTimingFunction = transitionTiming;
    });

    // Check theme preference on page load
    const savedThemePreference = localStorage.getItem('themePreference');
    if (savedThemePreference === 'dark') {
      enableDarkMode();
    } else {
      disableDarkMode();
    }
    checkThemePreference();
  });
</script>
Voir le Memberscript
Champs personnalisés
UX

#49 - Désactiver la première option d'une entrée de sélection

Empêchez les utilisateurs de sélectionner l'option de remplacement dans vos entrées de sélection.


<!-- 💙 MEMBERSCRIPT #49 v0.1 💙 DISABLE FIRST OPTION IN SELECT INPUT -->
<script>
    let selects = document.querySelectorAll("select[ms-code=hide-first-option]");
    selects.forEach((select) => { 
        let options = select.getElementsByTagName("option");
        options[0].hidden = true;
    });
</script>
v0.1

<!-- 💙 MEMBERSCRIPT #49 v0.1 💙 DISABLE FIRST OPTION IN SELECT INPUT -->
<script>
    let selects = document.querySelectorAll("select[ms-code=hide-first-option]");
    selects.forEach((select) => { 
        let options = select.getElementsByTagName("option");
        options[0].hidden = true;
    });
</script>
Voir le Memberscript
Champs personnalisés
UX

#48 - Autocomplétion des entrées d'adresses

Pré-remplir toutes les entrées d'adresse à l'aide de l'API Google Places !

Code de la tête

Place this in your page <head>


<!-- 💙 MEMBERSCRIPT #48 HEAD CODE v0.1 💙 AUTOFILL ADDRESS INPUTS -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR-API-KEY&libraries=places&callback=initAutocomplete" async defer> </script>
<style>
.pac-logo::after {
display: none;
}
.pac-container {
border-radius: 5px;
border: 1px solid #ccc;
}
.pac-item {
padding: 0 10px;
}
</style>

Code du corps

Place this in your page </body>


<!-- 💙 MEMBERSCRIPT #48 BODY CODE v0.1 💙 AUTOFILL ADDRESS INPUTS -->
<script>
let autocomplete;

function initAutocomplete() {
  autocomplete = new google.maps.places.Autocomplete(
    document.querySelector('input[ms-code-input="address"]'),
    {
      componentRestrictions: { country: ['US'] },
      fields: ['address_components'],
      types: ['address']
    }
  );

  autocomplete.addListener('place_changed', function() {
    const place = autocomplete.getPlace();

    if (place) {
      const addressInput = document.querySelector('input[ms-code-input="address"]');
      const cityInput = document.querySelector('input[ms-code-input="city"]');
      const regionInput = document.querySelector('input[ms-code-input="region"]');
      const countryInput = document.querySelector('input[ms-code-input="country"]');
      const postalCodeInput = document.querySelector('input[ms-code-input="postal-code"]');

      addressInput.value = extractAddress(place);
      cityInput.value = extractCity(place);
      regionInput.value = extractRegion(place);
      countryInput.value = extractCountry(place);
      postalCodeInput.value = extractPostalCode(place);
    }
  });
}

function extractAddress(place) {
  let address = '';
  const streetNumber = extractComponent(place, 'street_number');
  const route = extractComponent(place, 'route');

  if (streetNumber) {
    address += streetNumber + ' ';
  }
  if (route) {
    address += route;
  }

  return address.trim();
}

function extractComponent(place, componentType) {
  for (const component of place.address_components) {
    if (component.types.includes(componentType)) {
      return component.long_name;
    }
  }
  return '';
}

function extractCity(place) {
  for (const component of place.address_components) {
    if (component.types.includes('locality')) {
      return component.long_name;
    }
  }
  return '';
}

function extractRegion(place) {
  for (const component of place.address_components) {
    if (component.types.includes('administrative_area_level_1')) {
      return component.long_name;
    }
  }
  return '';
}

function extractCountry(place) {
  for (const component of place.address_components) {
    if (component.types.includes('country')) {
      return component.long_name;
    }
  }
  return '';
}

function extractPostalCode(place) {
  for (const component of place.address_components) {
    if (component.types.includes('postal_code')) {
      return component.long_name;
    }
  }
  return '';
}
</script>
v0.1

Code de la tête

Place this in your page <head>


<!-- 💙 MEMBERSCRIPT #48 HEAD CODE v0.1 💙 AUTOFILL ADDRESS INPUTS -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR-API-KEY&libraries=places&callback=initAutocomplete" async defer> </script>
<style>
.pac-logo::after {
display: none;
}
.pac-container {
border-radius: 5px;
border: 1px solid #ccc;
}
.pac-item {
padding: 0 10px;
}
</style>

Code du corps

Place this in your page </body>


<!-- 💙 MEMBERSCRIPT #48 BODY CODE v0.1 💙 AUTOFILL ADDRESS INPUTS -->
<script>
let autocomplete;

function initAutocomplete() {
  autocomplete = new google.maps.places.Autocomplete(
    document.querySelector('input[ms-code-input="address"]'),
    {
      componentRestrictions: { country: ['US'] },
      fields: ['address_components'],
      types: ['address']
    }
  );

  autocomplete.addListener('place_changed', function() {
    const place = autocomplete.getPlace();

    if (place) {
      const addressInput = document.querySelector('input[ms-code-input="address"]');
      const cityInput = document.querySelector('input[ms-code-input="city"]');
      const regionInput = document.querySelector('input[ms-code-input="region"]');
      const countryInput = document.querySelector('input[ms-code-input="country"]');
      const postalCodeInput = document.querySelector('input[ms-code-input="postal-code"]');

      addressInput.value = extractAddress(place);
      cityInput.value = extractCity(place);
      regionInput.value = extractRegion(place);
      countryInput.value = extractCountry(place);
      postalCodeInput.value = extractPostalCode(place);
    }
  });
}

function extractAddress(place) {
  let address = '';
  const streetNumber = extractComponent(place, 'street_number');
  const route = extractComponent(place, 'route');

  if (streetNumber) {
    address += streetNumber + ' ';
  }
  if (route) {
    address += route;
  }

  return address.trim();
}

function extractComponent(place, componentType) {
  for (const component of place.address_components) {
    if (component.types.includes(componentType)) {
      return component.long_name;
    }
  }
  return '';
}

function extractCity(place) {
  for (const component of place.address_components) {
    if (component.types.includes('locality')) {
      return component.long_name;
    }
  }
  return '';
}

function extractRegion(place) {
  for (const component of place.address_components) {
    if (component.types.includes('administrative_area_level_1')) {
      return component.long_name;
    }
  }
  return '';
}

function extractCountry(place) {
  for (const component of place.address_components) {
    if (component.types.includes('country')) {
      return component.long_name;
    }
  }
  return '';
}

function extractPostalCode(place) {
  for (const component of place.address_components) {
    if (component.types.includes('postal_code')) {
      return component.long_name;
    }
  }
  return '';
}
</script>
Voir le Memberscript
Nous n'avons pas trouvé de scripts pour cette recherche... veuillez réessayer.
Slack

Besoin d'aide avec MemberScripts ? Rejoignez notre communauté Slack de plus de 5 500 membres ! 🙌

Les MemberScripts sont une ressource communautaire de Memberstack - si vous avez besoin d'aide pour les faire fonctionner avec votre projet, rejoignez le Slack de Memberstack 2.0 et demandez de l'aide !

Rejoignez notre Slack
Vitrine

Découvrez les entreprises qui ont réussi avec Memberstack

Ne vous contentez pas de nous croire sur parole, consultez les entreprises de toutes tailles qui font confiance à Memberstack pour leur authentification et leurs paiements.

Voir tous les exemples de réussite
Même Webflow utilise Memberstack !
Commencer à construire

Commencez à construire vos rêves

Memberstack est 100% gratuit jusqu'à ce que vous soyez prêt à vous lancer - alors, qu'attendez-vous ? Créez votre première application et commencez à construire dès aujourd'hui.