Mitglieder-Skripte
Eine attributbasierte Lösung zum Hinzufügen von Funktionen zu Ihrer Webflow-Site.
Kopieren Sie einfach etwas Code, fügen Sie einige Attribute hinzu, und schon sind Sie fertig.
Alle Memberstack-Kunden können im 2.0 Slack um Unterstützung bitten. Bitte beachten Sie, dass dies keine offiziellen Funktionen sind und der Support nicht garantiert werden kann.

#Nr. 58 - Eingaben für Preisspannenschieber
Erstellen Sie eine Preisspanneneingabe mit individuellen Eingaben für Minimum und 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>
<!-- 💙 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>

#Nr. 57 - Time Picker Eingabe
Fügen Sie eine Zeitauswahl zu Ihrem Formular hinzu und füllen Sie die Zeit in einem Feld vor.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 56 - Eingabe von Optionspaaren
Kombinieren Sie die Werte von mehreren Eingaben in einem Feld.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 55 - Ändern der Stile für übergeordnete Kontrollkästchen
Ändern Sie die Stile eines anderen Elements, wenn ein Kontrollkästchen markiert ist.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 54 - Logik der Checkbox-Formularfelder
Andere Felder/Einträge blockieren, wenn ein Kontrollkästchen nicht markiert ist.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 53 - JSON-Elemente mit einem Formular aktualisieren
Erlauben Sie Ihren Mitgliedern, Details über ihre JSON-Elemente zu ändern.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 52 - Verzögerte Seitenumleitung
Leiten Sie die Mitglieder mit einer optionalen Verzögerung auf eine neue Seite um.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 51 - Metadaten der Mitglieder anzeigen
Zeigen Sie die Metadaten der Mitglieder dynamisch auf Ihrer Website an.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 50 - Geräteübergreifender Dunkelmodus
Dauerhafte Dunkelmodus-Option, die auf den verschiedenen Geräten Ihrer Mitglieder funktioniert.
Kopf-Code
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 der Einrichtung
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>
Kopf-Code
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 der Einrichtung
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>

#Nr. 49 - Erste Option in einer Auswahleingabe deaktivieren
Verhindern Sie, dass Benutzer die Platzhalteroption in Ihren Auswahleingaben auswählen.
<!-- 💙 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>
<!-- 💙 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>

#Nr. 48 - Autovervollständigung von Adresseingaben
Füllen Sie alle Adresseingaben mit der Google Places API aus!
Kopf-Code
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 der Einrichtung
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>
Kopf-Code
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 der Einrichtung
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>

#Nr. 47 - Anzeige des Datums vom Mitglied JSON
Zeigen Sie den Mitgliedern ein Datum an - zum Beispiel, wann ihr Plan abläuft!
<!-- 💙 MEMBERSCRIPT #47 v0.1 💙 DISPLAY ONE TIME DATE -->
<script>
document.addEventListener("DOMContentLoaded", async function() {
const memberstack = window.$memberstackDom;
const formatDate = function(date) {
const options = { month: 'long', day: 'numeric', year: 'numeric' };
return new Date(date).toLocaleDateString('en-US', options);
// Replace 'en-US' with one of these depending on your locale: en-US, en-GB, en-CA, en-AU, fr-FR, de-DE, es-ES, it-IT, ja-JP, ko-KR, pt-BR, ru-RU, zn-CH, ar-SA
};
const updateTextSpans = async function() {
const member = await memberstack.getMemberJSON();
if (!member.data || !member.data['one-time-date']) {
// Member data or one-time date not available, do nothing
return;
}
const oneTimeDate = formatDate(member.data['one-time-date']);
const textSpans = document.querySelectorAll('[ms-code-display-text="one-time-date"]');
textSpans.forEach(span => {
span.textContent = oneTimeDate;
});
};
updateTextSpans();
});
</script>
<!-- 💙 MEMBERSCRIPT #47 v0.1 💙 DISPLAY ONE TIME DATE -->
<script>
document.addEventListener("DOMContentLoaded", async function() {
const memberstack = window.$memberstackDom;
const formatDate = function(date) {
const options = { month: 'long', day: 'numeric', year: 'numeric' };
return new Date(date).toLocaleDateString('en-US', options);
// Replace 'en-US' with one of these depending on your locale: en-US, en-GB, en-CA, en-AU, fr-FR, de-DE, es-ES, it-IT, ja-JP, ko-KR, pt-BR, ru-RU, zn-CH, ar-SA
};
const updateTextSpans = async function() {
const member = await memberstack.getMemberJSON();
if (!member.data || !member.data['one-time-date']) {
// Member data or one-time date not available, do nothing
return;
}
const oneTimeDate = formatDate(member.data['one-time-date']);
const textSpans = document.querySelectorAll('[ms-code-display-text="one-time-date"]');
textSpans.forEach(span => {
span.textContent = oneTimeDate;
});
};
updateTextSpans();
});
</script>

