33 lines
3.7 KiB
JavaScript
33 lines
3.7 KiB
JavaScript
const definitions={requests:['request'],suppliers:['supplier'],sourcing:['request'],orders:['award'],receipts:['order','receipt','movement'],invoices:['order','invoice'],obligations:['invoice'],dossiers:['request']};
|
|
export function readFocus(stage,search){
|
|
const keys=definitions[stage];if(!keys)throw Error('Etapa de consulta inválida.');const query=new URLSearchParams(search);if(!query.size)return null;const result={};
|
|
for(const [key,value]of query){if(!keys.includes(key)||query.getAll(key).length!==1||!/^[1-9][0-9]*$/.test(value)||!Number.isSafeInteger(Number(value)))throw Error('Atalho inválido. Seleccione o registo na lista autorizada.');result[key]=Number(value);}
|
|
if(stage==='receipts'&&result.movement){if(Object.keys(result).length!==1)throw Error('Atalho inválido. Seleccione o registo na lista autorizada.');return result;}
|
|
if(!result[keys[0]])throw Error('O atalho não identifica a origem. Seleccione o registo na lista autorizada.');return result;
|
|
}
|
|
export function focusHref(stage,ids){const query=new URLSearchParams(Object.entries(ids).map(([k,v])=>[k,String(v)]));readFocus(stage,query);return '/purchasing/'+stage+'?'+query;}
|
|
/** Keep the currently authorised document when explicitly choosing another QA function. */
|
|
export function rememberFocus(stage,ids){
|
|
const entry=document.querySelector('[data-purchasing-entry]');if(!entry)return;
|
|
const href=focusHref(stage,ids);globalThis.history?.replaceState(null,'',href);entry.href='/compras?'+new URLSearchParams({return_to:href});
|
|
}
|
|
export function continuationHref(stage,ids){
|
|
const href=focusHref(stage,ids);
|
|
if(document.querySelector('nav[aria-label="Etapas de Compras"] a[href="/purchasing/'+stage+'"]'))return href;
|
|
return document.querySelector('[data-purchasing-entry]')?'/compras?'+new URLSearchParams({return_to:href}):null;
|
|
}
|
|
export function appendProcessLinks(target,links,allowed=()=>true){
|
|
for(const link of links??[]){try{const match=/^\/purchasing\/([a-z]+)\?([^#]+)$/.exec(link.href);if(!match||focusHref(match[1],Object.fromEntries(new URLSearchParams(match[2])))!==link.href)continue;readFocus(match[1],match[2]);if(!allowed(match[1]))continue;const a=document.createElement('a');a.href=link.href;a.textContent=link.label;target.append(a);}catch{/* An invalid navigation hint must never become an external or ambiguous link. */}}
|
|
}
|
|
/** Menu visibility is a presentation hint. Destination APIs remain the authority. */
|
|
export function appendStageLinks(root,target,links){
|
|
if(root.dataset.continuityEnabled!=='true')return;
|
|
appendProcessLinks(target,links,stage=>Boolean(document.querySelector('nav[aria-label="Etapas de Compras"] a[href="/purchasing/'+stage+'"]')));
|
|
if(document.querySelector('[data-purchasing-entry]'))for(const link of links??[]){try{const match=/^\/purchasing\/([a-z]+)\?([^#]+)$/.exec(link.href);if(!match||focusHref(match[1],Object.fromEntries(new URLSearchParams(match[2])))!==link.href||document.querySelector('nav[aria-label="Etapas de Compras"] a[href="/purchasing/'+match[1]+'"]'))continue;const a=document.createElement('a');a.href='/compras?'+new URLSearchParams({return_to:link.href});a.textContent='Mudar função para '+link.label;target.append(a);}catch{/* Invalid hints never become navigation. */}}
|
|
}
|
|
/** Startup does reads only; it never calls a preview/confirmation or changes company/module. */
|
|
export async function beginWorkspace({stage,root,load,open,current,error,search=globalThis.location?.search??''}){
|
|
let focus=null,problem=null;if(root.dataset.focusEnabled==='true'){try{focus=readFocus(stage,search);}catch(e){problem=e.message;}}
|
|
const pending=load(),generation=current();await pending;if(current()!==generation)return;if(problem){error(problem);return;}if(focus)await open(focus);
|
|
}
|