daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

viewer.ts (2381B)


      1 /**
      2  * A small image viewer for sheet images, so the cursor's "View image"
      3  * pill does what it says. A native <dialog>: Escape, a click anywhere or
      4  * the close button dismisses it, focus returns to the image, and the
      5  * page behind is inert while it is open.
      6  *
      7  * Images inside a link keep the link's behaviour; tiny inline images
      8  * (badges, icons) are left alone.
      9  */
     10 let dialog: HTMLDialogElement | null = null;
     11 let shown: HTMLImageElement | null = null;
     12 
     13 function ensureDialog(): HTMLDialogElement {
     14   if (dialog && dialog.isConnected) return dialog;
     15   dialog = document.createElement('dialog');
     16   dialog.className = 'dmn-viewer';
     17   dialog.setAttribute('aria-label', 'Image viewer');
     18   const img = document.createElement('img');
     19   img.className = 'dmn-viewer__img';
     20   const cap = document.createElement('p');
     21   cap.className = 'dmn-viewer__cap';
     22   const close = document.createElement('button');
     23   close.type = 'button';
     24   close.className = 'dmn-viewer__close';
     25   close.textContent = 'Close';
     26   dialog.append(img, cap, close);
     27   dialog.addEventListener('click', () => dialog?.close());
     28   dialog.addEventListener('close', () => shown?.focus({ preventScroll: true }));
     29   document.body.appendChild(dialog);
     30   return dialog;
     31 }
     32 
     33 function open(from: HTMLImageElement): void {
     34   const d = ensureDialog();
     35   const img = d.querySelector<HTMLImageElement>('.dmn-viewer__img')!;
     36   const cap = d.querySelector<HTMLElement>('.dmn-viewer__cap')!;
     37   img.src = from.currentSrc || from.src;
     38   img.alt = from.alt;
     39   cap.textContent = from.alt || '';
     40   cap.hidden = !from.alt;
     41   shown = from;
     42   d.showModal();
     43 }
     44 
     45 export function initViewer(): void {
     46   document.querySelectorAll<HTMLImageElement>('.prose img:not([data-zoomable])').forEach((img) => {
     47     if (img.closest('a')) return;
     48     const mark = () => {
     49       if (img.naturalWidth && img.naturalWidth < 120) return;
     50       img.dataset.zoomable = '';
     51       img.tabIndex = 0;
     52       img.setAttribute('role', 'button');
     53       img.setAttribute('aria-label', img.alt ? `Enlarge image: ${img.alt}` : 'Enlarge image');
     54       img.addEventListener('click', () => open(img));
     55       img.addEventListener('keydown', (e) => {
     56         if (e.key === 'Enter' || e.key === ' ') {
     57           e.preventDefault();
     58           open(img);
     59         }
     60       });
     61     };
     62     if (img.complete) mark();
     63     else img.addEventListener('load', mark, { once: true });
     64   });
     65 }