#46 - Passwort bestätigen
Fügen Sie Ihren Anmelde- und Passwortrücksetzungsformularen eine Eingabe zur Passwortbestätigung hinzu.
<!-- 💙 MEMBERSCRIPT #46 v0.1 💙 CONFIRM PASSWORD INPUT -->
<script>
var password = document.querySelector('[data-ms-member=password]')
, confirm_password = document.querySelector('[ms-code-password=confirm]')
function validatePassword(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
confirm_password.classList.add("invalid")
confirm_password.classList.remove("valid")
} else {
confirm_password.setCustomValidity('');
confirm_password.classList.remove("invalid")
confirm_password.classList.add("valid")
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
</script>
<!-- 💙 MEMBERSCRIPT #46 v0.1 💙 CONFIRM PASSWORD INPUT -->
<script>
var password = document.querySelector('[data-ms-member=password]')
, confirm_password = document.querySelector('[ms-code-password=confirm]')
function validatePassword(){
if(password.value != confirm_password.value) {
confirm_password.setCustomValidity("Passwords Don't Match");
confirm_password.classList.add("invalid")
confirm_password.classList.remove("valid")
} else {
confirm_password.setCustomValidity('');
confirm_password.classList.remove("invalid")
confirm_password.classList.add("valid")
}
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
</script>

#45 - Passwort anzeigen/verbergen
Fügen Sie jedem Formular mit einer Passworteingabe eine Schaltfläche zum Ein-/Ausblenden des Passworts hinzu.
<!-- 💙 MEMBERSCRIPT #45 v0.2 💙 SHOW AND HIDE PASSWORD -->
<script>
document.querySelectorAll("[ms-code-password='transform']").forEach(function(button) {
button.addEventListener("click", transform);
});
var isPassword = true;
function transform() {
var passwordInputs = document.querySelectorAll("[data-ms-member='password'], [data-ms-member='new-password'], [data-ms-member='current-password']");
passwordInputs.forEach(function(myInput) {
var inputType = myInput.getAttribute("type");
if (isPassword) {
myInput.setAttribute("type", "text");
} else {
myInput.setAttribute("type", "password");
}
});
isPassword = !isPassword;
}
</script>
<!-- 💙 MEMBERSCRIPT #45 v0.2 💙 SHOW AND HIDE PASSWORD -->
<script>
document.querySelectorAll("[ms-code-password='transform']").forEach(function(button) {
button.addEventListener("click", transform);
});
var isPassword = true;
function transform() {
var passwordInputs = document.querySelectorAll("[data-ms-member='password'], [data-ms-member='new-password'], [data-ms-member='current-password']");
passwordInputs.forEach(function(myInput) {
var inputType = myInput.getAttribute("type");
if (isPassword) {
myInput.setAttribute("type", "text");
} else {
myInput.setAttribute("type", "password");
}
});
isPassword = !isPassword;
}
</script>

#44 - Element anzeigen, wenn Attribut mit Mitglieds-ID übereinstimmt
Elemente bedingt anzeigen, wenn sie ein Attribut haben, das der ID der Mitglieder entspricht.
<!-- 💙 MEMBERSCRIPT #44 v0.1 💙 SHOW ELEMENT IF ATTRIBUTE MATCHES MEMBER ID -->
<script>
document.addEventListener("DOMContentLoaded", function() {
if (localStorage.getItem("_ms-mem")) {
const memberData = JSON.parse(localStorage.getItem("_ms-mem"));
const memberId = memberData.id;
const elements = document.querySelectorAll("[ms-code-member-id='" + memberId + "']");
elements.forEach(element => {
element.style.display = "block";
});
}
});
</script>
<!-- 💙 MEMBERSCRIPT #44 v0.1 💙 SHOW ELEMENT IF ATTRIBUTE MATCHES MEMBER ID -->
<script>
document.addEventListener("DOMContentLoaded", function() {
if (localStorage.getItem("_ms-mem")) {
const memberData = JSON.parse(localStorage.getItem("_ms-mem"));
const memberId = memberData.id;
const elements = document.querySelectorAll("[ms-code-member-id='" + memberId + "']");
elements.forEach(element => {
element.style.display = "block";
});
}
});
</script>

#Nr. 43 - Scrollen blockieren, wenn das Modal geöffnet ist
Beenden Sie das Scrollen der Seite, wenn jemand ein Modal öffnet.
<!-- 💙 MEMBERSCRIPT #43 v0.1 💙 BLOCK SCROLLING WHEN MODAL IS OPEN -->
<style>
.no-scroll {
overflow: hidden;
}
</style>
<script>
function isDesktopViewport() {
return window.innerWidth >= 900; // Adjust the breakpoint width as needed
}
const codeBlocks = document.querySelectorAll('[ms-code-block-scroll]');
function handleScrollBlock(event) {
if (isDesktopViewport()) {
document.body.classList.add('no-scroll');
}
}
function handleScrollUnblock(event) {
if (isDesktopViewport()) {
document.body.classList.remove('no-scroll');
}
}
codeBlocks.forEach(codeBlock => {
codeBlock.addEventListener('mouseenter', handleScrollBlock);
codeBlock.addEventListener('mouseleave', handleScrollUnblock);
});
</script>
<!-- 💙 MEMBERSCRIPT #43 v0.1 💙 BLOCK SCROLLING WHEN MODAL IS OPEN -->
<style>
.no-scroll {
overflow: hidden;
}
</style>
<script>
function isDesktopViewport() {
return window.innerWidth >= 900; // Adjust the breakpoint width as needed
}
const codeBlocks = document.querySelectorAll('[ms-code-block-scroll]');
function handleScrollBlock(event) {
if (isDesktopViewport()) {
document.body.classList.add('no-scroll');
}
}
function handleScrollUnblock(event) {
if (isDesktopViewport()) {
document.body.classList.remove('no-scroll');
}
}
codeBlocks.forEach(codeBlock => {
codeBlock.addEventListener('mouseenter', handleScrollBlock);
codeBlock.addEventListener('mouseleave', handleScrollUnblock);
});
</script>

#Nr. 42 - Bildeditor-Formularfeld
Erlauben Sie den Benutzern, Fotos hochzuladen und zu bearbeiten und sie dann an Google Drive zu senden!
Kopf-Code
Place this in your page <head>
<!-- 💙 MEMBERSCRIPT #42 HEAD CODE v0.2 💙 FILE EDITOR FEATURE -->
<link rel="stylesheet" href="https://unpkg.com/filepond@^4/dist/filepond.css" />
<link rel="stylesheet" href="https://unpkg.com/filepond-plugin-image-edit/dist/filepond-plugin-image-edit.css" />
<link rel="stylesheet" href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css" />
Code der Einrichtung
Place this in your page </body>
<!-- 💙 MEMBERSCRIPT #42 BODY CODE v0.2 💙 FILE EDITOR FEATURE -->
<script> src="https://unpkg.com/filepond-plugin-file-encode/dist/filepond-plugin-file-encode.js"> </script>
<script> src="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.js"> </script>
<script> src="https://unpkg.com/filepond-plugin-image-edit/dist/filepond-plugin-image-edit.js"> </script>
<script> src="https://unpkg.com/filepond@^4/dist/filepond.js"> </script>
<script> src="https://scaleflex.cloudimg.io/v7/plugins/filerobot-image-editor/latest/filerobot-image-editor.min.js"> </script>
<style>
.dXhZSB {
background-color: #2962ff;
}
.FIE_root * {
font-family: inherit !important;
}
.SfxModal-Wrapper * {
font-family: inherit !important;
}
.jpHEiD {
font-family: inherit !important;
}
#editor_container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 999;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Register the plugins
FilePond.registerPlugin(FilePondPluginImagePreview);
FilePond.registerPlugin(FilePondPluginImageEdit);
const inputElement = document.querySelector('input[type="file"]');
const pond = FilePond.create(inputElement, {
credits: false,
name: 'fileToUpload',
storeAsFile: true,
imageEditEditor: {
open: (file, instructions) => {
console.log('Open editor', file, instructions);
openFilerobotImageEditor(file, instructions);
},
onconfirm: (output) => {
console.log('Confirm editor', output);
handleImageEditConfirm(output);
},
oncancel: () => {
console.log('Cancel editor');
handleImageEditCancel();
},
onclose: () => {
console.log('Close editor');
handleImageEditClose();
}
}
});
function openFilerobotImageEditor(file, instructions) {
const imageURL = URL.createObjectURL(file);
const config = {
source: imageURL,
onSave: (updatedImage) => {
confirmCallback(updatedImage);
},
annotationsCommon: {
fill: '#ff0000'
},
Text: {
text: 'Add your text here',
font: 'inherit'
}, // Set font to inherit from the page body
Rotate: {
angle: instructions.rotation,
componentType: 'slider'
},
tabsIds: [
'Adjust',
'Annotate',
'Watermark'
],
defaultTabId: 'Annotate',
defaultToolId: 'Text'
};
const editorContainer = document.createElement('div');
editorContainer.id = 'editor_container';
document.body.appendChild(editorContainer);
const filerobotImageEditor = new window.FilerobotImageEditor(editorContainer, config);
const confirmCallback = (output) => {
console.log('Confirmed:', output);
const dataURL = output.imageBase64;
const file = dataURLToFile(dataURL, output.name);
// Add the file to FilePond
pond.addFiles([file]);
document.body.removeChild(editorContainer); // Remove the editor container
};
function dataURLToFile(dataURL, fileName) {
const arr = dataURL.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const fileExtension = mime.split('/')[1];
const updatedFileName = fileName + '.' + fileExtension;
const bstr = atob(arr[1]);
const n = bstr.length;
const u8arr = new Uint8Array(n);
for (let i = 0; i < n; i++) {
u8arr[i] = bstr.charCodeAt(i);
}
return new File([u8arr], updatedFileName, { type: mime });
}
const cancelCallback = () => {
console.log('Canceled');
document.body.removeChild(editorContainer); // Remove the editor container
};
const closeButton = document.createElement('button');
closeButton.textContent = 'Close';
closeButton.addEventListener('click', () => {
filerobotImageEditor.onClose();
});
const buttonContainer = document.createElement('div');
buttonContainer.appendChild(closeButton);
editorContainer.appendChild(buttonContainer);
filerobotImageEditor.render({
onClose: (closingReason) => {
console.log('Closing reason', closingReason);
filerobotImageEditor.terminate();
},
});
}
function handleImageEditConfirm(output) {
console.log('Image edit confirmed:', output);
// Handle the confirmed output here
}
function handleImageEditCancel() {
console.log('Image edit canceled');
// Handle the canceled edit here
}
function handleImageEditClose() {
console.log('Image editor closed');
// Handle the editor close here
}
});
</script>
Kopf-Code
Place this in your page <head>
<!-- 💙 MEMBERSCRIPT #42 HEAD CODE v0.2 💙 FILE EDITOR FEATURE -->
<link rel="stylesheet" href="https://unpkg.com/filepond@^4/dist/filepond.css" />
<link rel="stylesheet" href="https://unpkg.com/filepond-plugin-image-edit/dist/filepond-plugin-image-edit.css" />
<link rel="stylesheet" href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css" />
Code der Einrichtung
Place this in your page </body>
<!-- 💙 MEMBERSCRIPT #42 BODY CODE v0.2 💙 FILE EDITOR FEATURE -->
<script> src="https://unpkg.com/filepond-plugin-file-encode/dist/filepond-plugin-file-encode.js"> </script>
<script> src="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.js"> </script>
<script> src="https://unpkg.com/filepond-plugin-image-edit/dist/filepond-plugin-image-edit.js"> </script>
<script> src="https://unpkg.com/filepond@^4/dist/filepond.js"> </script>
<script> src="https://scaleflex.cloudimg.io/v7/plugins/filerobot-image-editor/latest/filerobot-image-editor.min.js"> </script>
<style>
.dXhZSB {
background-color: #2962ff;
}
.FIE_root * {
font-family: inherit !important;
}
.SfxModal-Wrapper * {
font-family: inherit !important;
}
.jpHEiD {
font-family: inherit !important;
}
#editor_container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 999;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Register the plugins
FilePond.registerPlugin(FilePondPluginImagePreview);
FilePond.registerPlugin(FilePondPluginImageEdit);
const inputElement = document.querySelector('input[type="file"]');
const pond = FilePond.create(inputElement, {
credits: false,
name: 'fileToUpload',
storeAsFile: true,
imageEditEditor: {
open: (file, instructions) => {
console.log('Open editor', file, instructions);
openFilerobotImageEditor(file, instructions);
},
onconfirm: (output) => {
console.log('Confirm editor', output);
handleImageEditConfirm(output);
},
oncancel: () => {
console.log('Cancel editor');
handleImageEditCancel();
},
onclose: () => {
console.log('Close editor');
handleImageEditClose();
}
}
});
function openFilerobotImageEditor(file, instructions) {
const imageURL = URL.createObjectURL(file);
const config = {
source: imageURL,
onSave: (updatedImage) => {
confirmCallback(updatedImage);
},
annotationsCommon: {
fill: '#ff0000'
},
Text: {
text: 'Add your text here',
font: 'inherit'
}, // Set font to inherit from the page body
Rotate: {
angle: instructions.rotation,
componentType: 'slider'
},
tabsIds: [
'Adjust',
'Annotate',
'Watermark'
],
defaultTabId: 'Annotate',
defaultToolId: 'Text'
};
const editorContainer = document.createElement('div');
editorContainer.id = 'editor_container';
document.body.appendChild(editorContainer);
const filerobotImageEditor = new window.FilerobotImageEditor(editorContainer, config);
const confirmCallback = (output) => {
console.log('Confirmed:', output);
const dataURL = output.imageBase64;
const file = dataURLToFile(dataURL, output.name);
// Add the file to FilePond
pond.addFiles([file]);
document.body.removeChild(editorContainer); // Remove the editor container
};
function dataURLToFile(dataURL, fileName) {
const arr = dataURL.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const fileExtension = mime.split('/')[1];
const updatedFileName = fileName + '.' + fileExtension;
const bstr = atob(arr[1]);
const n = bstr.length;
const u8arr = new Uint8Array(n);
for (let i = 0; i < n; i++) {
u8arr[i] = bstr.charCodeAt(i);
}
return new File([u8arr], updatedFileName, { type: mime });
}
const cancelCallback = () => {
console.log('Canceled');
document.body.removeChild(editorContainer); // Remove the editor container
};
const closeButton = document.createElement('button');
closeButton.textContent = 'Close';
closeButton.addEventListener('click', () => {
filerobotImageEditor.onClose();
});
const buttonContainer = document.createElement('div');
buttonContainer.appendChild(closeButton);
editorContainer.appendChild(buttonContainer);
filerobotImageEditor.render({
onClose: (closingReason) => {
console.log('Closing reason', closingReason);
filerobotImageEditor.terminate();
},
});
}
function handleImageEditConfirm(output) {
console.log('Image edit confirmed:', output);
// Handle the confirmed output here
}
function handleImageEditCancel() {
console.log('Image edit canceled');
// Handle the canceled edit here
}
function handleImageEditClose() {
console.log('Image editor closed');
// Handle the editor close here
}
});
</script>

#Nr. 41 - Perfekte Rufnummerneingaben
Internationale Rufnummerneingabe, so wie sie sein sollte.
Mit IP-Suche
Verwenden Sie diese Option, wenn Sie möchten, dass das IP-Land des Benutzers automatisch vorausgefüllt wird. WICHTIG: Verwenden Sie diese Option nicht in Verbindung mit Profilformularen, da sie sich sonst fehlerhaft verhält.
<!-- 💙 MEMBERSCRIPT #41 v0.2 💙 PERFECT PHONE NUMBER INPUTS (WITH IP LOOKUP) -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/css/intlTelInput.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/intlTelInput.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"> </script>
<script>
$(document).ready(function() {
$('input[ms-code-phone-number]').each(function() {
var input = this;
var preferredCountries = $(input).attr('ms-code-phone-number').split(',');
var iti = window.intlTelInput(input, {
preferredCountries: preferredCountries,
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"
});
$.get("https://ipinfo.io", function(response) {
var countryCode = response.country;
iti.setCountry(countryCode);
}, "jsonp");
input.addEventListener('change', formatPhoneNumber);
input.addEventListener('keyup', formatPhoneNumber);
function formatPhoneNumber() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
}
var form = $(input).closest('form');
form.submit(function() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
});
});
});
</script>
Ohne IP-Suche
Verwenden Sie diese Option für Profilformulare und/oder wenn Sie keine automatische Vorauswahl anhand der Benutzer-IP vornehmen möchten.
<!-- 💙 MEMBERSCRIPT #41 v0.2 💙 PERFECT PHONE NUMBER INPUTS (WITHOUT IP LOOKUP) -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/css/intlTelInput.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/intlTelInput.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"> </script>
<script>
$(document).ready(function() {
$('input[ms-code-phone-number]').each(function() {
var input = this;
var preferredCountries = $(input).attr('ms-code-phone-number').split(',');
var iti = window.intlTelInput(input, {
preferredCountries: preferredCountries,
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"
});
input.addEventListener('change', formatPhoneNumber);
input.addEventListener('keyup', formatPhoneNumber);
function formatPhoneNumber() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
}
var form = $(input).closest('form');
form.submit(function() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
});
});
});
</script>
Mit IP-Suche
Verwenden Sie diese Option, wenn Sie möchten, dass das IP-Land des Benutzers automatisch vorausgefüllt wird. WICHTIG: Verwenden Sie diese Option nicht in Verbindung mit Profilformularen, da sie sich sonst fehlerhaft verhält.
<!-- 💙 MEMBERSCRIPT #41 v0.2 💙 PERFECT PHONE NUMBER INPUTS (WITH IP LOOKUP) -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/css/intlTelInput.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/intlTelInput.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"> </script>
<script>
$(document).ready(function() {
$('input[ms-code-phone-number]').each(function() {
var input = this;
var preferredCountries = $(input).attr('ms-code-phone-number').split(',');
var iti = window.intlTelInput(input, {
preferredCountries: preferredCountries,
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"
});
$.get("https://ipinfo.io", function(response) {
var countryCode = response.country;
iti.setCountry(countryCode);
}, "jsonp");
input.addEventListener('change', formatPhoneNumber);
input.addEventListener('keyup', formatPhoneNumber);
function formatPhoneNumber() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
}
var form = $(input).closest('form');
form.submit(function() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
});
});
});
</script>
Ohne IP-Suche
Verwenden Sie diese Option für Profilformulare und/oder wenn Sie keine automatische Vorauswahl anhand der Benutzer-IP vornehmen möchten.
<!-- 💙 MEMBERSCRIPT #41 v0.2 💙 PERFECT PHONE NUMBER INPUTS (WITHOUT IP LOOKUP) -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/css/intlTelInput.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/intlTelInput.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"> </script>
<script>
$(document).ready(function() {
$('input[ms-code-phone-number]').each(function() {
var input = this;
var preferredCountries = $(input).attr('ms-code-phone-number').split(',');
var iti = window.intlTelInput(input, {
preferredCountries: preferredCountries,
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.8/js/utils.js"
});
input.addEventListener('change', formatPhoneNumber);
input.addEventListener('keyup', formatPhoneNumber);
function formatPhoneNumber() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
}
var form = $(input).closest('form');
form.submit(function() {
var formattedNumber = iti.getNumber(intlTelInputUtils.numberFormat.INTERNATIONAL);
input.value = formattedNumber;
});
});
});
</script>

