1/** 2 * ECS Dark Mode Switcher 3 * 4 * Handles three display modes (toggle, dual, dropdown) for the 5 * ECS Dark Mode Switcher widget. Persists the user's choice via 6 * a cookie so PHP can add data-ecs-scheme="alt" to <html> before 7 * first paint â cache-safe. 8 * 9 * No dependencies â vanilla JS, loaded in the footer. 10 */ 11(function () { 12 'use strict'; 13 14 // Guard against double-init when loaded more than once. 15 if ( window.__ecsDmsReady ) { return; } 16 window.__ecsDmsReady = true; 17 18 var COOKIE_NAME = 'ecs_color_scheme'; 19 var ALT_VALUE = 'alt'; 20 21 /** 22 * Get the current active scheme ('alt' or null). 23 */ 24 function getCurrentScheme() { 25 return document.documentElement.getAttribute('data-ecs-scheme'); 26 } 27 28 /** 29 * Apply a scheme by setting / removing the attribute on <html>. 30 */ 31 function applyScheme(scheme) { 32 if (scheme === ALT_VALUE) { 33 document.documentElement.setAttribute('data-ecs-scheme', ALT_VALUE); 34 } else { 35 document.documentElement.removeAttribute('data-ecs-scheme'); 36 } 37 } 38 39 /** 40 * Persist the choice as a cookie so both PHP (server-side, for cache-aware 41 * pages) and the inline anti-FOUC script can read it before first paint. 42 */ 43 function persistScheme(scheme) { 44 if (scheme === ALT_VALUE) { 45 document.cookie = COOKIE_NAME + '=alt; path=/; max-age=31536000; SameSite=Lax'; 46 } else { 47 document.cookie = COOKIE_NAME + '=; path=/; max-age=0; SameSite=Lax'; 48 } 49 } 50 51 /** 52 * Return true if the user has a manually stored scheme preference. 53 */ 54 function hasCookie() { 55 return /(?:^|;\s*)ecs_color_scheme=/.test( document.cookie ); 56 } 57 58 /** 59 * Sync every widget on the page to the current scheme. 60 * Handles toggle, dual, and dropdown display types. 61 */ 62 function syncAllWidgets() { 63 var isAlt = getCurrentScheme() === ALT_VALUE; 64 65 document.querySelectorAll('.ecs-dms-wrap').forEach(function (wrap) { 66 // Wrapper gets .is-alt for CSS toggle state switching 67 wrap.classList.toggle('is-alt', isAlt); 68 69 var display = wrap.dataset.display; 70 71 if (display === 'toggle') { 72 var btn = wrap.querySelector('.ecs-dms-btn'); 73 if (btn) { 74 btn.classList.toggle('is-active', isAlt); 75 } 76 77 } else if (display === 'dual') { 78 wrap.querySelectorAll('.ecs-dms-btn').forEach(function (btn) { 79 var isActive = btn.dataset.scheme === ALT_VALUE ? isAlt : !isAlt; 80 btn.classList.toggle('is-active', isActive); 81 btn.setAttribute('aria-pressed', isActive ? 'true' : 'false'); 82 }); 83 84 } else if (display === 'dropdown') { 85 var select = wrap.querySelector('.ecs-dms-select'); 86 if (select) { 87 select.value = isAlt ? ALT_VALUE : 'default'; 88 } 89 } 90 }); 91 } 92 93 /** 94 * Click handler â handles toggle and dual buttons. 95 */ 96 function handleClick(event) { 97 var btn = event.target.closest('.ecs-dms-btn'); 98 if (!btn) { return; } 99 100 var wrap = btn.closest('.ecs-dms-wrap'); 101 if (!wrap) { return; } 102 103 var newScheme; 104 105 if (wrap.dataset.display === 'dual') { 106 // Each dual button carries its target scheme explicitly 107 newScheme = btn.dataset.scheme; 108 } else { 109 // Toggle: flip the current scheme 110 newScheme = getCurrentScheme() === ALT_VALUE ? 'default' : ALT_VALUE; 111 } 112 113 applyScheme(newScheme); 114 persistScheme(newScheme); 115 syncAllWidgets(); 116 } 117 118 /** 119 * Change handler â handles dropdown. 120 */ 121 function handleDropdownChange(event) { 122 var select = event.target; 123 if (!select.classList.contains('ecs-dms-select')) { return; } 124 125 applyScheme(select.value); 126 persistScheme(select.value); 127 syncAllWidgets(); 128 } 129 130 // ââ Init âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 131 132 function init() { 133 // Sync widgets to whatever the anti-FOUC script already set on <html> 134 syncAllWidgets(); 135 136 // System Auto: if enabled and no manual preference stored, 137 // follow live OS theme changes. 138 var cfg = window.ecsSchemeConfig || {}; 139 if ( cfg.systemAuto ) { 140 var mq = window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ); 141 if ( mq ) { 142 mq.addEventListener( 'change', function ( e ) { 143 if ( ! hasCookie() ) { 144 applyScheme( e.matches ? ALT_VALUE : 'default' ); 145 syncAllWidgets(); 146 } 147 } ); 148 } 149 } 150 151 // Delegate on document so Elementor re-renders don't require re-binding 152 document.addEventListener('click', handleClick); 153 document.addEventListener('change', handleDropdownChange); 154 } 155 156 if (document.readyState === 'loading') { 157 document.addEventListener('DOMContentLoaded', init); 158 } else { 159 init(); 160 } 161})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.