1(function(){var FALLBACK=['zh-TW','zh-CN','es','fr','ja','ko','pt','de'];var SUPPORTED=(function(){try{var out=[];var ls=document.querySelectorAll('link[rel=alternate][hreflang]');for(var i=0;i<ls.length;i++){var h=ls[i].getAttribute('hreflang');if(!h||h==='x-default'||h==='en')continue;if(out.indexOf(h)===-1)out.push(h);}return out.length?out:FALLBACK;}catch(e){return FALLBACK;}})();function detectLang(){var raw=(navigator.languages&&navigator.languages[0])||navigator.language||'';var lang=raw.toLowerCase().replace('_','-');var exact=SUPPORTED.find(function(s){return s.toLowerCase()===lang;});if(exact)return exact;var prefix=lang.split('-')[0];var pref=SUPPORTED.find(function(s){return s.toLowerCase()===prefix;});if(pref)return pref;return null;}function maybeRedirect(){if(location.pathname!=='/'&&location.pathname!=='/index.html')return;if(localStorage.getItem('toolhub-lang-chosen'))return;var target=detectLang();if(!target)return;var newPath='/'+target+'/';var base=location.pathname.replace(/\/(index\.html)?\/?$/,'');if(base&&base!=='/')newPath=base+newPath;if(location.pathname!==newPath)location.replace(newPath);}maybeRedirect();document.addEventListener('DOMContentLoaded',function(){var dropdown=document.querySelector('.lang-dropdown');if(!dropdown)return;var btn=dropdown.querySelector('.lang-btn');var menu=dropdown.querySelector('.lang-menu');if(!btn||!menu)return;btn.addEventListener('click',function(e){e.stopPropagation();menu.classList.toggle('show');});document.addEventListener('click',function(){menu.classList.remove('show');});menu.addEventListener('click',function(e){if(!e.target.closest('a'))e.stopPropagation();});menu.querySelectorAll('a').forEach(function(link){link.addEventListener('click',function(){localStorage.setItem('toolhub-lang-chosen','1');});});});})(); 2 3 4/* ===== Custom English date picker (replaces browser-native date calendar) ===== */ 5/* perf(batch46-B, 2026-08-17): the calendar widget (42+ nodes) and its render 6 * listeners were built at script execution on EVERY page, even pages with no 7 * date input at all. Now the calendar DOM is created lazily by ensureDP() on 8 * the first date-input interaction; the MutationObserver (cheap) still starts 9 * immediately so dynamically added date rows are enhanced as before. */ 10(function () { 11 var dp = null, titleEl = null, weekEl = null, gridEl = null; 12 var viewY = 0, viewM = 0, currentInput = null; 13 14 var MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December']; 15 var WEEKDAYS = ['Su','Mo','Tu','We','Th','Fr','Sa']; 16 var pad = function (n) { return n < 10 ? '0' + n : '' + n; }; 17 var fmt = function (d) { return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()); }; 18 19 function ensureDP() { 20 if (dp) return dp; 21 dp = document.createElement('div'); 22 dp.className = 'muxtly-dp'; 23 dp.style.cssText = 'position:fixed;z-index:2147483000;display:none;background:var(--surface,#ffffff);border:1px solid var(--border,#d1d5db);border-radius:12px;box-shadow:0 12px 40px rgba(0,0,0,.18);padding:10px;width:264px;color:var(--text,#111827);user-select:none;font-size:.85rem'; 24 dp.innerHTML = 25 '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">' + 26 '<button type="button" class="muxtly-dp-prev" style="border:1px solid var(--border,#d1d5db);background:var(--surface,#f9fafb);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:1rem;line-height:1">‹</button>' + 27 '<span class="muxtly-dp-title" style="font-weight:700;font-size:.9rem"></span>' + 28 '<button type="button" class="muxtly-dp-next" style="border:1px solid var(--border,#d1d5db);background:var(--surface,#f9fafb);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:1rem;line-height:1">›</button>' + 29 '</div>' + 30 '<div class="muxtly-dp-week" style="display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-weight:600;color:var(--text-muted,#6b7280);font-size:.72rem;margin-bottom:4px"></div>' + 31 '<div class="muxtly-dp-grid" style="display:grid;grid-template-columns:repeat(7,1fr);gap:2px;text-align:center"></div>'; 32 document.body.appendChild(dp); 33 titleEl = dp.querySelector('.muxtly-dp-title'); 34 weekEl = dp.querySelector('.muxtly-dp-week'); 35 gridEl = dp.querySelector('.muxtly-dp-grid');
36 WEEKDAYS.forEach(function (w) { 37 var s = document.createElement('div'); s.textContent = w; weekEl.appendChild(s); 38 }); 39 dp.querySelector('.muxtly-dp-prev').addEventListener('click', function (e) { e.stopPropagation(); viewM--; if (viewM < 0) { viewM = 11; viewY--; } render(); }); 40 dp.querySelector('.muxtly-dp-next').addEventListener('click', function (e) { e.stopPropagation(); viewM++; if (viewM > 11) { viewM = 0; viewY++; } render(); }); 41 dp.addEventListener('click', function (e) { e.stopPropagation(); }); 42 document.addEventListener('click', close); 43 document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); }); 44 window.addEventListener('scroll', close, true); 45 return dp; 46 } 47 48 function close() { 49 if (!dp) return; 50 dp.style.display = 'none'; 51 currentInput = null; 52 } 53 54 function render() { 55 titleEl.textContent = MONTHS[viewM] + ' ' + viewY; 56 gridEl.innerHTML = ''; 57 var first = new Date(viewY, viewM, 1); 58 var startDow = first.getDay(); 59 var daysInMonth = new Date(viewY, viewM + 1, 0).getDate(); 60 var today = new Date(); today.setHours(0, 0, 0, 0); 61 var todayStr = fmt(today); 62 var selectedStr = currentInput && currentInput.value ? currentInput.value : ''; 63 var blank = daysInMonth + startDow; 64 var cells = Math.ceil(blank / 7) * 7; 65 for (var i = 0; i < cells; i++) { 66 var d = i - startDow + 1; 67 var cell = document.createElement('button'); 68 cell.type = 'button'; 69 if (d < 1 || d > daysInMonth) { 70 cell.style.visibility = 'hidden'; 71 } else { 72 var dt = new Date(viewY, viewM, d); 73 var ds = fmt(dt); 74 cell.textContent = d; 75 cell.style.cssText = 'border:none;background:none;border-radius:6px;height:30px;cursor:pointer;color:var(--text,#111827)'; 76 if (ds === todayStr) { cell.style.fontWeight = '800'; cell.style.color = '#2563eb'; } 77 if (ds === selectedStr) { cell.style.background = '#2563eb'; cell.style.color = '#fff'; cell.style.fontWeight = '700'; } 78 cell.addEventListener('mouseenter', function () { 79 if (this.style.background !== 'rgb(37, 99, 235)') this.style.background = 'var(--primary,#2563eb)'; 80 if (this.style.background.indexOf('37, 99, 235') === -1 && this.style.background !== 'rgb(37, 99, 235)') this.style.background = 'rgba(37,99,235,.12)'; 81 }); 82 cell.addEventListener('mouseleave', function () { 83 if (this.style.background.indexOf('rgba') !== -1) this.style.background = 'none'; 84 }); 85 (function (dsv) { 86 cell.addEventListener('click', function () { 87 if (currentInput) { 88 currentInput.value = dsv; 89 currentInput.dispatchEvent(new Event('input', { bubbles: true })); 90 currentInput.dispatchEvent(new Event('change', { bubbles: true })); 91 } 92 close(); 93 }); 94 })(ds); 95 } 96 gridEl.appendChild(cell); 97 } 98 } 99 100 function open(input) { 101 ensureDP(); 102 var now = new Date(); 103 var v = input.value; 104 if (v && /^\d{4}-\d{2}-\d{2}$/.test(v)) { 105 var parts = v.split('-'); 106 viewY = parseInt(parts[0], 10); viewM = parseInt(parts[1], 10) - 1; 107 } else { 108 viewY = now.getFullYear(); viewM = now.getMonth(); 109 } 110 currentInput = input; 111 render(); 112 var rect = input.getBoundingClientRect(); 113 var top = rect.bottom + 6; 114 if (top + 320 > window.innerHeight) { top = rect.top - 310; } 115 if (top < 4) { top = 4; } 116 var left = Math.min(Math.max(4, rect.left), window.innerWidth - 280); 117 dp.style.display = 'block'; 118 dp.style.top = top + 'px'; 119 dp.style.left = left + 'px'; 120 } 121 122 function enhance() { 123 document.querySelectorAll('input[data-date], input[type="date"]').forEach(function (inp) { 124 if (inp.dataset.muxtlyDp) return; 125 inp.dataset.muxtlyDp = '1'; 126 var v = inp.value; 127 if (inp.type === 'date') { try { inp.type = 'text'; } catch (e) { /* keep date type */ } } 128 inp.value = v; 129 inp.setAttribute('placeholder', 'dd/mm/yyyy'); 130 inp.readOnly = true; 131 inp.style.cursor = 'pointer'; 132 inp.addEventListener('click', function (e) { e.stopPropagation(); open(inp); }); 133 inp.addEventListener('keydown', function (e) { 134 if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); open(inp); } 135 }); 136 }); 137 } 138 enhance(); 139 if (document.readyState === 'loading') { 140 document.addEventListener('DOMContentLoaded', enhance); 141 } 142 var observer = new MutationObserver(function (mutations) { 143 for (var i = 0; i < mutations.length; i++) { 144 var added = mutations[i].addedNodes; 145 for (var j = 0; j < added.length; j++) { 146 var node = added[j]; 147 if (node.nodeType === 1) { 148 if (node.tagName === 'INPUT' && (node.getAttribute('data-date') || node.type === 'date')) { enhance(); return; } 149 if (node.querySelectorAll) { if (node.querySelectorAll('input[data-date], input[type="date"]').length) { enhance(); return; } } 150 } 151 } 152 } 153 }); 154 observer.observe(document.documentElement || document.body || document, { childList: true, subtree: true }); 155})();
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.