#Nr. 40 - Datei-Uploader per Ziehen und Ablegen
Fügen Sie Ihrer Webflow-Website ganz einfach eine Funktion zum Hochladen von Dateien per Drag-and-Drop hinzu!
Wichtig
Wenn Sie MemberScript #38 verwenden, stellen Sie sicher, dass Sie dieses Skript NACHHER einfügen!
<!-- 💙 MEMBERSCRIPT #40 v0.1 💙 DRAG AND DROP FILE UPLOADER -->
<script> src="https://unpkg.com/filepond@^4/dist/filepond.js"> </script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const inputElement = document.querySelector('input[type="file"]');
const pond = FilePond.create(inputElement, {
credits: false,
name: 'fileToUpload',
storeAsFile: true
// for more property options, go to https://pqina.nl/filepond/docs/api/instance/properties/
});
});
</script>
Wichtig
Wenn Sie MemberScript #38 verwenden, stellen Sie sicher, dass Sie dieses Skript NACHHER einfügen!
<!-- 💙 MEMBERSCRIPT #40 v0.1 💙 DRAG AND DROP FILE UPLOADER -->
<script> src="https://unpkg.com/filepond@^4/dist/filepond.js"> </script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const inputElement = document.querySelector('input[type="file"]');
const pond = FilePond.create(inputElement, {
credits: false,
name: 'fileToUpload',
storeAsFile: true
// for more property options, go to https://pqina.nl/filepond/docs/api/instance/properties/
});
});
</script>

#Nr. 39 - Felder besser auswählen
Hinzufügen von Suchen und einer besseren Benutzeroberfläche für die Auswahl und Mehrfachauswahl von Feldern!
Kopf-Code
Put this in the <head> section of your page.
<!-- 💙 MEMBERSCRIPT #39 v0.1 HEAD CODE 💙 BETTER SELECT FIELDS -->
<script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"> </script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" />
Code der Einrichtung
Put this in the </body> section of your page.
<!-- 💙 MEMBERSCRIPT #39 v0.1 BODY CODE 💙 BETTER SELECT FIELDS -->
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"> </script>
<script>
$(document).ready(function() {
$('[ms-code-custom-select="select-with-search"]').select2();
});
</script>
Kopf-Code
Put this in the <head> section of your page.
<!-- 💙 MEMBERSCRIPT #39 v0.1 HEAD CODE 💙 BETTER SELECT FIELDS -->
<script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"> </script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" />
Code der Einrichtung
Put this in the </body> section of your page.
<!-- 💙 MEMBERSCRIPT #39 v0.1 BODY CODE 💙 BETTER SELECT FIELDS -->
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"> </script>
<script>
$(document).ready(function() {
$('[ms-code-custom-select="select-with-search"]').select2();
});
</script>
Mitglieder-Skripte
Instantly add custom features to your Webflow site.
Just paste a script, set attributes, and go live.
Join the Memberstack 2.0 Slack for tips, answers, and community scripts. Please note that these are not official features and support cannot be guaranteed.

#Nr. 138 - Anker Link Scroll Offset
Behebung des Problems mit Ankerlinks und klebrigen/fixierten Navigationsleisten in Webflow.
<!-- 💙 MEMBERSCRIPT #138 v0.1 💙 - ANCHOR LINK SCROLL OFFSET -->
<script>
// Disable Webflow's built-in smooth scrolling
var Webflow = Webflow || [];
Webflow.push(function() {
$(function() {
$(document).off('click.wf-scroll');
});
});
// Smooth scroll implementation with customizable settings
(function() {
// Customizable settings
const SCROLL_SETTINGS = {
duration: 1000, // in milliseconds
easing: 'easeInOutCubic' // 'linear', 'easeInQuad', 'easeOutQuad', 'easeInOutQuad', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic'
};
const EASING_FUNCTIONS = {
linear: t => t,
easeInQuad: t => t * t,
easeOutQuad: t => t * (2 - t),
easeInOutQuad: t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
easeInCubic: t => t * t * t,
easeOutCubic: t => (--t) * t * t + 1,
easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
};
function getOffset() {
const navbar = document.querySelector('[ms-code-scroll-offset]');
if (!navbar) return 0;
const navbarHeight = navbar.offsetHeight;
const customOffset = parseInt(navbar.getAttribute('ms-code-scroll-offset') || '0', 10);
return navbarHeight + customOffset;
}
function smoothScroll(target) {
const startPosition = window.pageYOffset;
const offset = getOffset();
const targetPosition = target.getBoundingClientRect().top + startPosition - offset;
const distance = targetPosition - startPosition;
let startTime = null;
function animation(currentTime) {
if (startTime === null) startTime = currentTime;
const timeElapsed = currentTime - startTime;
const progress = Math.min(timeElapsed / SCROLL_SETTINGS.duration, 1);
const easeProgress = EASING_FUNCTIONS[SCROLL_SETTINGS.easing](progress);
window.scrollTo(0, startPosition + distance * easeProgress);
if (timeElapsed < SCROLL_SETTINGS.duration) requestAnimationFrame(animation);
}
requestAnimationFrame(animation);
}
function handleClick(e) {
const href = e.currentTarget.getAttribute('href');
if (href.startsWith('#')) {
e.preventDefault();
const target = document.getElementById(href.slice(1));
if (target) smoothScroll(target);
}
}
function handleHashChange() {
if (window.location.hash) {
const target = document.getElementById(window.location.hash.slice(1));
if (target) {
setTimeout(() => smoothScroll(target), 0);
}
}
}
function init() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', handleClick);
});
window.addEventListener('hashchange', handleHashChange);
handleHashChange(); // Handle initial hash on page load
}
document.addEventListener('DOMContentLoaded', init);
window.Webflow && window.Webflow.push(init);
})();
</script>
<!-- 💙 MEMBERSCRIPT #138 v0.1 💙 - ANCHOR LINK SCROLL OFFSET -->
<script>
// Disable Webflow's built-in smooth scrolling
var Webflow = Webflow || [];
Webflow.push(function() {
$(function() {
$(document).off('click.wf-scroll');
});
});
// Smooth scroll implementation with customizable settings
(function() {
// Customizable settings
const SCROLL_SETTINGS = {
duration: 1000, // in milliseconds
easing: 'easeInOutCubic' // 'linear', 'easeInQuad', 'easeOutQuad', 'easeInOutQuad', 'easeInCubic', 'easeOutCubic', 'easeInOutCubic'
};
const EASING_FUNCTIONS = {
linear: t => t,
easeInQuad: t => t * t,
easeOutQuad: t => t * (2 - t),
easeInOutQuad: t => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
easeInCubic: t => t * t * t,
easeOutCubic: t => (--t) * t * t + 1,
easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
};
function getOffset() {
const navbar = document.querySelector('[ms-code-scroll-offset]');
if (!navbar) return 0;
const navbarHeight = navbar.offsetHeight;
const customOffset = parseInt(navbar.getAttribute('ms-code-scroll-offset') || '0', 10);
return navbarHeight + customOffset;
}
function smoothScroll(target) {
const startPosition = window.pageYOffset;
const offset = getOffset();
const targetPosition = target.getBoundingClientRect().top + startPosition - offset;
const distance = targetPosition - startPosition;
let startTime = null;
function animation(currentTime) {
if (startTime === null) startTime = currentTime;
const timeElapsed = currentTime - startTime;
const progress = Math.min(timeElapsed / SCROLL_SETTINGS.duration, 1);
const easeProgress = EASING_FUNCTIONS[SCROLL_SETTINGS.easing](progress);
window.scrollTo(0, startPosition + distance * easeProgress);
if (timeElapsed < SCROLL_SETTINGS.duration) requestAnimationFrame(animation);
}
requestAnimationFrame(animation);
}
function handleClick(e) {
const href = e.currentTarget.getAttribute('href');
if (href.startsWith('#')) {
e.preventDefault();
const target = document.getElementById(href.slice(1));
if (target) smoothScroll(target);
}
}
function handleHashChange() {
if (window.location.hash) {
const target = document.getElementById(window.location.hash.slice(1));
if (target) {
setTimeout(() => smoothScroll(target), 0);
}
}
}
function init() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', handleClick);
});
window.addEventListener('hashchange', handleHashChange);
handleHashChange(); // Handle initial hash on page load
}
document.addEventListener('DOMContentLoaded', init);
window.Webflow && window.Webflow.push(init);
})();
</script>
.avif)
#Nr. 137 - Anzeige des Namens des Besucherlandes
Ersetzen Sie den Text durch das Land, in dem sich ein Benutzer auf der Grundlage seiner IP-Adresse befindet.
<!-- 💙 MEMBERSCRIPT #137 v0.1 💙 - DISPLAY COUNTRY NAME -->
<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('https://ipapi.co/json/')
.then(response => response.json())
.then(data => {
if (data.country_name) {
const countryElements = document.querySelectorAll('[ms-code-display-country]');
countryElements.forEach(element => {
element.textContent = data.country_name;
});
}
})
.catch(error => {
console.error('Error fetching country:', error);
});
});
</script>
<!-- 💙 MEMBERSCRIPT #137 v0.1 💙 - DISPLAY COUNTRY NAME -->
<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('https://ipapi.co/json/')
.then(response => response.json())
.then(data => {
if (data.country_name) {
const countryElements = document.querySelectorAll('[ms-code-display-country]');
countryElements.forEach(element => {
element.textContent = data.country_name;
});
}
})
.catch(error => {
console.error('Error fetching country:', error);
});
});
</script>

