;(function() {
// Prevent multiple executions
let hasSynced = false;
let observer;
let rafId;
// Batch processing configuration
const BATCH_SIZE = 10;
const RAF_TIMEOUT = 16; // ~60fps
// Cache for DOM queries
const cache = new Map();
const getCached = (selector, context = document) => {
const key = `${selector}:${context === document ? 'doc' : 'ctx'}`;
if (!cache.has(key)) {
cache.set(key, context.querySelectorAll(selector));
}
return cache.get(key);
};
// Clear cache when DOM changes
const clearCache = () => cache.clear();
// Batch DOM operations using DocumentFragment
function processBatch(items, startIndex = 0) {
const endIndex = Math.min(startIndex + BATCH_SIZE, items.length);
const fragment = document.createDocumentFragment();
const events = [];
// Process items in current batch
for (let i = startIndex; i < endIndex; i++) {
const wrapper = items[i];
const input = wrapper.querySelector('input.pplr_select');
if (!input?.value) continue;
const val = input.value.replace(/"/g, '\\"'); // Escape quotes for safety
const target = wrapper.querySelector(`[data-value="${val}"]`);
if (!target) continue;
// Collect events for later dispatch
events.push({ target, input });
}
// Execute DOM changes in batch
if (events.length > 0) {
// Disable transitions temporarily for performance
const style = document.createElement('style');
style.textContent = '.pplr-wrapper * { transition: none !important; }';
document.head.appendChild(style);
// Process all clicks
events.forEach(({ target }) => target.click());
// Batch fire change events
events.forEach(({ input }) => {
input.dispatchEvent(new Event('change', { bubbles: true }));
});
// Re-enable transitions after a frame
requestAnimationFrame(() => {
document.head.removeChild(style);
});
}
// Continue with next batch if needed
if (endIndex < items.length) {
rafId = requestAnimationFrame(() => processBatch(items, endIndex));
} else {
// All batches processed - final cleanup
finalizePricingUpdate();
}
}
// Optimized synchronization with batching
function syncPPLR() {
const wrappers = getCached('.pplr-wrapper');
if (wrappers.length === 0) return;
// Convert NodeList to Array for better performance
const wrappersArray = Array.from(wrappers);
// Start batch processing
processBatch(wrappersArray);
}
// Debounced price calculation
let priceCalcTimeout;
function finalizePricingUpdate() {
clearTimeout(priceCalcTimeout);
priceCalcTimeout = setTimeout(() => {
if (typeof window.PPLR_CAlCULATE_PRICE === 'function') {
try {
window.PPLR_CAlCULATE_PRICE();
} catch (error) {
console.warn('PPLR price calculation failed:', error);
}
}
}, 50); // Small delay to ensure DOM is settled
}
// Optimized tab reset
function resetToFirstTab() {
const firstTab = getCached('.pplr_tab_wrapper .pplr_tab_index[data-tab="1"]')[0];
if (firstTab) {
// Use faster method if available
if (firstTab.click) {
firstTab.click();
} else {
firstTab.dispatchEvent(new MouseEvent('click', { bubbles: true }));
}
}
}
// Enhanced initialization with performance monitoring
function initSync() {
if (hasSynced) return;
const wrappers = getCached('.pplr-wrapper');
if (wrappers.length === 0) return;
hasSynced = true;
// Performance timing
const startTime = performance.now();
// Clear cache before sync to get fresh elements
clearCache();
// Run synchronization
syncPPLR();
resetToFirstTab();
// Log performance in development
if (window.location.hostname === 'localhost' || window.location.hostname.includes('dev')) {
console.log(`PPLR sync completed in ${(performance.now() - startTime).toFixed(2)}ms`);
}
// Cleanup observer
if (observer) {
observer.disconnect();
observer = null;
}
}
// Throttled scheduling
let scheduleTimeout;
function scheduleSync() {
if (scheduleTimeout) return; // Already scheduled
scheduleTimeout = setTimeout(() => {
if ('requestIdleCallback' in window) {
requestIdleCallback(initSync, { timeout: 100 });
} else {
requestAnimationFrame(initSync);
}
scheduleTimeout = null;
}, 10);
}
// Optimized MutationObserver
function setupObserver() {
if (observer) return;
let mutationTimeout;
observer = new MutationObserver(() => {
clearTimeout(mutationTimeout);
mutationTimeout = setTimeout(() => {
if (document.querySelector('.pplr-wrapper')) {
clearCache(); // Clear cache when DOM changes
scheduleSync();
}
}, 20); // Debounce mutations
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributeFilter: ['class', 'data-value'] // Only watch relevant attributes
});
}
// Enhanced page lifecycle handling
function handlePageShow(event) {
if (event.persisted) {
clearCache();
hasSynced = false; // Reset sync state for cached pages
scheduleSync();
}
}
// Cleanup function for SPA navigation
function cleanup() {
if (rafId) {
cancelAnimationFrame(rafId);
rafId = null;
}
if (observer) {
observer.disconnect();
observer = null;
}
clearTimeout(scheduleTimeout);
clearTimeout(priceCalcTimeout);
clearCache();
}
// Initialize
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setupObserver();
scheduleSync();
});
} else {
setupObserver();
scheduleSync();
}
// Event listeners
window.addEventListener('pageshow', handlePageShow);
window.addEventListener('beforeunload', cleanup);
// Expose cleanup for SPA frameworks
window.PPLR_SYNC_CLEANUP = cleanup;
})();
Satin-Schleife mit Stern in Kontrastfarbe
Diese Premiumrosette wird mit einem Stern in Kontrastfarbe kombiniert.
Unter einer enggerüschten Premium-Rosette werden acht Spitzen als Stern
und zwei 25 cm lange Bänder montiert
Rosette-Ø: 12,5 cm
Bänder: 2 x 25 cm
Größe: 30 cm
Empfohlen für die Schleife Stockholm
Produktname
€19,99 | €24,99
In den Warenkorb
Produktname
€19,99 | €24,99
In den Warenkorb
Produktname
€19,99 | €24,99
In den Warenkorb
Produktname
€19,99 | €24,99
In den Warenkorb