127 lines
5.8 KiB
JavaScript
127 lines
5.8 KiB
JavaScript
/* Site DTF — Accepting files: the drop zone, the accept rules, first measurement.
|
|
Extracted verbatim from the single inline script in web/index.html.
|
|
Loaded as classic scripts in the order listed there: they share one global
|
|
scope and run top to bottom, exactly as the original did. */
|
|
// ── upload
|
|
// Untrusted filenames and recovered cart text must never become HTML.
|
|
function escapeHTML(value){
|
|
return String(value).replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
|
}
|
|
function recusa(lista){
|
|
const el=$('recusa'); if(!el) return;
|
|
if(!lista.length){ el.style.display='none'; el.innerHTML=''; return; }
|
|
const exts=escapeHTML([...new Set(lista.map(f=>extDe(f.name)))].join(', '));
|
|
el.style.display='block';
|
|
el.innerHTML = ehFolha()
|
|
? '<b>'+exts+' não dá para enviar aqui.</b> A folha pronta aceita PNG, JPG, TIFF, '+
|
|
'PDF, PSD, AI e CDR.'
|
|
: '<b>'+exts+' não dá para enviar aqui.</b> Artes avulsas precisam de PNG ou JPG com '+
|
|
'fundo transparente — é o que a montagem enxerga para encaixar. '+
|
|
'Se o seu arquivo é CDR, AI ou PSD, exporte em PNG ou use <b>Arquivo por metro</b>.';
|
|
}
|
|
const Z=$('zona'), I=$('inp');
|
|
Z.addEventListener('click',()=>I.click());
|
|
Z.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){I.click();e.preventDefault();}});
|
|
['dragover','dragenter'].forEach(ev=>Z.addEventListener(ev,e=>{e.preventDefault();Z.classList.add('sobre')}));
|
|
['dragleave','drop'].forEach(ev=>Z.addEventListener(ev,e=>{
|
|
e.preventDefault(); Z.classList.remove('sobre');
|
|
if(ev==='drop') sel([...e.dataTransfer.files]);
|
|
}));
|
|
I.addEventListener('change',()=>sel([...I.files]));
|
|
function sel(fs){
|
|
if(!fs.length) return;
|
|
// Pixels cannot tell a loose artwork from a finished sheet, so the customer
|
|
// declares it by choosing the product in the selector above. The declaration is
|
|
// verified in medirFolha; the file never changes product or price on its own.
|
|
const regra = ehFolha() ? ACEITA.folha : ACEITA.avulsa;
|
|
const fora = fs.filter(f=>!regra.test(f.name));
|
|
fs = fs.filter(f=>regra.test(f.name));
|
|
recusa(fora);
|
|
const max=window.dtfUploadMaxBytes||128*1048576;
|
|
const grandes=fs.filter(f=>f.size>max);
|
|
if(grandes.length){
|
|
const el=$('recusa');
|
|
el.style.display='block';
|
|
el.innerHTML='<b>Arquivo acima do limite de '+(max/1048576).toFixed(0)+
|
|
' MB.</b> A verificação de segurança ainda não consegue liberar arquivos maiores. '+
|
|
'Divida ou compacte a arte antes de enviar.';
|
|
fs=fs.filter(f=>f.size<=max);
|
|
}
|
|
if(!fs.length) return;
|
|
if(ehFolha()){
|
|
const auto=fs.filter(f=>AUTO.test(f.name)).length;
|
|
const manual=fs.length-auto;
|
|
if(caminho==='auto' && manual){
|
|
caminho='tabela';
|
|
avisoCam('<b>Trocamos o caminho para você.</b> Você marcou conferência automática, '+
|
|
'mas '+(manual>1? manual+' arquivos vieram':'o arquivo veio')+' em formato que não '+
|
|
'abrimos. O metro vai pela tabela, '+rs(TABELA[modo])+'.');
|
|
pintaCaminhos();
|
|
}else if(caminho==='tabela' && auto){
|
|
caminho='auto';
|
|
avisoCam('<b>Boa notícia.</b> Você marcou o caminho sem conferência, mas '+
|
|
(auto>1? 'os arquivos vieram':'o arquivo veio')+' em formato que a gente confere. '+
|
|
'Vamos avaliar e o metro pode cair até '+rs(pisoEscada())+'.');
|
|
pintaCaminhos();
|
|
}
|
|
const novas=fs.map(f=>({f, med:null, rep:1, m:0, semAnalise:null}));
|
|
folhas=folhas.concat(novas); // soma, não substitui
|
|
pintaFolha();
|
|
novas.forEach(x=>{
|
|
x.pct=5; pintaFolha();
|
|
medirFolha(x.f).then(md=>{
|
|
if(md && md.rejected){
|
|
x.measurementError=md.reason; x.pct=null; pintaFolha(); return;
|
|
}
|
|
if(md && md.dpiFolha!=null && md.dpiFolha<DPI_RECUSA) return recusaFolha(x, md);
|
|
x.med=md; if(md) x.m=md.alt/100; x.pct=55; pintaFolha();
|
|
if(md && RENDERIZA.test(x.f.name)){
|
|
carregarImagem(x.f).then(img=>{
|
|
if(img){ x.previewSrc=img.src; try{ x.an=analisarFolha(img, md.larg); if(x.an) x.an.fonteDpi='arquivo'; }
|
|
catch(e){} }
|
|
x.pct=null; pintaFolha();
|
|
});
|
|
}else if(md && /\.pdf$/i.test(x.f.name)){
|
|
x.pct=70; pintaFolha();
|
|
rasterizarPdf(x.f, md.larg, md.alt).then(r=>{
|
|
if(r && r.erro){
|
|
x.semAnalise = r.erro + (r.semWorker
|
|
? ' · este navegador não deixa o leitor rodar em segundo plano'
|
|
: '');
|
|
}
|
|
if(r && r.tela){
|
|
try{
|
|
x.an=analisarFolha(r.tela, md.larg);
|
|
// vetor puro não tem resolução · nota máxima, e está certo
|
|
x.an.dpi = r.dpi==null ? DPI_AVISA : r.dpi;
|
|
x.an.vetor = r.dpi==null;
|
|
x.an.fonteDpi = r.dpi==null ? 'vetor' : 'imagens';
|
|
x.an.res = r.res || null;
|
|
}catch(e){}
|
|
}
|
|
x.pct=null; pintaFolha();
|
|
});
|
|
}else{ x.pct=null; pintaFolha(); }
|
|
});
|
|
});
|
|
return;
|
|
}
|
|
const novos=fs.map(f=>({f,px:0,py:0,cm:0,q:1,prop:1,giro:0,esp:false}));
|
|
artes=novos.concat(artes); // a mais recente fica no topo da fila
|
|
recemChegada=novos[0];
|
|
pintaArtes();
|
|
$('lista').scrollIntoView({behavior:'smooth',block:'nearest'});
|
|
Promise.all(novos.map(medir)).then(pintaArtes);
|
|
}
|
|
function medir(a){
|
|
return carregarImagem(a.f).then(img=>{
|
|
if(img){ a.prop=img.height/img.width; a.px=img.width; a.py=img.height; a.src=img.src; }
|
|
else a.decodeError=true;
|
|
return a;
|
|
});
|
|
}
|
|
// A metragem sai do arquivo, nunca do peso em bytes.
|
|
// imagem → proporção da imagem aplicada à largura do filme
|
|
// PDF → página única lida pelo PDF.js, com boxes, rotação e UserUnit
|
|
// TIFF, PSD, AI, CDR → o navegador não abre; o cliente informa o comprimento
|