#Nr. 136 - Abschnittspfad aus URL entfernen
Wenn zu einem Abschnitt navigiert wird, wird der Pfad des Ankerlinks entfernt.
<!-- 💙 MEMBERSCRIPT #136 💙 REMOVE SECTION PATH FROM URL -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check if there's a hash in the URL
if (window.location.hash) {
// Get the target element
const targetId = window.location.hash.substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
// Scroll to the target element
targetElement.scrollIntoView({behavior: 'smooth'});
// Remove the hash after a short delay (to allow scrolling to complete)
setTimeout(function() {
history.pushState("", document.title, window.location.pathname + window.location.search);
}, 100);
}
}
// Add click event listeners to all internal links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
targetElement.scrollIntoView({behavior: 'smooth'});
// Remove the hash after a short delay (to allow scrolling to complete)
setTimeout(function() {
history.pushState("", document.title, window.location.pathname + window.location.search);
}, 100);
}
});
});
});
</script>
<!-- 💙 MEMBERSCRIPT #136 💙 REMOVE SECTION PATH FROM URL -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check if there's a hash in the URL
if (window.location.hash) {
// Get the target element
const targetId = window.location.hash.substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
// Scroll to the target element
targetElement.scrollIntoView({behavior: 'smooth'});
// Remove the hash after a short delay (to allow scrolling to complete)
setTimeout(function() {
history.pushState("", document.title, window.location.pathname + window.location.search);
}, 100);
}
}
// Add click event listeners to all internal links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
targetElement.scrollIntoView({behavior: 'smooth'});
// Remove the hash after a short delay (to allow scrolling to complete)
setTimeout(function() {
history.pushState("", document.title, window.location.pathname + window.location.search);
}, 100);
}
});
});
});
</script>

#Nr. 135 - Umleitung auf Basis eines ausgewählten Wertes
Legen Sie die Umleitung des Formulars dynamisch auf der Grundlage der Benutzerauswahl fest.
<!-- 💙 MEMBERSCRIPT #135 v0.2 💙 - REDIRECT FORM FROM SELECT VALUE -->
<script>
(function() {
'use strict';
function initDropdownRedirect() {
const dropdown = document.querySelector('select[ms-code-dropdown-redirect]');
if (!dropdown) return;
const form = dropdown.closest('form');
if (!form) return;
function updateRedirect() {
const selectedValue = dropdown.value;
form.setAttribute('redirect', selectedValue);
form.setAttribute('data-redirect', selectedValue);
}
function handleSubmit(event) {
event.preventDefault();
const redirectUrl = form.getAttribute('data-redirect') || form.getAttribute('redirect');
if (redirectUrl) {
setTimeout(() => {
window.location.href = redirectUrl;
}, 500); // Delay redirect by 500 milliseconds
} else {
form.submit(); // Fall back to normal form submission if no redirect is set
}
}
dropdown.addEventListener('change', updateRedirect);
form.addEventListener('submit', handleSubmit);
// Initialize redirect on page load
updateRedirect();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initDropdownRedirect);
} else {
initDropdownRedirect();
}
})();
</script>
<!-- 💙 MEMBERSCRIPT #135 v0.2 💙 - REDIRECT FORM FROM SELECT VALUE -->
<script>
(function() {
'use strict';
function initDropdownRedirect() {
const dropdown = document.querySelector('select[ms-code-dropdown-redirect]');
if (!dropdown) return;
const form = dropdown.closest('form');
if (!form) return;
function updateRedirect() {
const selectedValue = dropdown.value;
form.setAttribute('redirect', selectedValue);
form.setAttribute('data-redirect', selectedValue);
}
function handleSubmit(event) {
event.preventDefault();
const redirectUrl = form.getAttribute('data-redirect') || form.getAttribute('redirect');
if (redirectUrl) {
setTimeout(() => {
window.location.href = redirectUrl;
}, 500); // Delay redirect by 500 milliseconds
} else {
form.submit(); // Fall back to normal form submission if no redirect is set
}
}
dropdown.addEventListener('change', updateRedirect);
form.addEventListener('submit', handleSubmit);
// Initialize redirect on page load
updateRedirect();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initDropdownRedirect);
} else {
initDropdownRedirect();
}
})();
</script>

#Nr. 134 - Nach oben scrollen bei Tabwechsel
Wenn die Registerkarte gewechselt wird, blättert die Seite an den Anfang des Registerkartenbereichs.
<!-- 💙 MEMBERSCRIPT #134 💙 - SCROLL TO TOP OF TABS ON CHANGE -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Select all tab containers with the ms-code-tab-scroll-top attribute
const tabContainers = document.querySelectorAll('.w-tabs[ms-code-tab-scroll-top]');
tabContainers.forEach(container => {
const tabLinks = container.querySelectorAll('.w-tab-link');
const scrollTopValue = parseInt(container.getAttribute('ms-code-tab-scroll-top') || '0');
tabLinks.forEach(link => {
link.addEventListener('click', function(e) {
// Small delay to ensure the new tab content is rendered
setTimeout(() => {
// Find the active tab pane within this container
const activePane = container.querySelector('.w-tab-pane.w--tab-active');
if (activePane) {
// Calculate the new scroll position
const newScrollPosition = container.getBoundingClientRect().top + window.pageYOffset + scrollTopValue;
// Scroll to the new position
window.scrollTo({
top: newScrollPosition,
behavior: 'smooth'
});
}
}, 50); // 50ms delay, adjust if needed
});
});
});
});
</script>
<!-- 💙 MEMBERSCRIPT #134 💙 - SCROLL TO TOP OF TABS ON CHANGE -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Select all tab containers with the ms-code-tab-scroll-top attribute
const tabContainers = document.querySelectorAll('.w-tabs[ms-code-tab-scroll-top]');
tabContainers.forEach(container => {
const tabLinks = container.querySelectorAll('.w-tab-link');
const scrollTopValue = parseInt(container.getAttribute('ms-code-tab-scroll-top') || '0');
tabLinks.forEach(link => {
link.addEventListener('click', function(e) {
// Small delay to ensure the new tab content is rendered
setTimeout(() => {
// Find the active tab pane within this container
const activePane = container.querySelector('.w-tab-pane.w--tab-active');
if (activePane) {
// Calculate the new scroll position
const newScrollPosition = container.getBoundingClientRect().top + window.pageYOffset + scrollTopValue;
// Scroll to the new position
window.scrollTo({
top: newScrollPosition,
behavior: 'smooth'
});
}
}, 50); // 50ms delay, adjust if needed
});
});
});
});
</script>

#Nr. 133 - Automatisches Wasserzeichen für Bilder
Fügen Sie den Bildern auf Ihrer Webflow-Website ganz einfach ein Wasserzeichen hinzu.
<!-- 💙 MEMBERSCRIPT #133 v0.1 💙 - AUTO IMAGE WATERMARK -->
<script>
function addWatermarkToImages() {
const images = document.querySelectorAll('img[ms-code-watermark]');
images.forEach(img => {
img.crossOrigin = "Anonymous"; // This allows us to work with images from other domains
img.onload = function() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas size to match the image
canvas.width = img.width;
canvas.height = img.height;
// Draw the original image onto the canvas
ctx.drawImage(img, 0, 0, img.width, img.height);
// Get watermark text from attribute
const watermarkText = img.getAttribute('ms-code-watermark') || 'Watermark';
// Add watermark
ctx.font = `${img.width / 20}px Arial`; // Adjust font size based on image width
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Rotate and draw the watermark text
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(-Math.PI / 4); // Rotate 45 degrees
ctx.fillText(watermarkText, 0, 0);
ctx.restore();
// Preserve the original image's classes and other attributes
canvas.className = img.className;
for (let i = 0; i < img.attributes.length; i++) {
const attr = img.attributes[i];
if (attr.name !== 'src' && attr.name !== 'ms-code-watermark') {
canvas.setAttribute(attr.name, attr.value);
}
}
// Replace the original image with the watermarked canvas
img.parentNode.replaceChild(canvas, img);
};
// Trigger onload event (in case the image is already loaded)
if (img.complete) {
img.onload();
}
});
}
// Run the function when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', addWatermarkToImages);
</script>
<!-- 💙 MEMBERSCRIPT #133 v0.1 💙 - AUTO IMAGE WATERMARK -->
<script>
function addWatermarkToImages() {
const images = document.querySelectorAll('img[ms-code-watermark]');
images.forEach(img => {
img.crossOrigin = "Anonymous"; // This allows us to work with images from other domains
img.onload = function() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Set canvas size to match the image
canvas.width = img.width;
canvas.height = img.height;
// Draw the original image onto the canvas
ctx.drawImage(img, 0, 0, img.width, img.height);
// Get watermark text from attribute
const watermarkText = img.getAttribute('ms-code-watermark') || 'Watermark';
// Add watermark
ctx.font = `${img.width / 20}px Arial`; // Adjust font size based on image width
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Rotate and draw the watermark text
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(-Math.PI / 4); // Rotate 45 degrees
ctx.fillText(watermarkText, 0, 0);
ctx.restore();
// Preserve the original image's classes and other attributes
canvas.className = img.className;
for (let i = 0; i < img.attributes.length; i++) {
const attr = img.attributes[i];
if (attr.name !== 'src' && attr.name !== 'ms-code-watermark') {
canvas.setAttribute(attr.name, attr.value);
}
}
// Replace the original image with the watermarked canvas
img.parentNode.replaceChild(canvas, img);
};
// Trigger onload event (in case the image is already loaded)
if (img.complete) {
img.onload();
}
});
}
// Run the function when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', addWatermarkToImages);
</script>

#Nr. 132 - Elemente mit der Escape-Taste ausblenden
Fügen Sie ein Attribut hinzu, und wenn die Taste esc angeklickt wird, wird das Element auf "none" gesetzt.
<!-- 💙 MEMBERSCRIPT 💙 - HIDE ELEMENTS WITH ESC KEY -->
<script>
document.addEventListener('keydown', function(event) {
// Check if the pressed key is ESC (key code 27)
if (event.key === 'Escape' || event.keyCode === 27) {
// Find all elements with the attribute ms-code-close-esc
const elements = document.querySelectorAll('[ms-code-close-esc]');
// Loop through the elements and set their display to 'none'
elements.forEach(function(element) {
element.style.display = 'none';
});
}
});
</script>
<!-- 💙 MEMBERSCRIPT 💙 - HIDE ELEMENTS WITH ESC KEY -->
<script>
document.addEventListener('keydown', function(event) {
// Check if the pressed key is ESC (key code 27)
if (event.key === 'Escape' || event.keyCode === 27) {
// Find all elements with the attribute ms-code-close-esc
const elements = document.querySelectorAll('[ms-code-close-esc]');
// Loop through the elements and set their display to 'none'
elements.forEach(function(element) {
element.style.display = 'none';
});
}
});
</script>

