Files
safetynet/apps/server/public/branding-admin.js
T

14 lines
3.6 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.
// Company identity uses the existing signed policy publication and review flow.
let companyLogoDataUrl;
const brandingFields=['brand-logo-file','brand-logo-remove','startpage-title','startpage-subtitle','startpage-news-enabled','startpage-feed-url'];
function previewCompanyLogo(){const image=$('brand-logo-preview');image.hidden=!companyLogoDataUrl;if(companyLogoDataUrl)image.src=companyLogoDataUrl;else image.removeAttribute('src');}
function fillCompanyBranding(p){companyLogoDataUrl=p.brand?.logoDataUrl;$('startpage-title').value=p.startPage?.title??'Welcome';$('startpage-subtitle').value=p.startPage?.subtitle??'';$('startpage-news-enabled').checked=p.startPage?.newsEnabled===true;$('startpage-feed-url').value=p.startPage?.feedUrl??'';$('brand-logo-file').value='';$('brand-logo-status').textContent='';previewCompanyLogo();}
const fillBeforeCompanyBranding=fill;fill=function(p){fillBeforeCompanyBranding(p);fillCompanyBranding(p);};
const draftBeforeCompanyBranding=draft;draft=function(){const p=draftBeforeCompanyBranding();p.brand={...(policy?.brand||{}),...p.brand};if(companyLogoDataUrl)p.brand.logoDataUrl=companyLogoDataUrl;else delete p.brand.logoDataUrl;p.startPage={...(policy?.startPage||{}),title:$('startpage-title').value.trim(),subtitle:$('startpage-subtitle').value.trim(),newsEnabled:$('startpage-news-enabled').checked};const url=$('startpage-feed-url').value.trim();if(url)p.startPage.feedUrl=url;else delete p.startPage.feedUrl;return p;};
const permissionsBeforeCompanyBranding=applyOperatorPermissions;applyOperatorPermissions=function(principal){permissionsBeforeCompanyBranding(principal);const allowed=principal.permissions?.includes('policy.write')||(independentApprovalRequired&&principal.role==='operator');for(const id of brandingFields)$(id).disabled=!allowed;};
async function encodeCompanyLogo(file){if(!file||file.type!=='image/png'||file.size>128*1024)throw Error('Choose a PNG no larger than 128 KiB.');const bytes=new Uint8Array(await file.arrayBuffer());if(bytes.length<24||[137,80,78,71,13,10,26,10].some((v,i)=>bytes[i]!==v)||[73,72,68,82].some((v,i)=>bytes[12+i]!==v))throw Error('The file is not a PNG.');const dimension=offset=>bytes[offset]*16777216+bytes[offset+1]*65536+bytes[offset+2]*256+bytes[offset+3];if(dimension(16)<1||dimension(20)<1||dimension(16)>1024||dimension(20)>1024)throw Error('PNG dimensions must be at most 1024 × 1024 pixels.');const image=await createImageBitmap(file);try{if(image.width<1||image.height<1||image.width>1024||image.height>1024)throw Error('PNG dimensions must be at most 1024 × 1024 pixels.');const canvas=document.createElement('canvas');canvas.width=image.width;canvas.height=image.height;canvas.getContext('2d').drawImage(image,0,0);const encoded=canvas.toDataURL('image/png');if(encoded.length>180000||Math.ceil((encoded.length-22)*3/4)>128*1024)throw Error('Re-encoded logo is too large. Use a simpler or smaller PNG.');return encoded;}finally{image.close();}}
$('brand-logo-file').addEventListener('change',task(async()=>{const file=$('brand-logo-file').files[0];if(!file)return;companyLogoDataUrl=await encodeCompanyLogo(file);previewCompanyLogo();$('brand-logo-status').textContent='Logo added to draft. Publish policy to roll it out.';updateDraftStatus();}));
$('brand-logo-remove').addEventListener('click',()=>{companyLogoDataUrl=undefined;previewCompanyLogo();$('brand-logo-file').value='';$('brand-logo-status').textContent='Logo removal is in the draft.';updateDraftStatus();});
for(const id of brandingFields.slice(2))$(id).addEventListener('change',()=>updateDraftStatus());
if(policy)fillCompanyBranding(policy);if(currentPrincipal)applyOperatorPermissions(currentPrincipal);