124 lines
11 KiB
JavaScript
124 lines
11 KiB
JavaScript
(()=>{
|
||
'use strict';
|
||
const critical=img=>img.closest('header,.brand,#sunCloudAuthGate,.sun-auth-gate')||img.id==='sunLoginLogo'||img.classList.contains('sun-live-catalog-logo');
|
||
const tune=img=>{
|
||
if(!(img instanceof HTMLImageElement)||critical(img))return;
|
||
if(!img.hasAttribute('loading'))img.loading='lazy';
|
||
if(!img.hasAttribute('decoding'))img.decoding='async';
|
||
if(!img.hasAttribute('fetchpriority'))img.setAttribute('fetchpriority','low');
|
||
};
|
||
const scan=root=>{
|
||
if(root instanceof HTMLImageElement)tune(root);
|
||
root?.querySelectorAll?.('img').forEach(tune);
|
||
};
|
||
|
||
const MAX_FILE=15*1024*1024,TARGET=2*1024*1024,MAX_SIDE=2048;
|
||
const guardedInputs=new WeakSet();
|
||
const toast=(text,type='info',ms=4500)=>{try{return window.SunEnterprise?.toast?.(text,type,ms)}catch(_){}};
|
||
const jpegName=name=>String(name||'photo').replace(/\.[^.]+$/,'')+'.jpg';
|
||
const canvasBlob=(canvas,type,quality)=>new Promise((resolve,reject)=>canvas.toBlob(b=>b?resolve(b):reject(new Error('Не удалось сжать изображение.')),type,quality));
|
||
async function decodeImage(file){
|
||
if('createImageBitmap' in window){const bitmap=await createImageBitmap(file);return {source:bitmap,width:bitmap.width,height:bitmap.height,close:()=>bitmap.close?.()};}
|
||
const url=URL.createObjectURL(file);try{const img=new Image();await new Promise((resolve,reject)=>{img.onload=resolve;img.onerror=reject;img.src=url});return {source:img,width:img.naturalWidth,height:img.naturalHeight,close:()=>URL.revokeObjectURL(url)};}catch(e){URL.revokeObjectURL(url);throw e;}
|
||
}
|
||
async function compressImage(file){
|
||
if(!(file instanceof File)||!String(file.type||'').startsWith('image/')||/gif|svg/i.test(file.type||''))return file;
|
||
let decoded;try{decoded=await decodeImage(file);}catch(_){return file;}
|
||
try{
|
||
const {width,height,source}=decoded;if(!width||!height)return file;
|
||
if(file.size<=TARGET&&Math.max(width,height)<=MAX_SIDE)return file;
|
||
let scale=Math.min(1,MAX_SIDE/Math.max(width,height)),quality=.84,best=null;
|
||
for(let pass=0;pass<5;pass++){
|
||
const w=Math.max(1,Math.round(width*scale)),h=Math.max(1,Math.round(height*scale));
|
||
const canvas=document.createElement('canvas');canvas.width=w;canvas.height=h;
|
||
const ctx=canvas.getContext('2d',{alpha:false});if(!ctx)return file;ctx.fillStyle='#fff';ctx.fillRect(0,0,w,h);ctx.drawImage(source,0,0,w,h);
|
||
const blob=await canvasBlob(canvas,'image/jpeg',quality);if(!best||blob.size<best.size)best=blob;if(blob.size<=TARGET)break;
|
||
quality=Math.max(.60,quality-.08);scale*=.86;
|
||
}
|
||
if(!best||best.size>=file.size)return file;
|
||
return new File([best],jpegName(file.name),{type:'image/jpeg',lastModified:file.lastModified||Date.now()});
|
||
}finally{decoded.close?.();}
|
||
}
|
||
async function prepareAttachment(file){const prepared=await compressImage(file);if(prepared.size>MAX_FILE)throw new Error(`Файл «${file.name}» больше 15 МБ даже после оптимизации.`);return {file:prepared,originalSize:file.size,savedBytes:Math.max(0,file.size-prepared.size)};}
|
||
async function guardChatFiles(input){
|
||
const raw=[...(input.files||[])];if(!raw.length)return;
|
||
const prepared=[];let saved=0;
|
||
for(const f of raw){try{const p=await prepareAttachment(f);prepared.push(p.file);saved+=p.savedBytes;}catch(e){toast(e.message||String(e),'warn',6000);}}
|
||
if(!prepared.length){input.value='';return;}
|
||
const dt=new DataTransfer();prepared.forEach(f=>dt.items.add(f));input.files=dt.files;
|
||
guardedInputs.add(input);input.dispatchEvent(new Event('change',{bubbles:true}));guardedInputs.delete(input);
|
||
if(saved>256*1024)toast(`Фото оптимизированы: сэкономлено ${(saved/1024/1024).toFixed(1)} МБ.`,'success',4200);
|
||
}
|
||
document.addEventListener('change',e=>{
|
||
const input=e.target;if(!(input instanceof HTMLInputElement)||input.id!=='sunChatFilesV29'||guardedInputs.has(input)||typeof DataTransfer==='undefined')return;
|
||
e.preventDefault();e.stopImmediatePropagation();guardChatFiles(input).catch(err=>{console.error('[Caterium photo compression]',err);guardedInputs.add(input);input.dispatchEvent(new Event('change',{bubbles:true}));guardedInputs.delete(input);});
|
||
},true);
|
||
window.SunAttachmentGuard={VERSION:'17.6.1',MAX_FILE,TARGET,MAX_SIDE,compressImage,prepareAttachment};
|
||
|
||
let memoryData=null,memoryAt=0,memoryLoading=false;
|
||
const esc=v=>window.SunSafe?.escapeHTML?window.SunSafe.escapeHTML(String(v??'')):String(v??'');
|
||
async function loadMemory(){
|
||
const now=Date.now();if(memoryLoading)return memoryData;if(memoryData&&now-memoryAt<5000)return memoryData;
|
||
const c=window.SunCloudV2?.getClient?.();if(!c)return null;memoryLoading=true;
|
||
try{const r=await c.rpc('sun_dev_dashboard');if(r.error)throw r.error;memoryData=r.data||null;memoryAt=Date.now();return memoryData;}catch(_){return null}finally{memoryLoading=false;}
|
||
}
|
||
async function enhanceDeveloperMemory(){
|
||
const view=document.getElementById('sun-developer-console-v22');if(!view?.classList.contains('on'))return;
|
||
const body=document.getElementById('sunDevBody');if(!body)return;
|
||
const version=document.getElementById('sunDevReleaseVersion');if(version)version.textContent='17.6.1';
|
||
const d=await loadMemory();if(!d||!view.classList.contains('on'))return;
|
||
let box=document.getElementById('sunDevMemoryV1761');if(!box){box=document.createElement('div');box.id='sunDevMemoryV1761';box.className='sun-dev-grid';box.style.marginBottom='12px';body.prepend(box);}
|
||
box.innerHTML=`<div class="sun-dev-kpi"><small>Память сервера</small><b>${esc(d.server_size||d.database_size||'—')}</b></div><div class="sun-dev-kpi"><small>База PostgreSQL</small><b>${esc(d.database_size||'—')}</b></div><div class="sun-dev-kpi"><small>Файлы Storage</small><b>${esc(d.storage_size||'—')}</b></div><div class="sun-dev-kpi"><small>Объектов Storage</small><b>${Number(d.storage_objects||0)}</b></div>`;
|
||
}
|
||
|
||
const MOBILE_STYLE_ID='sun-mobile-catalog-v1761-style';
|
||
function installMobileCatalogStyle(){
|
||
if(document.getElementById(MOBILE_STYLE_ID))return;
|
||
const style=document.createElement('style');style.id=MOBILE_STYLE_ID;style.textContent=`
|
||
@media(max-width:900px){
|
||
.sun-enterprise-sidebar header>.sun-side-tools{display:none!important}
|
||
#new .catalog .catalog-head{display:grid!important;grid-template-columns:minmax(0,1fr)!important;align-items:stretch!important;gap:10px!important}
|
||
#new .catalog .catalog-head>h1{margin:0!important}
|
||
#new .catalog .sun-catalog-actions{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:8px!important;width:100%!important;align-items:stretch!important;justify-content:stretch!important}
|
||
#new .catalog .sun-catalog-view-switch{display:none!important}
|
||
#new .catalog .sun-catalog-search{grid-column:1/-1!important;order:-20!important;width:100%!important;min-width:0!important;height:42px!important;margin:0!important;padding:8px 12px!important;border-radius:10px!important}
|
||
#new .catalog #sunLiveCatalogPdfButton,#new .catalog #sunCatalogTabsButton,#new .catalog .sun-catalog-menu-button{width:100%!important;min-width:0!important;height:42px!important;min-height:42px!important;margin:0!important;padding:0 8px!important;border-radius:10px!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;gap:6px!important;white-space:nowrap!important;line-height:1!important}
|
||
#new .catalog #sunLiveCatalogPdfButton{order:1!important}
|
||
#new .catalog #sunCatalogTabsButton{order:2!important}
|
||
#new .catalog .sun-catalog-menu-button{order:3!important;font-size:0!important}
|
||
#new .catalog .sun-catalog-menu-button::before{content:'☰';font-size:16px!important;line-height:1!important;font-weight:700!important}
|
||
#new .catalog .sun-catalog-menu-button::after{content:'Меню';font-size:13px!important;line-height:1!important;font-weight:700!important}
|
||
#new .cats{display:flex!important;flex-wrap:nowrap!important;gap:8px!important;overflow-x:auto!important;overflow-y:hidden!important;-webkit-overflow-scrolling:touch!important;scrollbar-width:none!important;padding:9px 4px 10px!important}
|
||
#new .cats::-webkit-scrollbar{display:none!important}
|
||
#new .cats button{flex:0 0 auto!important;width:auto!important;min-width:max-content!important;margin:0!important;padding:10px 14px!important;white-space:nowrap!important}
|
||
#new .cats p{display:none!important}
|
||
}
|
||
@media(max-width:430px){
|
||
#new .catalog .sun-catalog-actions{gap:6px!important}
|
||
#new .catalog #sunLiveCatalogPdfButton,#new .catalog #sunCatalogTabsButton,#new .catalog .sun-catalog-menu-button{height:40px!important;min-height:40px!important;padding-inline:6px!important;font-size:12px!important}
|
||
#new .catalog .sun-catalog-menu-button::after{font-size:12px!important}
|
||
}
|
||
`;document.head.appendChild(style);
|
||
}
|
||
function installMobileCatalogUi(){
|
||
installMobileCatalogStyle();
|
||
const head=document.querySelector('#new .catalog .catalog-head');if(!head)return;
|
||
const menu=[...head.querySelectorAll('button')].find(b=>b.classList.contains('sun-catalog-menu-button')||(b.textContent||'').trim()==='Настроить');
|
||
if(menu){menu.classList.add('sun-catalog-menu-button');menu.setAttribute('aria-label','Меню каталога');menu.title='Меню каталога';}
|
||
const search=document.getElementById('sunCatalogSearch');if(search&&!search.getAttribute('aria-label'))search.setAttribute('aria-label','Поиск по каталогу');
|
||
const tabs=document.getElementById('sunCatalogTabsButton');if(tabs){tabs.setAttribute('aria-label','Вкладки каталога');tabs.title='Вкладки каталога';}
|
||
const pdf=document.getElementById('sunLiveCatalogPdfButton');if(pdf){pdf.setAttribute('aria-label','PDF каталога');}
|
||
}
|
||
window.SunMobileCatalogV1761={install:installMobileCatalogUi};
|
||
|
||
const start=()=>{
|
||
scan(document);installMobileCatalogUi();
|
||
const mo=new MutationObserver(records=>{records.forEach(r=>r.addedNodes.forEach(n=>{if(n.nodeType===1)scan(n)}));installMobileCatalogUi();enhanceDeveloperMemory();});
|
||
mo.observe(document.documentElement,{childList:true,subtree:true});
|
||
document.addEventListener('click',e=>{if(e.target.closest('#sunDeveloperNavV22,[data-dev-tab],#sunDevRefresh'))setTimeout(enhanceDeveloperMemory,100)},true);
|
||
window.addEventListener('sun:cloud-state-applied',()=>setTimeout(enhanceDeveloperMemory,150));
|
||
setInterval(()=>{if(document.getElementById('sun-developer-console-v22')?.classList.contains('on'))enhanceDeveloperMemory();},5000);
|
||
window.SunPerformance={scanImages:()=>scan(document),refreshDeveloperMemory:enhanceDeveloperMemory,refreshMobileCatalog:installMobileCatalogUi,disconnect:()=>mo.disconnect()};
|
||
};
|
||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',start,{once:true});else start();
|
||
})(); |