#Nr. 131 - Addition von Zahleneingaben
Nehmen Sie den Wert von Zahleneingaben und zeigen Sie ihn in einem Eingabewert oder in einem Textbereich an.
<!-- 💙 MEMBERSCRIPT #131 v0.1 💙 - CALCULATE NUMBER INPUTS -->
<script>
// Function to initialize the counter functionality
function initializeCounter() {
const counters = {};
// Find all elements with ms-code-show-number attribute
document.querySelectorAll('[ms-code-show-number]').forEach(el => {
const counterName = el.getAttribute('ms-code-show-number');
if (!counters[counterName]) {
counters[counterName] = { total: 0, displays: [] };
}
counters[counterName].displays.push(el);
});
// Find all input elements with ms-code-add-number attribute
document.querySelectorAll('input[ms-code-add-number]').forEach(input => {
const counterName = input.getAttribute('ms-code-add-number');
if (counters[counterName]) {
input.addEventListener('input', updateCounter);
}
});
// Function to update counter when input changes
function updateCounter(event) {
const input = event.target;
const counterName = input.getAttribute('ms-code-add-number');
const counter = counters[counterName];
if (counter) {
counter.total = 0;
document.querySelectorAll(`input[ms-code-add-number="${counterName}"]`).forEach(input => {
counter.total += parseInt(input.value) || 0;
});
counter.displays.forEach(display => {
if (display.tagName === 'INPUT') {
display.value = counter.total;
} else {
display.textContent = counter.total;
}
});
}
}
// Initial update for all counters
Object.keys(counters).forEach(counterName => {
const input = document.querySelector(`input[ms-code-add-number="${counterName}"]`);
if (input) {
input.dispatchEvent(new Event('input'));
}
});
}
// Run the initialization when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', initializeCounter);
</script>
<!-- 💙 MEMBERSCRIPT #131 v0.1 💙 - CALCULATE NUMBER INPUTS -->
<script>
// Function to initialize the counter functionality
function initializeCounter() {
const counters = {};
// Find all elements with ms-code-show-number attribute
document.querySelectorAll('[ms-code-show-number]').forEach(el => {
const counterName = el.getAttribute('ms-code-show-number');
if (!counters[counterName]) {
counters[counterName] = { total: 0, displays: [] };
}
counters[counterName].displays.push(el);
});
// Find all input elements with ms-code-add-number attribute
document.querySelectorAll('input[ms-code-add-number]').forEach(input => {
const counterName = input.getAttribute('ms-code-add-number');
if (counters[counterName]) {
input.addEventListener('input', updateCounter);
}
});
// Function to update counter when input changes
function updateCounter(event) {
const input = event.target;
const counterName = input.getAttribute('ms-code-add-number');
const counter = counters[counterName];
if (counter) {
counter.total = 0;
document.querySelectorAll(`input[ms-code-add-number="${counterName}"]`).forEach(input => {
counter.total += parseInt(input.value) || 0;
});
counter.displays.forEach(display => {
if (display.tagName === 'INPUT') {
display.value = counter.total;
} else {
display.textContent = counter.total;
}
});
}
}
// Initial update for all counters
Object.keys(counters).forEach(counterName => {
const input = document.querySelector(`input[ms-code-add-number="${counterName}"]`);
if (input) {
input.dispatchEvent(new Event('input'));
}
});
}
// Run the initialization when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', initializeCounter);
</script>

#130 - Formular automatisch absenden, wenn sich alle Eingaben ändern
Überspringen Sie die Schaltfläche "Senden" und senden Sie das Formular, wenn sich alle Eingaben geändert haben.
<!-- 💙 MEMBERSCRIPT #130 v0.1 💙 - AUTO SUBMIT FORMS FROM INPUT CHANGE -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const forms = document.querySelectorAll('form[ms-code-auto-submit]');
forms.forEach(form => {
const fields = form.querySelectorAll('input:not([type="submit"]):not([type="button"]):not([type="reset"]), select, textarea');
const fieldStates = new Map(Array.from(fields).map(field => [field, false]));
function updateFieldState(field, checkImmediately = false) {
switch (field.type) {
case 'checkbox':
fieldStates.set(field, true); // Considered interacted with once changed
break;
case 'radio':
const radioGroup = form.querySelectorAll(`input[type="radio"][name="${field.name}"]`);
radioGroup.forEach(radio => fieldStates.set(radio, true));
break;
case 'select-one':
case 'select-multiple':
fieldStates.set(field, field.value !== '');
break;
case 'file':
fieldStates.set(field, field.files.length > 0);
break;
case 'hidden':
fieldStates.set(field, true); // Always consider hidden fields as filled
break;
default:
// For text inputs, only update on blur or if checkImmediately is true
if (field.type === 'text' || field.type === 'password' || field.type === 'email' || field.type === 'tel' || field.type === 'url' || field.tagName === 'TEXTAREA') {
if (checkImmediately || !field.dataset.blurred) {
fieldStates.set(field, field.value.trim() !== '');
}
} else {
fieldStates.set(field, field.value.trim() !== '');
}
}
if (checkImmediately) {
checkAndSubmit();
}
}
function checkAndSubmit() {
if (Array.from(fieldStates.values()).every(state => state)) {
// Create and dispatch a submit event
const submitEvent = new Event('submit', {
bubbles: true,
cancelable: true
});
const submitted = form.dispatchEvent(submitEvent);
// If the event wasn't prevented, manually submit the form
if (submitted) {
form.submit();
}
}
}
fields.forEach(field => {
// Use 'change' event for checkboxes, radios, file inputs, and selects
if (['checkbox', 'radio', 'file', 'select-one', 'select-multiple'].includes(field.type) || field.tagName === 'SELECT') {
field.addEventListener('change', () => updateFieldState(field, true));
}
// For text-like inputs, use 'blur' event
if (field.type === 'text' || field.type === 'password' || field.type === 'email' || field.type === 'tel' || field.type === 'url' || field.tagName === 'TEXTAREA') {
field.addEventListener('blur', () => {
field.dataset.blurred = 'true';
updateFieldState(field, true);
});
// Also check on input, but don't submit immediately
field.addEventListener('input', () => updateFieldState(field, false));
}
});
// Initial check for pre-filled fields (e.g., browser autofill)
fields.forEach(field => updateFieldState(field, false));
checkAndSubmit();
});
});
</script>
<!-- 💙 MEMBERSCRIPT #130 v0.1 💙 - AUTO SUBMIT FORMS FROM INPUT CHANGE -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const forms = document.querySelectorAll('form[ms-code-auto-submit]');
forms.forEach(form => {
const fields = form.querySelectorAll('input:not([type="submit"]):not([type="button"]):not([type="reset"]), select, textarea');
const fieldStates = new Map(Array.from(fields).map(field => [field, false]));
function updateFieldState(field, checkImmediately = false) {
switch (field.type) {
case 'checkbox':
fieldStates.set(field, true); // Considered interacted with once changed
break;
case 'radio':
const radioGroup = form.querySelectorAll(`input[type="radio"][name="${field.name}"]`);
radioGroup.forEach(radio => fieldStates.set(radio, true));
break;
case 'select-one':
case 'select-multiple':
fieldStates.set(field, field.value !== '');
break;
case 'file':
fieldStates.set(field, field.files.length > 0);
break;
case 'hidden':
fieldStates.set(field, true); // Always consider hidden fields as filled
break;
default:
// For text inputs, only update on blur or if checkImmediately is true
if (field.type === 'text' || field.type === 'password' || field.type === 'email' || field.type === 'tel' || field.type === 'url' || field.tagName === 'TEXTAREA') {
if (checkImmediately || !field.dataset.blurred) {
fieldStates.set(field, field.value.trim() !== '');
}
} else {
fieldStates.set(field, field.value.trim() !== '');
}
}
if (checkImmediately) {
checkAndSubmit();
}
}
function checkAndSubmit() {
if (Array.from(fieldStates.values()).every(state => state)) {
// Create and dispatch a submit event
const submitEvent = new Event('submit', {
bubbles: true,
cancelable: true
});
const submitted = form.dispatchEvent(submitEvent);
// If the event wasn't prevented, manually submit the form
if (submitted) {
form.submit();
}
}
}
fields.forEach(field => {
// Use 'change' event for checkboxes, radios, file inputs, and selects
if (['checkbox', 'radio', 'file', 'select-one', 'select-multiple'].includes(field.type) || field.tagName === 'SELECT') {
field.addEventListener('change', () => updateFieldState(field, true));
}
// For text-like inputs, use 'blur' event
if (field.type === 'text' || field.type === 'password' || field.type === 'email' || field.type === 'tel' || field.type === 'url' || field.tagName === 'TEXTAREA') {
field.addEventListener('blur', () => {
field.dataset.blurred = 'true';
updateFieldState(field, true);
});
// Also check on input, but don't submit immediately
field.addEventListener('input', () => updateFieldState(field, false));
}
});
// Initial check for pre-filled fields (e.g., browser autofill)
fields.forEach(field => updateFieldState(field, false));
checkAndSubmit();
});
});
</script>

#Nr. 129 - Country Gating
Sperren Sie den Zugriff auf Ihre Website für Besucher, die sich in einem der verbotenen Länder befinden.
<!-- 💙 MEMBERSCRIPT #129 v0.1 💙 - COUNTRY GATING -->
<script>
// Configuration
const ACCESS_DENIED_PAGE = '/access-denied';
// List of disallowed countries using ISO 3166-1 alpha-2 country codes
const DISALLOWED_COUNTRIES = [
// "US", // United States
// "CN", // China
// "RU", // Russia
// "IN", // India
// "JP", // Japan
// "DE", // Germany
// "GB", // United Kingdom
// "FR", // France
// "BR", // Brazil
// "IT", // Italy
// Add more countries as needed
];
// Function to get visitor's country and check access
function checkCountryAccess() {
// Check if we're already on the access denied page
if (window.location.pathname === ACCESS_DENIED_PAGE) {
return; // Don't redirect if already on the access denied page
}
fetch('https://ipapi.co/json/')
.then(response => response.json())
.then(data => {
const visitorCountry = data.country_code; // This returns the ISO 3166-1 alpha-2 country code
if (DISALLOWED_COUNTRIES.includes(visitorCountry)) {
window.location.href = ACCESS_DENIED_PAGE;
}
})
.catch(error => {
console.error('Error fetching IP data:', error);
});
}
// Run the check when the page loads
document.addEventListener('DOMContentLoaded', checkCountryAccess);
</script>
<!-- 💙 MEMBERSCRIPT #129 v0.1 💙 - COUNTRY GATING -->
<script>
// Configuration
const ACCESS_DENIED_PAGE = '/access-denied';
// List of disallowed countries using ISO 3166-1 alpha-2 country codes
const DISALLOWED_COUNTRIES = [
// "US", // United States
// "CN", // China
// "RU", // Russia
// "IN", // India
// "JP", // Japan
// "DE", // Germany
// "GB", // United Kingdom
// "FR", // France
// "BR", // Brazil
// "IT", // Italy
// Add more countries as needed
];
// Function to get visitor's country and check access
function checkCountryAccess() {
// Check if we're already on the access denied page
if (window.location.pathname === ACCESS_DENIED_PAGE) {
return; // Don't redirect if already on the access denied page
}
fetch('https://ipapi.co/json/')
.then(response => response.json())
.then(data => {
const visitorCountry = data.country_code; // This returns the ISO 3166-1 alpha-2 country code
if (DISALLOWED_COUNTRIES.includes(visitorCountry)) {
window.location.href = ACCESS_DENIED_PAGE;
}
})
.catch(error => {
console.error('Error fetching IP data:', error);
});
}
// Run the check when the page loads
document.addEventListener('DOMContentLoaded', checkCountryAccess);
</script>

