Files
XiangYue/js/web.js
风之暇想 122480c12b v1.6.0.0
2025-09-10 13:30:52 +08:00

17 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function showNotification(message,isSuccess=true){const container=document.createElement('div');container.className='fixed right-4 transition-all duration-300 ease-in-out translate-x-full z-50';container.style.top=`${(document.querySelector('nav')?.offsetHeight || 0) + 10}px`;const setWidth=()=>container.style.width=window.innerWidth<640?'90%':'380px';setWidth();window.addEventListener('resize',setWidth);const isDark=document.documentElement.classList.contains('dark');const[color,icon]=isSuccess?['green','check']:['red','exclamation'];container.innerHTML=`
<div class="rounded-lg shadow-lg p-3 flex items-start border-l-4 border-${color}-500 ${isDark ? 'bg-gray-800 border-gray-700 text-white' : 'bg-white'}">
<div class="flex-shrink-0 mt-0.5 mr-2 text-${color}-500">
<i class="fa-solid fa-${icon}-circle"></i>
</div>
<div class="max-w-[90%]">
<p class="text-sm font-medium ${isDark ? 'dark:text-white' : 'text-gray-800'}">${message}</p>
</div>
<button class="ml-auto flex-shrink-0 inline-flex text-gray-400 hover:text-gray-600 focus:outline-none">
<i class="fa-solid fa-times"></i>
</button>
</div>
`;document.body.appendChild(container);const closeBtn=container.querySelector('button');setTimeout(()=>container.classList.remove('translate-x-full'),10);const remove=()=>{container.classList.add('translate-x-full');setTimeout(()=>container.remove(),300);};const timeoutId=setTimeout(remove,5000);closeBtn.addEventListener('click',()=>{clearTimeout(timeoutId);remove();});return container;}
function clearCryptoCache(){if(window.cryptoTempData){Object.values(window.cryptoTempData).forEach(data=>{if(data instanceof ArrayBuffer)new Uint8Array(data).fill(0);});window.cryptoTempData={};}
window.cryptoContext=null;typeof window.gc==='function'&&window.gc();}
document.addEventListener('DOMContentLoaded',()=>{const els=Object.fromEntries(['text-input','result-output','encryption-key','encrypt-btn','decrypt-btn','copy-btn','clear-btn','toggle-key-visibility','generate-password','save-password','result-status','theme-toggle','base64-toggle','paste-btn','encryption-mode-toggle','card-container'].map(id=>[id.replace(/-./g,m=>m[1].toUpperCase()),document.getElementById(id)]));window.cryptoTempData={};window.cryptoContext=null;const savedTheme=utils.getSavedThemeMode();const isDark=(savedTheme||(window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'))==='dark';document.documentElement.classList.toggle('dark',isDark);els.themeToggle.innerHTML=`<i class="fa-solid fa-${isDark ? 'moon' : 'sun'} ${isDark ? 'text-white' : 'text-dark'}"></i>`;els.encryptionKey.value=utils.getSavedPassword()||'';const modes=['chinese','base64','emoji','zero-width','japanese','korean','hieroglyphs'];const modeNames={chinese:'中文',base64:'Base64',emoji:'Emoji','zero-width':'零宽',japanese:'日语',korean:'韩语',hieroglyphs:'象形'};const icons={chinese:'fa-solid fa-language',base64:'fa-solid fa-code',emoji:'fa-regular fa-face-smile','zero-width':'fa-brands fa-creative-commons-zero',japanese:'fa-regular fa-sun',korean:'fa-solid fa-flag-checkered',hieroglyphs:'fa-solid fa-landmark-dome'};let outputMode=utils.getSavedOutputMode();els.base64Toggle.innerHTML=`<i class="${icons[outputMode]} theme-toggle-icon"></i>`;if(!window.crypto?.subtle){showNotification('不支持Web Crypto API无法使用加/解密功能',false);els.encryptBtn.disabled=els.decryptBtn.disabled=true;}
const baseStatusClass='absolute top-3 right-3 px-2 py-1 rounded-full text-xs font-medium';let isProcessing=false;const handleAction=async(action,inputGetter)=>{if(isProcessing)return showNotification('操作处理中,请稍候',false);const input=inputGetter();if(!input)return showNotification(`请输入要${action}的文本`,false);let password=els.encryptionKey.value.trim();const isDefault=!password;isDefault&&(password=DEFAULT_PASSWORD);try{isProcessing=true;els.encryptBtn.disabled=els.decryptBtn.disabled=true;els.resultStatus.textContent=`${action}中......`;els.resultStatus.className=`${baseStatusClass} bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200`;const result=await new Promise((resolve,reject)=>{setTimeout(async()=>{try{resolve(action==='加密'?await encryptionMethod1.encrypt(input,password,outputMode):await encryptionMethod1.decrypt(input,password));}catch(e){reject(e);}},0);});els.resultOutput.value=result;els.resultStatus.textContent=`${action}成功`;els.resultStatus.className=`${baseStatusClass} bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200`;showNotification(isDefault?`未检测到密码,现使用默认密码${action},建议更换为安全的密码。`:`文本已被${action}`,true);}catch(e){els.resultOutput.value='';els.resultStatus.textContent=`${action}失败`;els.resultStatus.className=`${baseStatusClass} bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200`;showNotification(e.message,false);}finally{clearCryptoCache();setTimeout(()=>els.resultStatus.classList.add('hidden'),1200);isProcessing=false;els.encryptBtn.disabled=els.decryptBtn.disabled=false;}};Object.entries({generatePassword:()=>{const pwd=utils.generatePassword(25);els.encryptionKey.value=pwd;utils.copyToClipboard(pwd);showNotification('已生成并复制25位随机密码');},toggleKeyVisibility:()=>{const isPassword=els.encryptionKey.type==='password';els.encryptionKey.type=isPassword?'text':'password';els.toggleKeyVisibility.innerHTML=`<i class="fa-regular fa-${isPassword ? 'eye' : 'eye-slash'}"></i>`;},savePassword:()=>{const password=els.encryptionKey.value.trim();utils.savePassword(password);showNotification(password?'密码已存本地(需要确保设备安全),清空密码再保存即删除。':'本地密码已删除');},base64Toggle:()=>{outputMode=modes[(modes.indexOf(outputMode)+1)%modes.length];utils.saveOutputMode(outputMode);els.base64Toggle.innerHTML=`<i class="${icons[outputMode]} theme-toggle-icon"></i>`;showNotification(`已切换到 ${modeNames[outputMode]} 密文`);},pasteBtn:()=>navigator.clipboard.readText().then(text=>{els.textInput.value=text;showNotification('已从剪贴板粘贴文本');}).catch(()=>els.textInput.select()),encryptBtn:()=>handleAction('加密',()=>els.textInput.value),decryptBtn:()=>handleAction('解密',()=>els.textInput.value.trim()),copyBtn:()=>{if(!els.resultOutput.value)return showNotification('没有可复制的结果',false);utils.copyToClipboard(els.resultOutput.value);showNotification('结果已复制到剪贴板');},clearBtn:()=>{els.textInput.value=els.resultOutput.value='';els.resultStatus.classList.add('hidden');showNotification('已清空内容');},themeToggle:()=>{const isDark=document.documentElement.classList.toggle('dark');utils.saveThemeMode(isDark?'dark':'light');els.themeToggle.innerHTML=`<i class="fa-solid fa-${isDark ? 'moon' : 'sun'} ${isDark ? 'text-white' : 'text-dark'}"></i>`;document.querySelectorAll('.fixed.right-4.transition-all.duration-300.ease-in-out.z-50').forEach(el=>el.remove());}}).forEach(([key,handler])=>els[key]?.addEventListener('click',handler));let isFirstClick=true;els.encryptionModeToggle?.addEventListener('click',function(){const cardContainer=els.cardContainer;if(!cardContainer)return;const icon=this.querySelector('i');if(isFirstClick){navigator.clipboard.writeText('https://github.com/fzxx/XiangYue').catch(()=>{});alert('非对称加密视 Github Stars关注量再考虑太少人用没有增加的必要\n\nGithub地址已复制 https://github.com/fzxx/XiangYue\n\n再次点按钮可预览非对称加密页面如有建议请到Github反馈。');isFirstClick=false;}else{cardContainer.classList.toggle('flipped');if(cardContainer.classList.contains('flipped')){icon.classList.remove('fa-exchange');icon.classList.add('fa-sync-alt');}else{icon.classList.remove('fa-sync-alt');icon.classList.add('fa-exchange');}}});});