PageSourceSearch

https://qrrq.io/assets/js/app.js?v=1790262222

js qrrq.io collected 2026-09-24 15:04:05 UTC 56,729 bytes, 138 lines download raw bytes

1'use strict';window.QRForge=window.QRForge||{};QRForge.FileValidator={rules:{logo:{mimeTypes:['image/png','image/jpeg','image/gif','image/webp'],extensions:['png','jpg','jpeg','gif','webp'],maxSize:2*1024*1024,label:'PNG, JPG, GIF, WebP'},pdf:{mimeTypes:['application/pdf'],extensions:['pdf'],maxSize:20*1024*1024,label:'PDF'},csv:{mimeTypes:['text/csv','application/vnd.ms-excel'],extensions:['csv'],maxSize:10*1024*1024,label:'CSV'}},validate:function(file,type){var rule=this.rules[type];if(!rule)return{valid:false,error:'Unknown file type: '+type};if(!file)return{valid:false,error:'No file selected.'};var ext=file.name.split('.').pop().toLowerCase();if(!rule.extensions.includes(ext)){return{valid:false,error:rule.label+' only.'};}
2if(!rule.mimeTypes.includes(file.type)){return{valid:false,error:rule.label+' only.'};}
3if(file.size>rule.maxSize){var maxMB=Math.round(rule.maxSize/(1024*1024));return{valid:false,error:'Max '+maxMB+'MB.'};}
4return{valid:true,error:null};}};(()=>{const bar=document.createElement('div');bar.id='qf-page-progress';document.documentElement.appendChild(bar);let running=false;function startBar(){if(running)return;running=true;bar.style.cssText='width:0;opacity:1;transition:none';bar.offsetWidth;bar.style.transition='width 8s cubic-bezier(0.1,0.6,0.3,1)';bar.style.width='85%';}
5function clearSkeletons(){document.querySelectorAll('.qf-skeleton-overlay').forEach(function(el){el.remove();});}
6function finishBar(){clearSkeletons();if(!running)return;bar.style.transition='width 0.2s ease, opacity 0.4s 0.2s ease';bar.style.width='100%';bar.style.opacity='0';running=false;}
7function sL(w){return'<div class="qf-skel qf-skel-text" style="width:'+(w||'100%')+'"></div>';}
8function sB(h){return'<div class="qf-skel" style="width:100%;height:'+(h||'120px')+';border-radius:8px;margin-bottom:16px;"></div>';}
9function sCard(inner){return'<div class="qf-skel-card">'+inner+'</div>';}
10function sTitle(w){return'<div class="qf-skel qf-skel-title" style="width:'+(w||'220px')+';height:28px;margin-bottom:20px;"></div>';}
11function sStatCards(n){var h='<div class="qf-skel-grid" style="margin-bottom:24px;">';for(var i=0;i<(n||4);i++)h+=sCard(sB('48px')+sL('50%'));return h+'</div>';}
12function sTableRows(cols,rows){var h='<div class="qf-skel-card" style="padding:16px;">';h+='<div style="display:flex;gap:12px;margin-bottom:16px;">';for(var c=0;c<cols;c++)h+='<div class="qf-skel qf-skel-text" style="width:'+(100/cols-2)+'%;height:14px;"></div>';h+='</div>';for(var r=0;r<(rows||5);r++){h+='<div style="display:flex;gap:12px;margin-bottom:12px;">';for(var c2=0;c2<cols;c2++)h+='<div class="qf-skel qf-skel-text" style="width:'+(100/cols-2)+'%;height:12px;"></div>';h+='</div>';}
13return h+'</div>';}
14function sChartBlock(){return sCard(sB('200px')+sL('30%'));}
15var skeletons={dashIndex:function(){return sTitle('260px')+sL('55%')+'<div style="height:12px"></div>'+
16sStatCards(4)+
17sChartBlock()+'<div class="qf-skel-row">'+'<div class="qf-skel-card" style="flex:1;">'+sB('24px')+sTableRows(3,4)+'</div>'+'<div class="qf-skel-card" style="flex:1;">'+sB('24px')+sTableRows(3,4)+'</div>'+'</div>';},dashQRCodes:function(){var h='<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">'+
18sTitle('180px')+'<div class="qf-skel" style="width:120px;height:36px;border-radius:8px;"></div></div>'+'<div style="display:flex;gap:12px;margin-bottom:20px;">'+'<div class="qf-skel" style="width:80px;height:32px;border-radius:16px;"></div>'+'<div class="qf-skel" style="width:80px;height:32px;border-radius:16px;"></div>'+'<div class="qf-skel" style="width:80px;height:32px;border-radius:16px;"></div>'+'<div class="qf-skel" style="flex:1;height:36px;border-radius:8px;max-width:240px;margin-left:auto;"></div>'+'</div>'+'<div class="qf-skel-grid">';for(var i=0;i<6;i++)h+=sCard('<div class="qf-skel" style="width:100%;height:60px;border-radius:8px 8px 0 0;margin-bottom:12px;"></div>'+sL('70%')+sL('50%')+'<div style="height:8px"></div>'+sL('40%'));return h+'</div>';},dashCreateQR:function(){return sTitle('200px')+'<div style="display:flex;gap:24px;">'+'<div style="flex:1;">'+'<div style="display:flex;gap:8px;margin-bottom:20px;">'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'</div>'+
19sB('40px')+sB('40px')+sB('40px')+sB('80px')+'</div>'+'<div style="width:320px;flex-shrink:0;">'+'<div class="qf-skel-card" style="text-align:center;padding:24px;">
19'+'<div class="qf-skel" style="width:200px;height:200px;border-radius:12px;margin:0 auto 16px;"></div>'+
20sL('60%')+'</div>'+'</div>'+'</div>';},dashAnalytics:function(){return'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">'+
21sTitle('180px')+'<div style="display:flex;gap:8px;">'+'<div class="qf-skel" style="width:50px;height:30px;border-radius:15px;"></div>'+'<div class="qf-skel" style="width:50px;height:30px;border-radius:15px;"></div>'+'<div class="qf-skel" style="width:50px;height:30px;border-radius:15px;"></div>'+'</div></div>'+
22sStatCards(3)+'<div class="qf-skel-row" style="margin-bottom:20px;">'+'<div class="qf-skel-card" style="flex:1;">'+sB('220px')+'</div>'+'<div class="qf-skel-card" style="flex:1;">'+sB('220px')+'</div>'+'</div>'+'<div class="qf-skel-row">'+'<div class="qf-skel-card" style="flex:1;">'+sTableRows(2,5)+'</div>'+'<div class="qf-skel-card" style="flex:1;">'+sTableRows(2,5)+'</div>'+'</div>';},dashSettings:function(){return sTitle('160px')+'<div style="display:flex;gap:24px;">'+'<div style="flex:1;">'+
23sCard('<div class="qf-skel" style="width:64px;height:64px;border-radius:50%;margin-bottom:16px;"></div>'+sB('40px')+sB('40px')+sB('40px')+sB('40px'))+
24sCard(sL('40%')+'<div style="height:8px"></div>'+sB('40px')+sB('40px'))+'</div>'+'<div style="width:300px;flex-shrink:0;">'+
25sCard(sB('60px')+sL('70%')+sL('60%')+sL('50%')+sL('65%'))+
26sCard(sL('80%')+sL('60%')+sL('70%'))+'</div>'+'</div>';},dashSubscription:function(){return sCard('<div style="display:flex;align-items:center;gap:16px;">'+'<div class="qf-skel" style="width:48px;height:48px;border-radius:12px;"></div>'+'<div style="flex:1;">'+sL('40%')+sL('25%')+'</div></div>')+'<div style="height:16px"></div>'+'<div class="qf-skel-grid">'+
27sCard(sB('48px')+sL('60%')+sB('8px'))+
28sCard(sB('48px')+sL('50%')+sB('8px'))+
29sCard(sB('48px')+sL('55%')+sB('8px'))+
30sCard(sB('48px')+sL('45%')+sB('8px'))+'</div>'+'<div style="height:20px"></div>'+sTitle('160px')+'<div class="qf-skel-grid">'+
31sCard(sB('80px')+sL('50%')+sL('40%')+sL('60%')+sL('55%')+sB('36px'))+
32sCard(sB('80px')+sL('50%')+sL('40%')+sL('60%')+sL('55%')+sB('36px'))+
33sCard(sB('80px')+sL('50%')+sL('40%')+sL('60%')+sL('55%')+sB('36px'))+'</div>';},dashTemplates:function(){var h=sTitle('180px')+'<div style="display:flex;gap:8px;margin-bottom:20px;">'+'<div class="qf-skel" style="width:70px;height:30px;border-radius:15px;"></div>'+'<div class="qf-skel" style="width:70px;height:30px;border-radius:15px;"></div>'+'<div class="qf-skel" style="width:70px;height:30px;border-radius:15px;"></div>'+'</div><div class="qf-skel-grid">';for(var i=0;i<6;i++)h+=sCard('<div class="qf-skel" style="width:100%;height:140px;border-radius:8px;margin-bottom:12px;"></div>'+sL('60%')+sL('40%'));return h+'</div>';},dashLinkpages:function(){var h=sTitle('180px')+'<div class="qf-skel-grid">';for(var i=0;i<3;i++)h+=sCard('<div class="qf-skel" style="width:100%;height:100px;border-radius:8px;margin-bottom:12px;"></div>'+sL('50%')+sL('30%'));return h+'</div>';},dashBulk:function(){return sTitle('200px')+
34sCard('<div style="display:flex;justify-content:space-between;margin-bottom:16px;">'+sL('30%')+'<div class="qf-skel" style="width:140px;height:32px;border-radius:8px;"></div></div>'+'<div class="qf-skel" style="width:100%;height:140px;border-radius:12px;border:2px dashed rgba(0,0,0,0.08);"></div>');},dashApiKeys:function(){return sTitle('160px')+
35sCard(sL('30%')+'<div style="height:8px"></div>'+'<div class="qf-skel" style="width:100%;height:44px;border-radius:8px;margin-bottom:12px;"></div>'+'<div style="display:flex;gap:8px;">'+'<div class="qf-skel" style="width:100px;height:36px;border-radius:8px;"></div>'+'<div class="qf-skel" style="width:100px;height:36px;border-radius:8px;"></div></div>')+'<div style="height:16px"></div>'+
36sCard(sL('25%')+'<div style="height:12px"></div>'+sB('80px')+sL('30%')+'<div style="height:12px"></div>'+sB('80px')+sL('30%')+'<div style="height:12px"></div>'+sB('80px'));},home:function(){return'<div style="max-width:1100px;margin:0 auto;padding:40px 20px;text-align:center;">'+'<div class="qf-skel" style="width:400px;height:40px;border-radius:8px;margin:0 auto 16px;"></div>'+'<div class="qf-skel" style="width:300px;height:18px;border-radius:8px;margin:0 auto 32px;"></div>'+'<div class="qf-skel" style="width:100%;height:400px;border-radius:16px;margin-bottom:60px;"></div>'+'<div class="qf-skel-grid">'+
37sCard(sB('48px')+sL('60%')+sL('80%'))+
38sCard(sB('48px')+sL('60%')+sL('80%'))+
39sCard(sB('48px')+sL('60%')+sL('80%'))+
40sCard(sB('48px')+sL('60%')+sL('80%'))+'</div></div>';},pricing:function(){return'<div style="max-width:1100px;margin:0 auto;padding:40px 20px;text-align:center;">'+'<div class="qf-skel" style="width:300px;height:36px;border-radius:8px;margin:0 auto 12px;"></div>'+'<div class="qf-skel" style="width:220px;height:16px;border-radius:8px;margin:0 auto 24px;"></div>'+'<div class="qf-skel" style="width:180px;height:36px;border-radius:18px;margin:0 auto 32px;"></div>'+'<div class="qf-skel-grid">'+
41sCard(sB('60px')+sL('50%')+sL('35%')+'<div style="height:12px"></div>'+sB('32px')+sL('70%')+sL('65%')+sL('60%')+sL('55%')+sB('40px'))+
42sCard(sB('60px')+sL('50%')+sL('35%')+'<div style="height:12px"></div>'+sB('32px')+sL('70%')+sL('65%')+sL('60%')+sL('55%')+sB('40px'))+
43sCard(sB('60px')+sL('50%')+sL('35%')+'<div style="height:12px"></div>'+sB('32px')+sL('70%')+sL('65%')+sL('60%')+sL('55%')+sB('40px'))+'</div></div>';},features:function(){var h='<div style="max-width:1100px;margin:0 auto;padding:40px 20px;text-align:center;">'+'<div class="qf-skel" style="width:300px;height:36px;border-radius:8px;margin:0 auto 12px;"></div>'+'<div class="qf-skel" style="width:400px;height:16px;border-radius:8px;margin:0 auto 32px;"></div>'+'<div class="qf-skel-grid">';for(var i=0;i<8;i++)h+=sCard('<div class="qf-skel" style="width:48px;height:48px;border-radius:12px;margin-bottom:12px;"></div>'+sL('60%')+sL('80%'));return h+'</div></div>';},generator:function(){return'<div style="max-width:1100px;margin:0 auto;padding:40px 20px;">'+'<div style="display:flex;gap:24px;">'+'<div style="flex:1;">'+'<div style="display:flex;gap:8px;margin-bottom:20px;">'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'<div class="qf-skel" style="width:60px;height:28px;border-radius:14px;"></div>'+'</div>'+
44sB('44px')+sB('44px')+sB('100px')+'</div>'+'<div style="width:320px;flex-shrink:0;">'+'<div class="qf-skel-card" style="text-align:center;padding:24px;">
44'+'<div class="qf-skel" style="width:200px;height:200px;border-radius:12px;margin:0 auto 16px;"></div>'+
45sL('60%')+'</div></div>'+'</div></div>';},adminDash:function(){return sTitle('200px')+sStatCards(4)+'<div class="qf-skel-row" style="margin-bottom:20px;">'+
46sChartBlock()+sChartBlock()+'</div>'+'<div class="qf-skel-row">'+'<div class="qf-skel-card" style="flex:1;">'+sTableRows(4,5)+'</div>'+'<div class="qf-skel-card" style="flex:1;">'+sTableRows(4,5)+'</div>'+'</div>';},adminTable:function(){return sTitle('180px')+
47sCard('<div class="qf-skel" style="width:100%;height:40px;border-radius:8px;margin-bottom:16px;"></div>')+
48sTableRows(6,8);},adminAnalytics:function(){return sTitle('180px')+sStatCards(1)+
49sChartBlock()+'<div class="qf-skel-row" style="margin-bottom:20px;">'+
50sChartBlock()+sChartBlock()+'</div>'+'<div class="qf-skel-row">'+'<div class="qf-skel-card" style="flex:1;">'+sTableRows(2,5)+'</div>'+'<div class="qf-skel-card" style="flex:1;">'+sTableRows(2,5)+'</div>'+'</div>';}};function getSkeletonForPath(path){var p=path.replace(/^\/(en|tr|de|es|ru)(\/|$)/,'/');if(!p.startsWith('/'))p='/'+p;if(p==='/dashboard'||p==='/dashboard/')return skeletons.dashIndex;if(p==='/dashboard/qrcodes')return skeletons.dashQRCodes;if(p==='/dashboard/create-qr'||p.startsWith('/dashboard/edit-qr'))return skeletons.dashCreateQR;if(p==='/dashboard/analytics'||p.startsWith('/dashboard/qr-analytics'))return skeletons.dashAnalytics;if(p==='/dashboard/settings')return skeletons.dashSettings;if(p==='/dashboard/subscription')return skeletons.dashSubscription;if(p==='/dashboard/templates')return skeletons.dashTemplates;if(p.startsWith('/dashboard/linkpages'))return skeletons.dashLinkpages;if(p==='/dashboard/bulk')return skeletons.dashBulk;if(p==='/dashboard/api-keys')return skeletons.dashApiKeys;const ap=window.__appConfig?.adminPrefix||'/qr-admin';if(p===ap||p===ap+'/')return skeletons.adminDash;if(p===ap+'/analytics')return skeletons.adminAnalytics;if(p===ap+'/users'||p===ap+'/qrcodes'||p===ap+'/payments'||p===ap+'/plans'||p===ap+'/contact-messages')return skeletons.adminTable;if(p.startsWith(ap+'/'))return skeletons.adminDash;if(p==='/'||p==='')return skeletons.home;if(p==='/pricing')return skeletons.pricing;if(p==='/features')return skeletons.features;if(p==='/generator')return skeletons.generator;if(document.querySelector('.dashboard-content'))return skeletons.dashIndex;return skeletons.home;}
51var pendingPath=null;function showSkeleton(){clearSkeletons();var builder=getSkeletonForPath(pendingPath||location.pathname);var container=document.querySelector('.dashboard-content')||document.querySelector('main');if(!container)return;container.innerHTML='<div class="qf-skeleton-overlay" style="padding:0 4px;">'+builder()+'</div>';}
52function isNavigationLink(e){const a=e.target.closest('a[href]');if(!a||a.target==='_blank'||a.hasAttribute('download')||e.ctrlKey||e.metaKey||e.shiftKey)return false;const href=a.getAttribute('href');if(!href||href.startsWith('#')||href.startsWith('javascript')||href.startsWith('mailto')||href.startsWith('tel'))return false;if(a.closest('.modal, [data-modal], .tab-btn, .dropdown, [data-action], [data-toggle]')||a.dataset.action||a.dataset.modal)return false;try{const url=new URL(href,location.origin);if(url.origin!==location.origin)return false;if(url.pathname===location.pathname&&url.search===location.search)return false;}catch(e){return false;}
53return true;}
54document.addEventListener('click',(e)=>{if(!isNavigationLink(e))return;var a=e.target.closest('a[href]');try{pendingPath=new URL(a.getAttribute('href'),location.origin).pathname;}catch(err){pendingPath=null;}
55startBar();setTimeout(function(){if(e.defaultPrevented){finishBar();return;}
56showSkeleton();},100);});document.addEventListener('submit',()=>startBar());window.addEventListener('pageshow',()=>finishBar());window.addEventListener('load',()=>finishBar());})();(()=>{const ICONS={success:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>',error:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',warning:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/>
56<line x1="12" y1="17" x2="12.01" y2="17"/></svg>',info:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',};const _t=window.__t||{};const TITLES={success:_t.success||'Success',error:_t.error||'Error',warning:_t.warning||'Warning',info:_t.info||'Info'};let container=null;const getContainer=()=>{if(!container||!document.body.contains(container)){container=document.createElement('div');container.className='qf-toast-container';document.body.appendChild(container);}
57return container;};QRForge.toast=(message,type='info',opts={})=>{const title=opts.title||TITLES[type]||TITLES.info;const duration=opts.duration||(type==='error'?5000:3500);const el=document.createElement('div');el.className=`qf-toast qf-toast-${type}`;el.innerHTML=`
58      <div class="qf-toast-icon">${ICONS[type] || ICONS.info}</div>
59      <div class="qf-toast-body">
60        <div class="qf-toast-title">${title}</div>
61        <div class="qf-toast-message">${message}</div>
62      </div>
63      <button class="qf-toast-close" aria-label="Close">
64        <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
65      </button>
66      <div class="qf-toast-progress" style="width:100%"></div>
67    `;const dismiss=()=>{el.classList.remove('qf-toast-visible');el.classList.add('qf-toast-exit');setTimeout(()=>el.remove(),350);};el.querySelector('.qf-toast-close').addEventListener('click',dismiss);getContainer().appendChild(el);el.offsetHeight;el.classList.add('qf-toast-visible');const bar=el.querySelector('.qf-toast-progress');if(bar){bar.style.transitionDuration=duration+'ms';requestAnimationFrame(()=>{bar.style.width='0%';});}
68setTimeout(dismiss,duration);};QRForge.btnLoading=(btn,loading)=>{if(!btn)return;if(loading){btn._savedHTML=btn.innerHTML;btn._savedWidth=btn.offsetWidth;btn.style.minWidth=btn._savedWidth+'px';btn.disabled=true;btn.classList.add('btn-loading');btn.innerHTML='<span class="btn-spinner"></span>'+(btn.dataset.loadingText||btn.textContent.trim());}else{btn.disabled=false;btn.classList.remove('btn-loading');if(btn._savedHTML)btn.innerHTML=btn._savedHTML;btn.style.minWidth='';}};QRForge.confirm=(message,opts={})=>{return new Promise((resolve)=>{const type=opts.type||'danger';const title=opts.title||(type==='danger'?(_t.are_you_sure||'Are you sure?'):(_t.confirm||'Confirm'));const confirmText=opts.confirmText||(type==='danger'?(_t.delete||'Delete'):(_t.confirm||'Confirm'));const cancelText=opts.cancelText||(_t.cancel||'Cancel');const btnClass=type==='danger'?'qf-confirm-btn-danger':type==='warning'?'qf-confirm-btn-warning':'qf-confirm-btn-ok';const overlay=document.createElement('div');overlay.className=`qf-confirm-overlay qf-confirm-${type}`;overlay.innerHTML=`
69        <div class="qf-confirm-dialog">
70          <div class="qf-confirm-header">
71            <div class="qf-confirm-icon">${ICONS[type === 'danger' ? 'error' : type] || ICONS.warning}</div>
72            <h3 class="qf-confirm-title">${title}</h3>
73          </div>
74          <div class="qf-confirm-body">${message}</div>
75          <div class="qf-confirm-actions">
76            <button class="qf-confirm-btn qf-confirm-btn-cancel">${cancelText}</button>
77            <button class="qf-confirm-btn ${btnClass}">${confirmText}</button>
78          </div>
79        </div>
80      `;const close=(result)=>{overlay.classList.remove('qf-confirm-visible');setTimeout(()=>overlay.remove(),200);resolve(result);};overlay.querySelector('.qf-confirm-btn-cancel').addEventListener('click',()=>close(false));overlay.querySelector(`.${btnClass}`).addEventListener('click',()=>close(true));overlay.addEventListener('click',(e)=>{if(e.target===overlay)close(false);});document.addEventListener('keydown',function onEsc(e){if(e.key==='Escape'){document.removeEventListener('keydown',onEsc);close(false);}});document.body.appendChild(overlay);requestAnimationFrame(()=>overlay.classList.add('qf-confirm-visible'));overlay.querySelector(`.${btnClass}`).focus();});};})();(()=>{const navbar=document.getElementById('navbar');const hamburger=document.getElementById('hamburger-toggle');const mobileMenu=document.getElementById('mobile-menu');if(navbar){window.addEventListener('scroll',()=>{if(window.scrollY>50){navbar.classList.add('scrolled');}else{navbar.classList.remove('scrolled');}});}
81if(hamburger&&mobileMenu){hamburger.addEventListener('click',(e)=>{e.stopPropagation();mobileMenu.classList.toggle('open');hamburger.classList.toggle('active');hamburger.setAttribute('aria-expanded',mobileMenu.classList.contains('open'));});document.addEventListener('click',(e)=>{if(mobileMenu.classList.contains('open')&&!mobileMenu.contains(e.target)&&!hamburger.contains(e.target)){mobileMenu.classList.remove('open');hamburger.classList.remove('active');hamburger.setAttribute('aria-expanded','false');}});}
82document.querySelectorAll('.dropdown-toggle').forEach((toggle)=>{toggle.addEventListener('click',(e)=>{e.preventDefault();e.stopPropagation();const dropdown=toggle.closest('.dropdown');if(!dropdown)return;document.querySelectorAll('.dropdown.open').forEach((d)=>{if(d!==dropdown)d.classList.remove('open');});dropdown.classList.toggle('open');});});document.addEventListener('click',()=>{document.querySelectorAll('.dropdown.open').forEach((d)=>{d.classList.remove('open');});});})();(()=>{const dismissFlash=(el)=>{el.style.opacity='0';el.style.transform='translateY(-10px)';el.style.transition='opacity 0.4s ease, transform 0.4s ease';setTimeout(()=>el.remove(),400);};document.querySelectorAll('.flash-message').forEach((msg)=>{setTimeout(()=>dismissFlash(msg),5000);const closeBtn=msg.querySelector('.flash-close');if(closeBtn){closeBtn.addEventListener('click',()=>dismissFlash(msg));}});})();const CSRFHelper=(()=>{const getToken=()=>{const meta=document.querySelector('meta[name="csrf-token"]');return meta?meta.getAttribute('content'):'';};const fetchWithCSRF=(url,options={})=>{const token=getToken();const headers=new Headers(options.headers||{});if(token){headers.set('X-CSRF-TOKEN',token);}
83if(!(options.body instanceof FormData)&&!headers.has('Content-Type')){headers.set('Content-Type','application/json');}
84headers.set('X-Requested-With','XMLHttpRequest');return fetch(url,{...options,headers});};return{getToken,fetchWithCSRF};})();window.QRForge.csrf=CSRFHelper;QRForge.QRGenerator=Object.assign(QRForge.QRGenerator||{},(()=>{let qrLib=null;let libReady=false;const libReadyCallbacks=[];const loadLibrary=()=>{return new Promise((resolve,reject)=>{if(libReady){resolve();return;}
85if(typeof qrcode!=='undefined'){qrLib=qrcode;libReady=true;resolve();return;}
86const script=document.createElement('script');script.src='https://cdn.jsdelivr.net/npm/[email protected]/qrcode.min.js';script.onload=()=>{qrLib=qrcode;libReady=true;libReadyCallbacks.forEach((cb)=>cb());libReadyCallbacks.length=0;resolve();};script.onerror=()=>reject(new Error('Failed to load QR code library'));document.head.appendChild(script);});};loadLibrary().catch((err)=>console.warn('QR lib load deferred:',err));const toUTF8ByteString=(str)=>{const bytes=new TextEncoder().encode(str);let out='';for(let i=0;i<bytes.length;i++){out+=String.fromCharCode(bytes[i]);}
87return out;};const generateMatrix=(data,ecLevel='M')=>
87{if(!libReady)throw new Error('QR library not loaded yet');const typeNumber=0;const ecMap={L:'L',M:'M',Q:'Q',H:'H'};const qr=qrLib(typeNumber,ecMap[ecLevel]||'M');const hasNonAscii=/[^\x00-\x7F]/.test(data);qr.addData(hasNonAscii?toUTF8ByteString(data):data,hasNonAscii?'Byte':undefined);qr.make();const count=qr.getModuleCount();const matrix=[];for(let r=0;r<count;r++){const row=[];for(let c=0;c<count;c++){row.push(qr.isDark(r,c));}
88matrix.push(row);}
89return matrix;};const drawModule=(ctx,x,y,size,pattern)=>{const r=size/2;switch(pattern){case'rounded':ctx.beginPath();ctx.roundRect(x,y,size,size,size*0.3);ctx.fill();break;case'dots':ctx.beginPath();ctx.arc(x+r,y+r,r*0.85,0,Math.PI*2);ctx.fill();break;case'sharp':ctx.beginPath();ctx.moveTo(x+r,y);ctx.lineTo(x+size,y+r);ctx.lineTo(x+r,y+size);ctx.lineTo(x,y+r);ctx.closePath();ctx.fill();break;case'square':default:ctx.fillRect(x,y,size,size);break;}};const drawFinder=(ctx,cx,cy,modSize,cornerStyle,fg,bg,isTransparent)=>{const s=modSize*7;const draw=(x,y,w,h,radius)=>{if(cornerStyle==='rounded'||cornerStyle==='dot'){ctx.beginPath();ctx.roundRect(x,y,w,h,radius);ctx.fill();}else if(cornerStyle==='sharp'){ctx.fillRect(x,y,w,h);}else{ctx.fillRect(x,y,w,h);}};ctx.fillStyle=fg;draw(cx,cy,s,s,cornerStyle==='dot'?s*0.35:modSize);if(isTransparent){ctx.save();ctx.globalCompositeOperation='destination-out';ctx.fillStyle='rgba(0,0,0,1)';draw(cx+modSize,cy+modSize,modSize*5,modSize*5,cornerStyle==='dot'?modSize*2:modSize*0.5);ctx.restore();}else{ctx.fillStyle=bg||'#ffffff';draw(cx+modSize,cy+modSize,modSize*5,modSize*5,cornerStyle==='dot'?modSize*2:modSize*0.5);}
90ctx.fillStyle=fg;draw(cx+modSize*2,cy+modSize*2,modSize*3,modSize*3,cornerStyle==='dot'?modSize*1.5:modSize*0.3);};const isFinderModule=(r,c,count)=>{return((r<7&&c<7)||(r<7&&c>=count-7)||(r>=count-7&&c<7));};const renderToCanvas=async(canvas,data,opts={})=>{await loadLibrary();const{foregroundColor='#000000',backgroundColor='#ffffff',transparentBg=false,gradient=false,gradientColor1='#000000',gradientColor2='#0066ff',pattern='square',cornerStyle='square',logoUrl=null,logoSize=20,frame='none',frameText='',frameColor='#000000',}=opts;const ecLevel=logoUrl?'H':'M';const matrix=generateMatrix(data||(window.__appConfig?.url||''),ecLevel);const count=matrix.length;const quiet=2;const frameHeight=frame!=='none'?40:0;const modSize=Math.floor((canvas.width-quiet*2*(canvas.width/(count+quiet*2)))/count);const totalSize=modSize*(count+quiet*2);canvas.width=totalSize;canvas.height=totalSize+frameHeight;const ctx=canvas.getContext('2d');if(!transparentBg){ctx.fillStyle=backgroundColor;ctx.fillRect(0,0,canvas.width,canvas.height);}else{ctx.clearRect(0,0,canvas.width,canvas.height);}
91let fgFill=foregroundColor;if(gradient){const grad=ctx.createLinearGradient(0,0,totalSize,totalSize);grad.addColorStop(0,gradientColor1);grad.addColorStop(1,gradientColor2);fgFill=grad;}
92const offset=quiet*modSize;ctx.fillStyle=fgFill;drawFinder(ctx,offset,offset,modSize,cornerStyle,fgFill,backgroundColor,transparentBg);drawFinder(ctx,offset+(count-7)*modSize,offset,modSize,cornerStyle,fgFill,backgroundColor,transparentBg);drawFinder(ctx,offset,offset+(count-7)*modSize,modSize,cornerStyle,fgFill,backgroundColor,transparentBg);ctx.fillStyle=fgFill;for(let r=0;r<count;r++){for(let c=0;c<count;c++){if(isFinderModule(r,c,count))continue;if(!matrix[r][c])continue;const x=offset+c*modSize;const y=offset+r*modSize;drawModule(ctx,x,y,modSize,pattern);}}
93if(logoUrl){try{const logo=await loadImage(logoUrl);const logoSizePx=totalSize*(logoSize/100);const logoX=(totalSize-logoSizePx)/2;const logoY=(totalSize-logoSizePx)/2;const pad=logoSizePx*0.1;ctx.fillStyle=backgroundColor;ctx.beginPath();ctx.roundRect(logoX-pad,logoY-pad,logoSizePx+pad*2,logoSizePx+pad*2,pad);ctx.fill();ctx.drawImage(logo,logoX,logoY,logoSizePx,logoSizePx);}catch(err){console.warn('Logo load failed:',err);}}
94if(frame!=='none'&&frameText){const fy=frame==='top-text'?0:totalSize;ctx.fillStyle=frameColor;ctx.fillRect(0,fy,totalSize,frameHeight);ctx.fillStyle='#ffffff';ctx.font=`bold ${Math.round(frameHeight * 0.5)}px sans-serif`;ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText(frameText,totalSize/2,fy+frameHeight/2);}};const loadImage=(src)=>{return new Promise((resolve,reject)=>{const img=new Image();img.crossOrigin='anonymous';img.onload=()=>resolve(img);img.onerror=reject;img.src=src;});};const toDataURL=(canvas,format='image/png')=>{return canvas.toDataURL(format);};const toSVG=(data,opts={})=>{const{foregroundColor='#000000',backgroundColor='#ffffff',pattern='square',logoUrl=null,}=opts;const ecLevel=logoUrl?'H':'M';const matrix=generateMatrix(data||(window.__appConfig?.url||''),ecLevel);const count=matrix.length;const modSize=10;const quiet=2;const size=(count+quiet*2)*modSize;let paths='';const offset=quiet*modSize;for(let r=0;r<count;r++){for(let c=0;c<count;c++){if(!matrix[r][c])continue;const x=offset+c*modSize;const y=offset+r*modSize;if(pattern==='dots'){const cx=x+modSize/2;const cy=y+modSize/2;const rad=modSize*0.42;paths+=`<circle cx="${cx}" cy="${cy}" r="${rad}" fill="${foregroundColor}"/>`;}else if(pattern==='rounded'){const rx=modSize*0.3;paths+=`<rect x="${x}" y="${y}" width="${modSize}" height="${modSize}" rx="${rx}" fill="${foregroundColor}"/>`;}else if(pattern==='smooth'){const s=modSize,hr=s/2;const isDk=(dr,dc)=>dr>=0&&dc>=0&&dr<count&&dc<count&&matrix[dr][dc];const L=isDk(r,c-1)?1:0,R=isDk(r,c+1)?1:0,T=isDk(r-1,c)?1:0,B=isDk(r+1,c)?1:0;const nc=L+R+T+B;if(nc===0){paths+=`<circle cx="${x+hr}" cy="${y+hr}" r="${hr}" fill="${foregroundColor}"/>`;}else if(nc>2||(L&&R)||(T&&B)){paths+=`<rect x="${x}" y="${y}" width="${s}" height="${s}" fill="${foregroundColor}"/>`;}else if(nc===1){let d;if(L)d=`M${x} ${y}h${hr}a${hr} ${hr} 0 0 1 0 ${s}H${x}z`;else if(R)d=`M${x+s} ${y+s}h${-hr}a${hr} ${hr} 0 0 1 0 ${-s}H${x+s}z`;else if(T)d=`M${x} ${y}h${s}v${hr}a${hr} ${hr} 0 0 1 ${-s} 0z`;else d=`M${x+s} ${y+s}h${-s}v${-hr}a${hr} ${hr} 0 0 1 ${s} 0z`;paths+=`<path d="${d}" fill="${foregroundColor}"/>`;}else{let d;if(L&&T)d=`M${x} ${y}h${s}v${hr}a${hr} ${hr} 0 0 1 ${-hr} ${hr}H${x}z`;else if(T&&R)d=`M${x+s} ${y}v${s}h${-hr}a${hr} ${hr} 0 0 1 ${-hr} ${-hr}V${y}z`;else if(R&&B)d=`M${x+s} ${y+s}h${-s}v${-hr}a${hr} ${hr} 0 0 1 ${hr} ${-hr}H${x+s}z`;else d=`M${x} ${y+s}v${-s}h${hr}a${hr} ${hr} 0 0 1 ${hr} ${hr}V${y+s}z`;paths+=`<path d="${d}" fill="${foregroundColor}"/>`;}}else{paths+=`<rect x="${x}" y="${y}" width="${modSize}" height="${modSize}" fill="${foregroundColor}"/>`;}}}
95return`<?xml version="1.0" encoding="UTF-8"?>
96<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${size} ${size}" width="${size}" height="${size}">
97  <rect width="${size}" height="${size}" fill="${backgroundColor}"/>
98  ${paths}
99</svg>`;};return{loadLibrary,generateMatrix,renderToCanvas,toDataURL,toSVG,};})());QRForge.Preview=(()=>{let debounceTimer=null;
99let currentType='url';const formatters={url:(f)=>{let v=f.url||'';if(v&&!/^https?:\/\//i.test(v))v='https://'+v;return v;},text:(f)=>f.text||'',email:(f)=>{const to=f.email||'';const subject=f.subject||'';const body=f.body||'';return`mailto:${to}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;},phone:(f)=>`tel:${f.phone || ''}`,sms:(f)=>{const phone=f.phone||'';const msg=f.message||'';return`sms:${phone}${msg ? '?body=' + encodeURIComponent(msg) : ''}`;},whatsapp:(f)=>{const phone=(f.phone||'').replace(/[^0-9]/g,'');const msg=f.message||'';return`https://wa.me/${phone}${msg ? '?text=' + encodeURIComponent(msg) : ''}`;},wifi:(f)=>{const ssid=f.ssid||'';const pass=f.password||'';const enc=f.encryption||'WPA';return`WIFI:T:${enc};S:${ssid};P:${pass};;`;},vcard:(f)=>{const fn=((f.firstName||'')+' '+(f.lastName||'')).trim();const lines=['BEGIN:VCARD','VERSION:3.0','PRODID:-//QR//EN',`N;CHARSET=UTF-8:${f.lastName || ''};${f.firstName || ''};;;`,`FN;CHARSET=UTF-8:${fn}`,];if(f.org)lines.push(`ORG;CHARSET=UTF-8:${f.org}`);if(f.title)lines.push(`TITLE;CHARSET=UTF-8:${f.title}`);if(f.phone)lines.push(`TEL:${f.phone}`);if(f.email)lines.push(`EMAIL:${f.email}`);if(f.website)lines.push(`URL:${f.website}`);if(f.address)lines.push(`ADR;CHARSET=UTF-8:;;${f.address};;;;`);lines.push('END:VCARD');return lines.join('\n');},location:(f)=>{const lat=f.latitude||'0';const lng=f.longitude||'0';let geo=`geo:${lat},${lng}`;if(f.query)geo+='?q='+encodeURIComponent(f.query);return geo;},event:(f)=>{const fmt=(d)=>(d?d.replace(/[-:]/g,'').replace('T','T'):'');return['BEGIN:VEVENT',`SUMMARY:${f.title || ''}`,`LOCATION:${f.location || ''}`,`DTSTART:${fmt(f.start)}`,`DTEND:${fmt(f.end)}`,`DESCRIPTION:${f.description || ''}`,'END:VEVENT',].join('\n');},crypto:(f)=>{const currency=(f.currency||'bitcoin').toLowerCase();const address=f.address||'';const amount=f.amount||'';return`${currency}:${address}${amount ? '?amount=' + amount : ''}`;},social:(f)=>f.social_url||'',};const getFormValues=()=>{const form=document.getElementById('qr-generator-form');if(!form)return{};const data={};const inputs=form.querySelectorAll('input, textarea, select');inputs.forEach((el)=>{if(el.name)data[el.name]=el.value;});return data;};const getDesignOptions=()=>{const get=(id,fallback)=>{const el=document.getElementById(id);return el?el.value:fallback;};return{foregroundColor:get('design-fg-color','#000000'),backgroundColor:get('design-bg-color','#ffffff'),gradient:document.getElementById('design-gradient')?.checked||false,gradientColor1:get('design-gradient-color1','#000000'),gradientColor2:get('design-gradient-color2','#0066ff'),pattern:get('design-pattern','square'),cornerStyle:get('design-corner-style','square'),logoUrl:QRForge._logoDataUrl||null,logoSize:parseInt(get('design-logo-size','20'),10),frame:get('design-frame','none'),frameText:get('design-frame-text',''),frameColor:get('design-frame-color','#000000'),};};const updatePreview=async()=>{const canvas=document.getElementById('qr-preview-canvas');if(!canvas)return;const formValues=getFormValues();const designOpts=getDesignOptions();const qrType=document.getElementById('qr-type-select')?.value||currentType;const formatter=formatters[qrType]||formatters.text;const data=formatter(formValues);if(!data||data.length===0)return;try{await QRForge.QRGenerator.renderToCanvas(canvas,data,designOpts);}catch(err){console.warn('Preview render error:',err);}};const debouncedUpdate=()=>{clearTimeout(debounceTimer);debounceTimer=setTimeout(updatePreview,300);};const switchQRType=(type)=>{currentType=type;document.querySelectorAll('.qr-type-fields').forEach((section)=>{section.style.display='none';});const active=document.getElementById(`qr-fields-${type}`);if(active)active.style.display='block';debouncedUpdate();};const init=()=>{const form=document.getElementById('qr-generator-form');if(!form)return;form.addEventListener('input',debouncedUpdate);form.addEventListener('change',debouncedUpdate);const typeSelect=document.getElementById('qr-type-select');if(typeSelect){typeSelect.addEventListener('change',(e)=>switchQRType(e.target.value));switchQRType(typeSelect.value);}
100document.querySelectorAll('.design-control').forEach((el)=>{el.addEventListener('input',debouncedUpdate);el.addEventListener('change',debouncedUpdate);});updatePreview();};return{init,updatePreview,switchQRType,formatters};})();
100QRForge.DesignControls=(()=>{const init=()=>{document.querySelectorAll('.pattern-option').forEach((opt)=>{opt.addEventListener('click',()=>{document.querySelectorAll('.pattern-option').forEach((o)=>o.classList.remove('active'));opt.classList.add('active');const patternInput=document.getElementById('design-pattern');if(patternInput){patternInput.value=opt.dataset.pattern;patternInput.dispatchEvent(new Event('change',{bubbles:true}));}});});document.querySelectorAll('.corner-option').forEach((opt)=>{opt.addEventListener('click',()=>{document.querySelectorAll('.corner-option').forEach((o)=>o.classList.remove('active'));opt.classList.add('active');const cornerInput=document.getElementById('design-corner-style');if(cornerInput){cornerInput.value=opt.dataset.corner;cornerInput.dispatchEvent(new Event('change',{bubbles:true}));}});});const logoInput=document.getElementById('design-logo-upload');const logoPreview=document.getElementById('design-logo-preview');const logoRemoveBtn=document.getElementById('design-logo-remove');if(logoInput){logoInput.addEventListener('change',(e)=>{const file=e.target.files[0];if(!file)return;var check=QRForge.FileValidator.validate(file,'logo');if(!check.valid){(QRForge.toast?QRForge.toast(check.error,'error'):alert(check.error));logoInput.value='';return;}
101const reader=new FileReader();reader.onload=(ev)=>{QRForge._logoDataUrl=ev.target.result;if(logoPreview){logoPreview.src=ev.target.result;logoPreview.style.display='block';}
102if(logoRemoveBtn)logoRemoveBtn.style.display='inline-block';QRForge.Preview.updatePreview();};reader.readAsDataURL(file);});}
103if(logoRemoveBtn){logoRemoveBtn.addEventListener('click',()=>{QRForge._logoDataUrl=null;if(logoPreview){logoPreview.src='';logoPreview.style.display='none';}
104if(logoInput)logoInput.value='';logoRemoveBtn.style.display='none';QRForge.Preview.updatePreview();});}
105const gradientToggle=document.getElementById('design-gradient');const gradientOptions=document.getElementById('gradient-options');if(gradientToggle&&gradientOptions){gradientToggle.addEventListener('change',()=>{gradientOptions.style.display=gradientToggle.checked?'block':'none';});}
106const frameSelect=document.getElementById('design-frame');const frameTextGroup=document.getElementById('frame-text-group');if(frameSelect&&frameTextGroup){frameSelect.addEventListener('change',()=>{frameTextGroup.style.display=frameSelect.value!=='none'?'block':'none';});}};const RISKY_CORNERS=['diamond','shield','hexagon','star'];const DENSE_PATTERNS=['square','rounded','smooth'];const CLOVER_FORBIDDEN_PATTERNS=['diamond','star','heart'];const isIncompatibleCorner=(corner,pattern)=>{if(!DENSE_PATTERNS.includes(pattern)&&RISKY_CORNERS.includes(corner))return true;if(corner==='clover'&&CLOVER_FORBIDDEN_PATTERNS.includes(pattern))return true;return false;};const applyTemplate=(designJson)=>{if(!designJson)return;const setVal=(id,val)=>{const el=document.getElementById(id);if(el&&val!==undefined){el.value=val;el.dispatchEvent(new Event('change',{bubbles:true}));}};const safeCornerStyle=designJson.cornerStyle&&designJson.pattern&&isIncompatibleCorner(designJson.cornerStyle,designJson.pattern)?'square':designJson.cornerStyle;setVal('design-fg-color',designJson.foregroundColor);setVal('design-bg-color',designJson.backgroundColor);setVal('design-pattern',designJson.pattern);setVal('design-corner-style',safeCornerStyle);setVal('design-frame',designJson.frame);setVal('design-frame-text',designJson.frameText);setVal('design-frame-color',designJson.frameColor);setVal('design-logo-size',designJson.logoSize);setVal('design-gradient-color1',designJson.gradientColor1);setVal('design-gradient-color2',designJson.gradientColor2);const gradientToggle=document.getElementById('design-gradient');if(gradientToggle){gradientToggle.checked=!!designJson.gradient;gradientToggle.dispatchEvent(new Event('change',{bubbles:true}));}
107if(designJson.pattern){document.querySelectorAll('.pattern-option').forEach((o)=>{o.classList.toggle('active',o.dataset.pattern===designJson.pattern);});}
108if(safeCornerStyle){document.querySelectorAll('.corner-option').forEach((o)=>{o.classList.toggle('active',o.dataset.corner===safeCornerStyle);});}
109QRForge.Preview.updatePreview();};return{init,applyTemplate};})();QRForge.Download=(()=>{const triggerDownload=(href,filename)=>{const a=document.createElement('a');a.href=href;a.download=filename;document.body.appendChild(a);a.click();document.body.removeChild(a);};const downloadPNG=(sourceCanvas,filename='qrcode.png',size=1024)=>{const exportCanvas=document.createElement('canvas');exportCanvas.width=size;exportCanvas.height=size;const ctx=exportCanvas.getContext('2d');ctx.imageSmoothingEnabled=false;ctx.drawImage(sourceCanvas,0,0,size,size);triggerDownload(exportCanvas.toDataURL('image/png'),filename);};const downloadSVG=(svgString,filename='qrcode.svg')=>{const blob=new Blob([svgString],{type:'image/svg+xml'});triggerDownload(URL.createObjectURL(blob),filename);};const downloadPDF=(canvas,filename='qrcode.pdf')=>{const imgData=canvas.toDataURL('image/png');const binary=atob(imgData.split(',')[1]);const bytes=new Uint8Array(binary.length);for(let i=0;i<binary.length;
109i++){bytes[i]=binary.charCodeAt(i);}
110const imgWidth=canvas.width;const imgHeight=canvas.height;const pageW=612;const pageH=792;const qrSize=Math.min(pageW-100,pageH-100,400);const xOff=(pageW-qrSize)/2;const yOff=(pageH-qrSize)/2;const stream=bytes;const streamLen=stream.length;const pdfParts=[];const offsets=[];const addObj=(content)=>{offsets.push(pdfParts.join('').length);pdfParts.push(content);};pdfParts.push('%PDF-1.4\n');addObj('1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n');addObj('2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n');addObj(`3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${pageW} ${pageH}] /Contents 4 0 R /Resources << /XObject << /Img 5 0 R >> >> >>\nendobj\n`);const contentStream=`q ${qrSize} 0 0 ${qrSize} ${xOff} ${yOff} cm /Img Do Q`;addObj(`4 0 obj\n<< /Length ${contentStream.length} >>\nstream\n${contentStream}\nendstream\nendobj\n`);addObj(`5 0 obj\n<< /Type /XObject /Subtype /Image /Width ${imgWidth} /Height ${imgHeight} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /FlateDecode /Length ${streamLen} >>\nstream\n`);const pdfHtml=`
111      <!DOCTYPE html>
112      <html>
113      <head><title>QR Code - ${window.__appConfig?.name || 'QR'}</title>
114      <style>
115        body { margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
116        img { max-width: 90vw; max-height: 90vh; }
117        @media print { body { margin: 0; } img { max-width: 100%; } }
118      </style>
119      </head>
120      <body>
121        <img src="${imgData}" alt="QR Code" />
122        <script>window.onload = () => window.print();<\/script>
123      </body>
124      </html>
125    `;const blob=new Blob([pdfHtml],{type:'text/html'});const url=URL.createObjectURL(blob);window.open(url,'_blank');};const init=()=>{const canvas=document.getElementById('qr-preview-canvas');document.getElementById('btn-download-png')?.addEventListener('click',()=>{if(canvas){const sizeInput=document.getElementById('download-size');const size=sizeInput?parseInt(sizeInput.value,10):1024;downloadPNG(canvas,'qr-code.png',size);}});document.getElementById('btn-download-svg')?.addEventListener('click',()=>{const formValues=QRForge.Preview.getFormValues?QRForge.Preview.getFormValues():{};const designOpts={};const typeSelect=document.getElementById('qr-type-select');const qrType=typeSelect?typeSelect.value:'url';const formatter=QRForge.Preview.formatters[qrType]||QRForge.Preview.formatters.text;const data=formatter(formValues);const svg=QRForge.QRGenerator.toSVG(data,designOpts);downloadSVG(svg,'qr-code.svg');});document.getElementById('btn-download-pdf')?.addEventListener('click',()=>{if(canvas)downloadPDF(canvas,'qr-code.pdf');});};return{init,downloadPNG,downloadSVG,downloadPDF};})();QRForge.Dashboard=(()=>{const deleteQR=async(id,triggerBtn)=>{const ok=await QRForge.confirm(_t.delete_qr_confirm||'This QR code will be permanently deleted.',{title:_t.delete_qr_title||'Delete QR Code?',type:'danger',confirmText:_t.delete||'Delete',});if(!ok)return;QRForge.btnLoading(triggerBtn,true);try{const res=await CSRFHelper.fetchWithCSRF(`/api/qrcodes/${id}`,{method:'DELETE',});if(res.ok){const card=document.querySelector(`[data-qr-id="${id}"]`);if(card){card.style.opacity='0';card.style.transform='scale(0.95)';card.style.transition='all 0.3s ease';setTimeout(()=>card.remove(),300);}
126QRForge.toast(_t.delete_qr_success||'QR code deleted.','success');}else{const data=await res.json().catch(()=>({}));QRForge.toast(data.message||_t.delete_qr_error||'Failed to delete QR code.','error');}}catch(err){console.error('Delete error:',err);QRForge.toast('Network error.','error');}finally{QRForge.btnLoading(triggerBtn,false);}};const toggleQRStatus=async(id,active,triggerBtn)=>{QRForge.btnLoading(triggerBtn,true);try{const res=await CSRFHelper.fetchWithCSRF(`/api/qrcodes/${id}/status`,{method:'PATCH',body:JSON.stringify({is_active:active}),});if(res.ok){const badge=document.querySelector(`[data-qr-id="${id}"] .status-badge`);if(badge){badge.textContent=active?'Active':'Paused';badge.className=`status-badge ${active ? 'badge-success' : 'badge-warning'}`;}}}catch(err){console.error('Toggle status error:',err);}finally{QRForge.btnLoading(triggerBtn,false);}};const generateApiKey=async(triggerBtn)=>{const ok=await QRForge.confirm(_t.api_regen_confirm||'The current API key will stop working immediately.',{title:_t.api_regen_title||'Regenerate API Key?',type:'warning',confirmText:_t.api_regen_btn||'Regenerate',});if(!ok)return;QRForge.btnLoading(triggerBtn,true);try{const res=await CSRFHelper.fetchWithCSRF('/api/keys/regenerate',{method:'POST',});const data=await res.json();if(res.ok&&data.api_key){const display=document.getElementById('api-key-display');if(display)display.textContent=data.api_key;copyToClipboard(data.api_key);QRForge.toast(_t.api_regen_success||'New API key generated.','success');}else{QRForge.toast(data.message||_t.api_regen_error||'Failed to generate API key.','error');}}catch(err){console.error('API key error:',err);QRForge.toast(_t.api_regen_error||'Failed to generate API key.','error');}finally{QRForge.btnLoading(triggerBtn,false);}};const copyToClipboard=async(text)=>{try{await navigator.clipboard.writeText(text);showToast('Copied to clipboard!');}catch(err){const ta=document.createElement('textarea');ta.value=text;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);showToast('Copied to clipboard!');}};const showToast=(message,duration=2500)=>{QRForge.toast(message,'success',{duration});};
126return{deleteQR,toggleQRStatus,generateApiKey,copyToClipboard,showToast};})();QRForge.Bulk=(()=>{let parsedCSV=null;const init=()=>{const dropZone=document.getElementById('csv-drop-zone');const fileInput=document.getElementById('csv-file-input');if(!dropZone)return;['dragenter','dragover','dragleave','drop'].forEach((evt)=>{dropZone.addEventListener(evt,(e)=>{e.preventDefault();e.stopPropagation();});});['dragenter','dragover'].forEach((evt)=>{dropZone.addEventListener(evt,()=>dropZone.classList.add('drag-over'));});['dragleave','drop'].forEach((evt)=>{dropZone.addEventListener(evt,()=>dropZone.classList.remove('drag-over'));});dropZone.addEventListener('drop',(e)=>{const files=e.dataTransfer.files;if(files.length>0)handleCSVFile(files[0]);});dropZone.addEventListener('click',()=>fileInput?.click());fileInput?.addEventListener('change',(e)=>{if(e.target.files.length>0)handleCSVFile(e.target.files[0]);});document.getElementById('btn-bulk-generate')?.addEventListener('click',startBulkGeneration);};const handleCSVFile=(file)=>{var csvCheck=QRForge.FileValidator.validate(file,'csv');if(!csvCheck.valid){QRForge.toast(csvCheck.error,'warning');return;}
127const reader=new FileReader();reader.onload=(e)=>{const text=e.target.result;const rows=text.trim().split('\n').map((line)=>line.split(',').map((cell)=>cell.trim()));parsedCSV=rows;showCSVPreview(rows);};reader.readAsText(file);};const showCSVPreview=(rows)=>{const container=document.getElementById('csv-preview');if(!container)return;const previewRows=rows.slice(0,6);let html='<table class="csv-preview-table"><thead><tr>';if(previewRows[0]){previewRows[0].forEach((cell)=>{html+=`<th>${escapeHTML(cell)}</th>`;});}
128html+='</tr></thead><tbody>';previewRows.slice(1,6).forEach((row)=>{html+='<tr>';row.forEach((cell)=>{html+=`<td>${escapeHTML(cell)}</td>`;});html+='</tr>';});html+='</tbody></table>';if(rows.length>6){html+=`<p class="text-muted">Showing 5 of ${rows.length - 1} rows</p>`;}
129container.innerHTML=html;container.style.display='block';const genBtn=document.getElementById('btn-bulk-generate');if(genBtn)genBtn.style.display='inline-block';};const startBulkGeneration=async()=>{if(!parsedCSV||parsedCSV.length<2){QRForge.toast(_t.bulk_no_data||'No CSV data loaded.','warning');return;}
130const bulkBtn=document.getElementById('btn-bulk-generate');QRForge.btnLoading(bulkBtn,true);const progressBar=document.getElementById('bulk-progress');const progressFill=document.getElementById('bulk-progress-fill');if(progressBar)progressBar.style.display='block';const formData=new FormData();const fileInput=document.getElementById('csv-file-input');if(fileInput?.files[0]){formData.append('csv_file',fileInput.files[0]);}
131try{const res=await CSRFHelper.fetchWithCSRF('/api/qrcodes/bulk',{method:'POST',body:formData,});if(res.ok){if(progressFill){progressFill.style.width='100%';progressFill.style.transition='width 1s ease';}
132const data=await res.json();QRForge.Dashboard.showToast(`${data.count || 'All'} QR codes generated!`);setTimeout(()=>{if(data.redirect)window.location.href=data.redirect;},1500);}else{const err=await res.json().catch(()=>({}));QRForge.toast(err.message||_t.bulk_error||'Bulk generation failed.','error');}}catch(err){console.error('Bulk generation error:',err);QRForge.toast(_t.bulk_network_error||'Network error during bulk generation.','error');}finally{QRForge.btnLoading(bulkBtn,false);}};const escapeHTML=(str)=>{const div=document.createElement('div');div.textContent=str;return div.innerHTML;};return{init};})();QRForge.Payment=(()=>{const initCheckout=async(planSlug,billingCycle='monthly',provider='stripe')=>{const checkoutBtn=document.querySelector(`[onclick*="initCheckout"][onclick*="${planSlug}"]`);QRForge.btnLoading(checkoutBtn,true);try{const res=await CSRFHelper.fetchWithCSRF('/payment/create-checkout',{method:'POST',body:JSON.stringify({plan:planSlug,billing_cycle:billingCycle,provider,}),});const contentType=res.headers.get('content-type')||'';const langPrefix=document.documentElement.lang==='tr'?'/tr':'';if(!contentType.includes('application/json')){window.location.href=langPrefix+'/login?redirect='+encodeURIComponent(langPrefix+'/pricing?plan='+planSlug+'&cycle='+billingCycle);return;}
133const data=await res.json();if(data.error==='auth_required'){window.location.href=langPrefix+'/login?redirect='+encodeURIComponent(langPrefix+'/pricing?plan='+planSlug+'&cycle='+billingCycle);return;}
134if(res.ok&&data.checkout_url){window.location.href=data.checkout_url;}else{QRForge.toast(data.message||data.error||'Failed to start checkout.','error');}}catch(err){console.error('Checkout error:',err);QRForge.toast('Network error.','error');}
134finally{QRForge.btnLoading(checkoutBtn,false);}};const initPricingToggle=()=>{const toggle=document.getElementById('billing-toggle');if(!toggle)return;toggle.addEventListener('change',()=>{const isYearly=toggle.checked;const cycle=isYearly?'yearly':'monthly';document.querySelectorAll('.price-amount').forEach((el)=>{const monthly=el.dataset.monthly;const yearly=el.dataset.yearly;const target=isYearly?yearly:monthly;el.style.transform='scale(0.8)';el.style.opacity='0.3';el.style.transition='all 0.3s ease';setTimeout(()=>{el.textContent=target;el.style.transform='scale(1)';el.style.opacity='1';},200);});document.querySelectorAll('.billing-cycle-label').forEach((el)=>{el.textContent=isYearly?'/year':'/month';});document.querySelectorAll('input[name="billing_cycle"]').forEach((el)=>{el.value=cycle;});});};const init=()=>{initPricingToggle();document.querySelectorAll('[data-checkout]').forEach((btn)=>{btn.addEventListener('click',(e)=>{e.preventDefault();const plan=btn.dataset.plan;const cycle=btn.dataset.cycle||'monthly';const provider=btn.dataset.provider||'stripe';initCheckout(plan,cycle,provider);});});};return{init,initCheckout,initPricingToggle};})();(()=>{document.querySelectorAll('.faq-question').forEach((question)=>{question.addEventListener('click',()=>{const item=question.closest('.faq-item');const answer=item?.querySelector('.faq-answer');if(!answer)return;const isOpen=item.classList.contains('open');document.querySelectorAll('.faq-item.open').forEach((openItem)=>{if(openItem!==item){openItem.classList.remove('open');const openAnswer=openItem.querySelector('.faq-answer');if(openAnswer){openAnswer.style.maxHeight='0';openAnswer.style.opacity='0';}}});if(isOpen){item.classList.remove('open');answer.style.maxHeight='0';answer.style.opacity='0';}else{item.classList.add('open');answer.style.maxHeight=answer.scrollHeight+'px';answer.style.opacity='1';}});});})();(()=>{document.querySelectorAll('a[href^="#"]').forEach((anchor)=>{anchor.addEventListener('click',(e)=>{const targetId=anchor.getAttribute('href');if(targetId==='#')return;const target=document.querySelector(targetId);if(target){e.preventDefault();target.scrollIntoView({behavior:'smooth',block:'start'});history.pushState(null,'',targetId);}});});})();(()=>{if(!('IntersectionObserver'in window))return;const lazyObserver=new IntersectionObserver((entries)=>{entries.forEach((entry)=>{if(entry.isIntersecting){const img=entry.target;if(img.dataset.src){img.src=img.dataset.src;img.removeAttribute('data-src');}
135if(img.dataset.srcset){img.srcset=img.dataset.srcset;img.removeAttribute('data-srcset');}
136img.classList.add('loaded');lazyObserver.unobserve(img);}});},{rootMargin:'100px'});document.querySelectorAll('img[data-src]').forEach((img)=>{lazyObserver.observe(img);});})();(()=>{document.querySelectorAll('.tabs-container').forEach((container)=>{const tabBtns=container.querySelectorAll('.tab-btn');const tabPanels=container.querySelectorAll('.tab-panel');tabBtns.forEach((btn)=>{btn.addEventListener('click',()=>{const targetTab=btn.dataset.tab;tabBtns.forEach((b)=>b.classList.remove('active'));tabPanels.forEach((p)=>{p.classList.remove('active');p.style.display='none';});btn.classList.add('active');const panel=container.querySelector(`#tab-${targetTab}`)||container.querySelector(`[data-tab-panel="${targetTab}"]`);if(panel){panel.classList.add('active');panel.style.display='block';}});});});})();QRForge.FormValidation=(()=>{const rules={required:(val)=>(val&&val.trim().length>0)||'This field is required.',email:(val)=>!val||/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val)||'Please enter a valid email.',url:(val)=>!val||/^https?:\/\/.+\..+/.test(val)||'Please enter a valid URL (include http/https).',minLength:(min)=>(val)=>!val||val.length>=min||`Minimum ${min} characters required.`,maxLength:(max)=>(val)=>!val||val.length<=max||`Maximum ${max} characters allowed.`,phone:(val)=>!val||/^[\d\s\-+()]{7,20}$/.test(val)||'Please enter a valid phone number.',numeric:(val)=>!val||/^\d+(\.\d+)?$/.test(val)||'Please enter a valid number.',};const validate=(form)=>{const errors={};let valid=true;form.querySelectorAll('[data-validate]').forEach((field)=>{const fieldRules=field.dataset.validate.split('|');const value=field.value;for(const ruleDef of fieldRules){const[ruleName,ruleParam]=ruleDef.split(':');let ruleFunc;if(ruleParam&&typeof rules[ruleName]==='function'){ruleFunc=rules[ruleName](parseInt(ruleParam,10));}else{ruleFunc=rules[ruleName];}
137if(!ruleFunc)continue;const result=ruleFunc(value);if(result!==true){errors[field.name]=result;valid=false;field.classList.add('is-invalid');let errorEl=field.parentNode.querySelector('.field-error');if(!errorEl){errorEl=document.createElement('div');errorEl.className='field-error';field.parentNode.appendChild(errorEl);}
138errorEl.textContent=result;break;}else{field.classList.remove('is-invalid');const errorEl=field.parentNode.querySelector('.field-error');if(errorEl)errorEl.remove();}}});return{valid,errors};};const attach=(formSelector)=>{const form=document.querySelector(formSelector);if(!form)return;form.querySelectorAll('[data-validate]').forEach((field)=>{field.addEventListener('blur',()=>{validate(form);});});form.addEventListener('submit',(e)=>{const{valid}=validate(form);
138if(!valid){e.preventDefault();const firstError=form.querySelector('.is-invalid');if(firstError){firstError.scrollIntoView({behavior:'smooth',block:'center'});firstError.focus();}}});};return{validate,attach,rules};})();(()=>{document.querySelectorAll('.template-card').forEach((card)=>{card.addEventListener('click',()=>{document.querySelectorAll('.template-card').forEach((c)=>c.classList.remove('selected'));card.classList.add('selected');try{const designJson=JSON.parse(card.dataset.designJson||'{}');QRForge.DesignControls.applyTemplate(designJson);}catch(err){console.warn('Invalid template design JSON:',err);}});});})();document.addEventListener('DOMContentLoaded',()=>{QRForge.Preview.init();QRForge.DesignControls.init();QRForge.Download.init();QRForge.Bulk.init();QRForge.Payment.init();QRForge.FormValidation.attach('#register-form');QRForge.FormValidation.attach('#login-form');QRForge.FormValidation.attach('#contact-form');document.addEventListener('click',(e)=>{const btn=e.target.closest('[data-action]');if(!btn)return;const action=btn.dataset.action;const id=btn.dataset.id;switch(action){case'delete-qr':QRForge.Dashboard.deleteQR(id,btn);break;case'toggle-qr':QRForge.Dashboard.toggleQRStatus(id,btn.dataset.status==='true',btn);break;case'copy':QRForge.Dashboard.copyToClipboard(btn.dataset.text||'');break;case'generate-api-key':QRForge.Dashboard.generateApiKey(btn);break;}});});

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.