#128 - Elemente ausblenden, nachdem sie gesehen wurden
Fügen Sie ein Attribut hinzu, und Ihre Besucher werden dieses Element nur einmal sehen. Nach der Aktualisierung ist es verschwunden.
<!-- 💙 MEMBERSCRIPT #128 💙 - ONLY SHOW ELEMENT ONCE -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Find all elements with the ms-code-show-once attribute
const elements = document.querySelectorAll('[ms-code-show-once]');
elements.forEach(element => {
const identifier = element.getAttribute('ms-code-show-once');
const storageKey = `ms-code-shown-${identifier}`;
// Check if the element has been seen before
if (localStorage.getItem(storageKey) !== 'true') {
// If not seen, show the element
element.style.display = 'block';
// Mark it as seen in localStorage
localStorage.setItem(storageKey, 'true');
} else {
// If already seen, hide the element
element.style.display = 'none';
}
});
});
</script>
<!-- 💙 MEMBERSCRIPT #128 💙 - ONLY SHOW ELEMENT ONCE -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Find all elements with the ms-code-show-once attribute
const elements = document.querySelectorAll('[ms-code-show-once]');
elements.forEach(element => {
const identifier = element.getAttribute('ms-code-show-once');
const storageKey = `ms-code-shown-${identifier}`;
// Check if the element has been seen before
if (localStorage.getItem(storageKey) !== 'true') {
// If not seen, show the element
element.style.display = 'block';
// Mark it as seen in localStorage
localStorage.setItem(storageKey, 'true');
} else {
// If already seen, hide the element
element.style.display = 'none';
}
});
});
</script>

#Nr. 127 - Texteingaben validieren
Überprüfen Sie Texteingaben anhand einer beliebigen Liste von Zeichenfolgen, einschließlich Wildcards!
<!-- 💙 MEMBERSCRIPT #127 v0.1 💙 - TEXT INPUT VALIDATION -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Find all fields with ms-code-require attribute
const fields = document.querySelectorAll('[ms-code-require]');
fields.forEach(field => {
// Get the error element for this field
const errorElement = document.querySelector(`[ms-code-require-error="${field.getAttribute('ms-code-require')}"]`);
// Hide error message initially
if (errorElement) {
errorElement.style.display = 'none';
}
// Get the form containing the field
const form = field.closest('form');
// Get the submit button
const submitButton = form ? form.querySelector(`[ms-code-submit-button="${field.getAttribute('ms-code-require')}"]`) : null;
// Get the require-list attribute value
const requireList = field.getAttribute('ms-code-require-list');
if (requireList) {
// Convert the require-list to an array of regex patterns
const patterns = requireList.split(',').map(pattern => {
return pattern.replace(/\{([^}]+)\}/g, (match, p1) => {
return p1.split('').map(char => {
switch(char) {
case '0': return '\\d';
case 'A': return '[A-Z]';
case 'a': return '[a-z]';
default: return char;
}
}).join('');
});
});
// Validate function
function validateField() {
const value = field.value;
const isValid = patterns.some(pattern => new RegExp(`^${pattern}$`).test(value));
if (errorElement) {
errorElement.style.display = isValid ? 'none' : 'block';
}
if (submitButton) {
submitButton.style.opacity = isValid ? '1' : '0.5';
submitButton.style.pointerEvents = isValid ? 'auto' : 'none';
}
return isValid;
}
// Debounced validate function
const debouncedValidate = debounce(validateField, 500);
// Add blur event listener
field.addEventListener('blur', validateField);
// Add input event listener for debounced validation
field.addEventListener('input', debouncedValidate);
// Handle form submission
if (form) {
form.addEventListener('submit', function(event) {
if (!validateField() && submitButton) {
event.preventDefault();
field.focus();
}
});
}
}
});
});
</script>
<!-- 💙 MEMBERSCRIPT #127 v0.1 💙 - TEXT INPUT VALIDATION -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Find all fields with ms-code-require attribute
const fields = document.querySelectorAll('[ms-code-require]');
fields.forEach(field => {
// Get the error element for this field
const errorElement = document.querySelector(`[ms-code-require-error="${field.getAttribute('ms-code-require')}"]`);
// Hide error message initially
if (errorElement) {
errorElement.style.display = 'none';
}
// Get the form containing the field
const form = field.closest('form');
// Get the submit button
const submitButton = form ? form.querySelector(`[ms-code-submit-button="${field.getAttribute('ms-code-require')}"]`) : null;
// Get the require-list attribute value
const requireList = field.getAttribute('ms-code-require-list');
if (requireList) {
// Convert the require-list to an array of regex patterns
const patterns = requireList.split(',').map(pattern => {
return pattern.replace(/\{([^}]+)\}/g, (match, p1) => {
return p1.split('').map(char => {
switch(char) {
case '0': return '\\d';
case 'A': return '[A-Z]';
case 'a': return '[a-z]';
default: return char;
}
}).join('');
});
});
// Validate function
function validateField() {
const value = field.value;
const isValid = patterns.some(pattern => new RegExp(`^${pattern}$`).test(value));
if (errorElement) {
errorElement.style.display = isValid ? 'none' : 'block';
}
if (submitButton) {
submitButton.style.opacity = isValid ? '1' : '0.5';
submitButton.style.pointerEvents = isValid ? 'auto' : 'none';
}
return isValid;
}
// Debounced validate function
const debouncedValidate = debounce(validateField, 500);
// Add blur event listener
field.addEventListener('blur', validateField);
// Add input event listener for debounced validation
field.addEventListener('input', debouncedValidate);
// Handle form submission
if (form) {
form.addEventListener('submit', function(event) {
if (!validateField() && submitButton) {
event.preventDefault();
field.focus();
}
});
}
}
});
});
</script>

#Nr. 126 - Formular ohne Umleitung an Webhook senden
Senden Sie Daten an einen Webhook und behalten Sie das Standardverhalten des Webflow-Formulars bei.
<!-- 💙 MEMBERSCRIPT #126 v0.1 💙 - POST FORM DATA TO WEBHOOK WITHOUT REDIRECTING -->
<script>
// Wait for the DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Select all forms with the ms-code-form-no-redirect attribute
const forms = document.querySelectorAll('form[ms-code-form-no-redirect]');
forms.forEach(form => {
// Select the success and error message elements for this form
const formWrapper = form.closest('.w-form');
const successMessage = formWrapper.querySelector('.w-form-done');
const errorMessage = formWrapper.querySelector('.w-form-fail');
// Add submit event listener to the form
form.addEventListener('submit', function(event) {
// Prevent the default form submission
event.preventDefault();
// Get the form data
const formData = new FormData(form);
// Get the submit button and set its text to the waiting message
const submitButton = form.querySelector('input[type="submit"], button[type="submit"]');
const originalButtonText = submitButton.value || submitButton.textContent;
const waitingText = submitButton.getAttribute('data-wait') || 'Please wait...';
if (submitButton.tagName === 'INPUT') {
submitButton.value = waitingText;
} else {
submitButton.textContent = waitingText;
}
// Disable the submit button
submitButton.disabled = true;
// Send the form data to the form's action URL using fetch
fetch(form.action, {
method: 'POST',
body: formData
})
.then(response => {
if (response.ok) {
// If the submission was successful, show the success message
form.style.display = 'none';
successMessage.style.display = 'block';
errorMessage.style.display = 'none';
} else {
// If there was an error, show the error message
throw new Error('Form submission failed');
}
})
.catch(error => {
// If there was a network error or the submission failed, show the error message
console.error('Error:', error);
errorMessage.style.display = 'block';
successMessage.style.display = 'none';
})
.finally(() => {
// Reset the submit button text and re-enable it
if (submitButton.tagName === 'INPUT') {
submitButton.value = originalButtonText;
} else {
submitButton.textContent = originalButtonText;
}
submitButton.disabled = false;
});
});
});
});
</script>
<!-- 💙 MEMBERSCRIPT #126 v0.1 💙 - POST FORM DATA TO WEBHOOK WITHOUT REDIRECTING -->
<script>
// Wait for the DOM to be fully loaded
document.addEventListener('DOMContentLoaded', function() {
// Select all forms with the ms-code-form-no-redirect attribute
const forms = document.querySelectorAll('form[ms-code-form-no-redirect]');
forms.forEach(form => {
// Select the success and error message elements for this form
const formWrapper = form.closest('.w-form');
const successMessage = formWrapper.querySelector('.w-form-done');
const errorMessage = formWrapper.querySelector('.w-form-fail');
// Add submit event listener to the form
form.addEventListener('submit', function(event) {
// Prevent the default form submission
event.preventDefault();
// Get the form data
const formData = new FormData(form);
// Get the submit button and set its text to the waiting message
const submitButton = form.querySelector('input[type="submit"], button[type="submit"]');
const originalButtonText = submitButton.value || submitButton.textContent;
const waitingText = submitButton.getAttribute('data-wait') || 'Please wait...';
if (submitButton.tagName === 'INPUT') {
submitButton.value = waitingText;
} else {
submitButton.textContent = waitingText;
}
// Disable the submit button
submitButton.disabled = true;
// Send the form data to the form's action URL using fetch
fetch(form.action, {
method: 'POST',
body: formData
})
.then(response => {
if (response.ok) {
// If the submission was successful, show the success message
form.style.display = 'none';
successMessage.style.display = 'block';
errorMessage.style.display = 'none';
} else {
// If there was an error, show the error message
throw new Error('Form submission failed');
}
})
.catch(error => {
// If there was a network error or the submission failed, show the error message
console.error('Error:', error);
errorMessage.style.display = 'block';
successMessage.style.display = 'none';
})
.finally(() => {
// Reset the submit button text and re-enable it
if (submitButton.tagName === 'INPUT') {
submitButton.value = originalButtonText;
} else {
submitButton.textContent = originalButtonText;
}
submitButton.disabled = false;
});
});
});
});
</script>

#Nr. 125 - Kontrolle des erforderlichen Zustands mit Kontrollkästchen
Formularfelder basierend auf dem Status eines Kontrollkästchens auf erforderlich/optional setzen.
<!-- 💙 MEMBERSCRIPT #125 v0.1 💙 - CHECKBOX TOGGLE REQUIRED ON FORM FIELDS -->
<script>
// Function to initialize the form field requirements
function initFormFieldRequirements() {
// Handle checkbox changes
document.querySelectorAll('[ms-code-req-if-checked], [ms-code-req-if-unchecked]').forEach(checkbox => {
checkbox.addEventListener('change', updateFieldRequirements);
// Initial update
updateFieldRequirements.call(checkbox);
});
}
// Function to update field requirements based on checkbox state
function updateFieldRequirements() {
const isChecked = this.checked;
const group = this.getAttribute('ms-code-req-if-checked') || this.getAttribute('ms-code-req-if-unchecked');
const ifChecked = this.hasAttribute('ms-code-req-if-checked');
const shouldBeRequired = ifChecked ? isChecked : !isChecked;
const shouldDisableIfNotReq = this.hasAttribute('ms-code-disable-if-not-req');
// Update associated input fields
document.querySelectorAll(`[ms-code-req-input="${group}"]`).forEach(input => {
input.required = shouldBeRequired;
updateInputStyle(input, shouldBeRequired, shouldDisableIfNotReq);
});
// Update associated labels
document.querySelectorAll(`[ms-code-req-label="${group}"]`).forEach(label => {
label.style.display = shouldBeRequired ? '' : 'none';
});
}
// Function to update input style based on required state and disable setting
function updateInputStyle(input, isRequired, shouldDisableIfNotReq) {
if (shouldDisableIfNotReq) {
input.style.opacity = isRequired ? '1' : '0.4';
input.style.pointerEvents = isRequired ? '' : 'none';
} else {
input.style.opacity = '';
input.style.pointerEvents = '';
}
}
// Initialize when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', initFormFieldRequirements);
</script>
<!-- 💙 MEMBERSCRIPT #125 v0.1 💙 - CHECKBOX TOGGLE REQUIRED ON FORM FIELDS -->
<script>
// Function to initialize the form field requirements
function initFormFieldRequirements() {
// Handle checkbox changes
document.querySelectorAll('[ms-code-req-if-checked], [ms-code-req-if-unchecked]').forEach(checkbox => {
checkbox.addEventListener('change', updateFieldRequirements);
// Initial update
updateFieldRequirements.call(checkbox);
});
}
// Function to update field requirements based on checkbox state
function updateFieldRequirements() {
const isChecked = this.checked;
const group = this.getAttribute('ms-code-req-if-checked') || this.getAttribute('ms-code-req-if-unchecked');
const ifChecked = this.hasAttribute('ms-code-req-if-checked');
const shouldBeRequired = ifChecked ? isChecked : !isChecked;
const shouldDisableIfNotReq = this.hasAttribute('ms-code-disable-if-not-req');
// Update associated input fields
document.querySelectorAll(`[ms-code-req-input="${group}"]`).forEach(input => {
input.required = shouldBeRequired;
updateInputStyle(input, shouldBeRequired, shouldDisableIfNotReq);
});
// Update associated labels
document.querySelectorAll(`[ms-code-req-label="${group}"]`).forEach(label => {
label.style.display = shouldBeRequired ? '' : 'none';
});
}
// Function to update input style based on required state and disable setting
function updateInputStyle(input, isRequired, shouldDisableIfNotReq) {
if (shouldDisableIfNotReq) {
input.style.opacity = isRequired ? '1' : '0.4';
input.style.pointerEvents = isRequired ? '' : 'none';
} else {
input.style.opacity = '';
input.style.pointerEvents = '';
}
}
// Initialize when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', initFormFieldRequirements);
</script>

#Nr. 124 - Sichtbarkeit von Objekten umschalten
Verwenden Sie benutzerdefinierte Schaltflächen, um Elemente ein- und auszublenden, wobei die Zustände im lokalen Speicher gespeichert werden.
<!-- 💙 MEMBERSCRIPT #124 v0.1 💙 - TOGGLE ITEM VISIBILITY -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const STORAGE_KEY = 'ms-code-vis-states';
// Load saved states from local storage
let savedStates = JSON.parse(localStorage.getItem(STORAGE_KEY)) || {};
// Find all unique group identifiers
const groups = new Set([...document.querySelectorAll('[ms-code-vis-item]')].map(el => el.getAttribute('ms-code-vis-item')));
groups.forEach(group => {
const item = document.querySelector(`[ms-code-vis-item="${group}"]`);
const showButton = document.querySelector(`[ms-code-vis-show="${group}"]`);
const hideButton = document.querySelector(`[ms-code-vis-hide="${group}"]`);
if (!item || !showButton || !hideButton) return;
// Function to update visibility
function updateVisibility(isVisible) {
if (isVisible) {
item.style.removeProperty('display');
showButton.style.display = 'none';
hideButton.style.removeProperty('display');
} else {
item.style.display = 'none';
showButton.style.removeProperty('display');
hideButton.style.display = 'none';
}
// Save state to local storage
savedStates[group] = isVisible;
localStorage.setItem(STORAGE_KEY, JSON.stringify(savedStates));
}
// Set initial visibility
const defaultState = item.getAttribute('ms-code-vis-default');
const savedState = savedStates[group];
if (savedState !== undefined) {
updateVisibility(savedState);
} else if (defaultState === 'hide') {
updateVisibility(false);
} else {
updateVisibility(true);
}
// Add click event listeners
showButton.addEventListener('click', function(e) {
e.preventDefault();
updateVisibility(true);
});
hideButton.addEventListener('click', function(e) {
e.preventDefault();
updateVisibility(false);
});
});
});
</script>
<!-- 💙 MEMBERSCRIPT #124 v0.1 💙 - TOGGLE ITEM VISIBILITY -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const STORAGE_KEY = 'ms-code-vis-states';
// Load saved states from local storage
let savedStates = JSON.parse(localStorage.getItem(STORAGE_KEY)) || {};
// Find all unique group identifiers
const groups = new Set([...document.querySelectorAll('[ms-code-vis-item]')].map(el => el.getAttribute('ms-code-vis-item')));
groups.forEach(group => {
const item = document.querySelector(`[ms-code-vis-item="${group}"]`);
const showButton = document.querySelector(`[ms-code-vis-show="${group}"]`);
const hideButton = document.querySelector(`[ms-code-vis-hide="${group}"]`);
if (!item || !showButton || !hideButton) return;
// Function to update visibility
function updateVisibility(isVisible) {
if (isVisible) {
item.style.removeProperty('display');
showButton.style.display = 'none';
hideButton.style.removeProperty('display');
} else {
item.style.display = 'none';
showButton.style.removeProperty('display');
hideButton.style.display = 'none';
}
// Save state to local storage
savedStates[group] = isVisible;
localStorage.setItem(STORAGE_KEY, JSON.stringify(savedStates));
}
// Set initial visibility
const defaultState = item.getAttribute('ms-code-vis-default');
const savedState = savedStates[group];
if (savedState !== undefined) {
updateVisibility(savedState);
} else if (defaultState === 'hide') {
updateVisibility(false);
} else {
updateVisibility(true);
}
// Add click event listeners
showButton.addEventListener('click', function(e) {
e.preventDefault();
updateVisibility(true);
});
hideButton.addEventListener('click', function(e) {
e.preventDefault();
updateVisibility(false);
});
});
});
</script>

#Nr. 123 - Ein Hörspiel nach dem anderen
Halten Sie automatisch alle anderen Audioplayer an, wenn ein Benutzer auf die Wiedergabe eines Audioplayers klickt.
<!-- 💙 MEMBERSCRIPT #123 💙 - ONE AUDIO AT A TIME -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const pauseOthers = current =>
document.querySelectorAll('audio, video').forEach(el => el !== current && !el.paused && el.pause());
const addPlayListener = el => el.addEventListener('play', e => pauseOthers(e.target));
new MutationObserver(mutations =>
mutations.forEach(m => m.addedNodes.forEach(n =>
(n.nodeName === 'AUDIO' || n.nodeName === 'VIDEO') && addPlayListener(n)
))
).observe(document.body, { childList: true, subtree: true });
document.querySelectorAll('audio, video').forEach(addPlayListener);
});
</script>
<!-- 💙 MEMBERSCRIPT #123 💙 - ONE AUDIO AT A TIME -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const pauseOthers = current =>
document.querySelectorAll('audio, video').forEach(el => el !== current && !el.paused && el.pause());
const addPlayListener = el => el.addEventListener('play', e => pauseOthers(e.target));
new MutationObserver(mutations =>
mutations.forEach(m => m.addedNodes.forEach(n =>
(n.nodeName === 'AUDIO' || n.nodeName === 'VIDEO') && addPlayListener(n)
))
).observe(document.body, { childList: true, subtree: true });
document.querySelectorAll('audio, video').forEach(addPlayListener);
});
</script>

#122 - Externe Links in neuem Tab öffnen
Externe Links werden automatisch in einer neuen Registerkarte geöffnet, und die Attribute nofollow und noreferrer werden hinzugefügt.
<!-- 💙 MEMBERSCRIPT #122 💙 - OPEN EXTERNAL LINKS IN NEW TAB -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const thisDomain = location.hostname;
const externalSelector = `a:not([href*="${thisDomain}"]):not([href^="/"]):not([href^="#"]):not([ms-code-ext-link="ignore"])`;
document.querySelectorAll(externalSelector).forEach(link => {
link.target = '_blank'; // Open in new tab (comment out to disable)
link.rel = (link.rel ? link.rel + ' ' : '') + 'noreferrer'; // Add noreferrer (comment out to disable)
link.rel = (link.rel ? link.rel + ' ' : '') + 'nofollow'; // Add nofollow (comment out to disable)
});
});
</script>
<!-- 💙 MEMBERSCRIPT #122 💙 - OPEN EXTERNAL LINKS IN NEW TAB -->
<script>
document.addEventListener('DOMContentLoaded', () => {
const thisDomain = location.hostname;
const externalSelector = `a:not([href*="${thisDomain}"]):not([href^="/"]):not([href^="#"]):not([ms-code-ext-link="ignore"])`;
document.querySelectorAll(externalSelector).forEach(link => {
link.target = '_blank'; // Open in new tab (comment out to disable)
link.rel = (link.rel ? link.rel + ' ' : '') + 'noreferrer'; // Add noreferrer (comment out to disable)
link.rel = (link.rel ? link.rel + ' ' : '') + 'nofollow'; // Add nofollow (comment out to disable)
});
});
</script>

#Nr. 121 - Array aus benutzerdefiniertem Feld rendern
Zeigen Sie Ihren Mitgliedern in Webflow eine beliebige kommagetrennte Liste an.
<!-- 💙 MEMBERSCRIPT #121 v0.1 💙 - RENDER ARRAY FROM CUSTOM FIELD -->
<script>
// Function to render arrays from Memberstack custom fields
function renderMemberstackArrays() {
// Get all elements with the ms-code-render-array attribute
const arrayElements = document.querySelectorAll('[ms-code-render-array]');
arrayElements.forEach(element => {
const customFieldKey = element.getAttribute('ms-code-render-array');
// Get Memberstack data from localStorage
const memberData = JSON.parse(localStorage.getItem('_ms-mem'));
if (!memberData || !memberData.customFields || !memberData.customFields[customFieldKey]) {
// If no data found, remove the element
element.remove();
return;
}
const arrayString = memberData.customFields[customFieldKey];
// Convert string to array, trim whitespace
const arrayItems = arrayString.split(',').map(item => item.trim()).filter(item => item !== '');
if (arrayItems.length === 0) {
// If array is empty, remove the element
element.remove();
return;
}
// Store the parent element
const parentElement = element.parentNode;
// Clone the template
const templateItem = element.cloneNode(true);
// Remove the ms-code-render-array attribute from the template
templateItem.removeAttribute('ms-code-render-array');
// Create a document fragment to hold the new items
const fragment = document.createDocumentFragment();
// Render array items
arrayItems.forEach(item => {
const newItem = templateItem.cloneNode(true);
// Replace the content of the new item
replaceContent(newItem, item);
fragment.appendChild(newItem);
});
// Replace the original element with the new items
parentElement.replaceChild(fragment, element);
});
}
// Helper function to replace content in the element
function replaceContent(element, newContent) {
if (element.childNodes.length > 0) {
element.childNodes.forEach(child => {
if (child.nodeType === Node.ELEMENT_NODE) {
replaceContent(child, newContent);
} else if (child.nodeType === Node.TEXT_NODE) {
child.textContent = newContent;
}
});
} else {
element.textContent = newContent;
}
}
// Run the function when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', renderMemberstackArrays);
</script>
<!-- 💙 MEMBERSCRIPT #121 v0.1 💙 - RENDER ARRAY FROM CUSTOM FIELD -->
<script>
// Function to render arrays from Memberstack custom fields
function renderMemberstackArrays() {
// Get all elements with the ms-code-render-array attribute
const arrayElements = document.querySelectorAll('[ms-code-render-array]');
arrayElements.forEach(element => {
const customFieldKey = element.getAttribute('ms-code-render-array');
// Get Memberstack data from localStorage
const memberData = JSON.parse(localStorage.getItem('_ms-mem'));
if (!memberData || !memberData.customFields || !memberData.customFields[customFieldKey]) {
// If no data found, remove the element
element.remove();
return;
}
const arrayString = memberData.customFields[customFieldKey];
// Convert string to array, trim whitespace
const arrayItems = arrayString.split(',').map(item => item.trim()).filter(item => item !== '');
if (arrayItems.length === 0) {
// If array is empty, remove the element
element.remove();
return;
}
// Store the parent element
const parentElement = element.parentNode;
// Clone the template
const templateItem = element.cloneNode(true);
// Remove the ms-code-render-array attribute from the template
templateItem.removeAttribute('ms-code-render-array');
// Create a document fragment to hold the new items
const fragment = document.createDocumentFragment();
// Render array items
arrayItems.forEach(item => {
const newItem = templateItem.cloneNode(true);
// Replace the content of the new item
replaceContent(newItem, item);
fragment.appendChild(newItem);
});
// Replace the original element with the new items
parentElement.replaceChild(fragment, element);
});
}
// Helper function to replace content in the element
function replaceContent(element, newContent) {
if (element.childNodes.length > 0) {
element.childNodes.forEach(child => {
if (child.nodeType === Node.ELEMENT_NODE) {
replaceContent(child, newContent);
} else if (child.nodeType === Node.TEXT_NODE) {
child.textContent = newContent;
}
});
} else {
element.textContent = newContent;
}
}
// Run the function when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', renderMemberstackArrays);
</script>

#120 - Element auf Basis von Gerät, Betriebssystem oder Browser ein-/ausblenden
Bedingte Sichtbarkeit, je nachdem, welches Gerät, Betriebssystem oder welchen Browser der Besucher verwendet.
<!-- 💙 MEMBERSCRIPT #120 v0.1 💙 - DEVICE/OS/BROWSER CONDITIONAL VISIBILITY -->
<script>
// Define device types, operating systems, and browsers with their detection methods
const detectionTypes = {
// Device types
mobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
tablet: () => /iPad|Android|Silk/i.test(navigator.userAgent) && !/Mobile/i.test(navigator.userAgent),
desktop: () => !(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)),
touchdevice: () => 'ontouchstart' in window || navigator.maxTouchPoints > 0,
landscape: () => window.matchMedia("(orientation: landscape)").matches,
portrait: () => window.matchMedia("(orientation: portrait)").matches,
// Operating Systems
ios: () => /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream,
android: () => /Android/.test(navigator.userAgent),
macos: () => /Mac OS X/.test(navigator.userAgent) && !(/iPad|iPhone|iPod/.test(navigator.userAgent)),
windows: () => /Win/.test(navigator.platform),
linux: () => /Linux/.test(navigator.platform),
// Browsers
chrome: () => /Chrome/.test(navigator.userAgent) && !/Chromium/.test(navigator.userAgent),
firefox: () => /Firefox/.test(navigator.userAgent),
safari: () => /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
edge: () => /Edg/.test(navigator.userAgent),
opera: () => /OPR/.test(navigator.userAgent) || /Opera/.test(navigator.userAgent),
ie: () => /Trident/.test(navigator.userAgent)
};
function detectTypes() {
const detected = [];
for (const [type, detector] of Object.entries(detectionTypes)) {
if (detector()) {
detected.push(type);
}
}
return detected;
}
function evaluateCondition(condition, currentTypes) {
const parts = condition.split('&').map(part => part.trim());
return parts.every(part => {
const orParts = part.split('|').map(p => p.trim());
return orParts.some(p => {
if (p.startsWith('!')) {
return !currentTypes.includes(p.slice(1));
}
return currentTypes.includes(p);
});
});
}
function updateElementVisibility() {
const currentTypes = detectTypes();
const elements = document.querySelectorAll('[ms-code-device-show]');
elements.forEach(element => {
const showAttribute = element.getAttribute('ms-code-device-show').toLowerCase();
const shouldShow = evaluateCondition(showAttribute, currentTypes);
element.style.display = shouldShow ? '' : 'none';
});
}
// Run on page load and window resize
window.addEventListener('load', updateElementVisibility);
window.addEventListener('resize', updateElementVisibility);
</script>
<!-- 💙 MEMBERSCRIPT #120 v0.1 💙 - DEVICE/OS/BROWSER CONDITIONAL VISIBILITY -->
<script>
// Define device types, operating systems, and browsers with their detection methods
const detectionTypes = {
// Device types
mobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
tablet: () => /iPad|Android|Silk/i.test(navigator.userAgent) && !/Mobile/i.test(navigator.userAgent),
desktop: () => !(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)),
touchdevice: () => 'ontouchstart' in window || navigator.maxTouchPoints > 0,
landscape: () => window.matchMedia("(orientation: landscape)").matches,
portrait: () => window.matchMedia("(orientation: portrait)").matches,
// Operating Systems
ios: () => /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream,
android: () => /Android/.test(navigator.userAgent),
macos: () => /Mac OS X/.test(navigator.userAgent) && !(/iPad|iPhone|iPod/.test(navigator.userAgent)),
windows: () => /Win/.test(navigator.platform),
linux: () => /Linux/.test(navigator.platform),
// Browsers
chrome: () => /Chrome/.test(navigator.userAgent) && !/Chromium/.test(navigator.userAgent),
firefox: () => /Firefox/.test(navigator.userAgent),
safari: () => /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent),
edge: () => /Edg/.test(navigator.userAgent),
opera: () => /OPR/.test(navigator.userAgent) || /Opera/.test(navigator.userAgent),
ie: () => /Trident/.test(navigator.userAgent)
};
function detectTypes() {
const detected = [];
for (const [type, detector] of Object.entries(detectionTypes)) {
if (detector()) {
detected.push(type);
}
}
return detected;
}
function evaluateCondition(condition, currentTypes) {
const parts = condition.split('&').map(part => part.trim());
return parts.every(part => {
const orParts = part.split('|').map(p => p.trim());
return orParts.some(p => {
if (p.startsWith('!')) {
return !currentTypes.includes(p.slice(1));
}
return currentTypes.includes(p);
});
});
}
function updateElementVisibility() {
const currentTypes = detectTypes();
const elements = document.querySelectorAll('[ms-code-device-show]');
elements.forEach(element => {
const showAttribute = element.getAttribute('ms-code-device-show').toLowerCase();
const shouldShow = evaluateCondition(showAttribute, currentTypes);
element.style.display = shouldShow ? '' : 'none';
});
}
// Run on page load and window resize
window.addEventListener('load', updateElementVisibility);
window.addEventListener('resize', updateElementVisibility);
</script>

#Nr. 119 - Altersberechnung ab Datumseingabe
Berechnen Sie die Gesamtzahl der vergangenen Jahre und füllen Sie eine Eingabe mit dieser Zahl aus.
<!-- 💙 MEMBERSCRIPT #119 v0.1 💙 - AGE CALCULATOR FROM DATE INPUT -->
<script>
// Function to calculate age
function calculateAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
}
// Function to update age input
function updateAgeInput(birthdayInput) {
const attrValue = birthdayInput.getAttribute('ms-code-bday-input');
const ageInput = document.querySelector(`[ms-code-age-input="${attrValue}"]`);
if (birthdayInput.value) {
const age = calculateAge(birthdayInput.value);
ageInput.value = age;
} else {
ageInput.value = '';
}
}
// Function to set up event listeners for all birthday inputs
function setupAgeCalculators() {
const birthdayInputs = document.querySelectorAll('[ms-code-bday-input]');
birthdayInputs.forEach(input => {
input.addEventListener('input', () => updateAgeInput(input));
// Initial call to set age if birthday is pre-filled
updateAgeInput(input);
});
}
// Run setup when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', setupAgeCalculators);
</script>
<!-- 💙 MEMBERSCRIPT #119 v0.1 💙 - AGE CALCULATOR FROM DATE INPUT -->
<script>
// Function to calculate age
function calculateAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
}
// Function to update age input
function updateAgeInput(birthdayInput) {
const attrValue = birthdayInput.getAttribute('ms-code-bday-input');
const ageInput = document.querySelector(`[ms-code-age-input="${attrValue}"]`);
if (birthdayInput.value) {
const age = calculateAge(birthdayInput.value);
ageInput.value = age;
} else {
ageInput.value = '';
}
}
// Function to set up event listeners for all birthday inputs
function setupAgeCalculators() {
const birthdayInputs = document.querySelectorAll('[ms-code-bday-input]');
birthdayInputs.forEach(input => {
input.addEventListener('input', () => updateAgeInput(input));
// Initial call to set age if birthday is pre-filled
updateAgeInput(input);
});
}
// Run setup when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', setupAgeCalculators);
</script>
Brauchen Sie Hilfe mit MemberScripts? Treten Sie unserer Slack-Community mit über 5.500 Mitgliedern bei! 🙌
MemberScripts sind eine Community-Ressource von Memberstack - wenn du Hilfe brauchst, damit sie mit deinem Projekt funktionieren, melde dich bitte im Memberstack 2.0 Slack an und bitte um Hilfe!
Unserem Slack beitretenEntdecken Sie echte Unternehmen, die mit Memberstack erfolgreich waren
Verlassen Sie sich nicht nur auf unser Wort - schauen Sie sich die Unternehmen aller Größen an, die sich auf Memberstack für ihre Authentifizierung und Zahlungen verlassen.
Bauen Sie Ihre Träume
Memberstack ist 100% kostenlos, bis Sie bereit sind, zu starten - worauf warten Sie also noch? Erstellen Sie Ihre erste App und beginnen Sie noch heute mit der Entwicklung.