Upgraded, runtime‑grade bookmarklet — wrapped in an executable, dormant‑until‑trigger shell
This document takes your provided bookmarklet and specification, integrates it as a dormant runtime, and exposes a triggerable introspector that snapshots the page, observes it over time, and streams structured JSON into a dedicated inspection window.
You asked for the entire content to be wrapped in a fully engineered HTML document with advanced CSS, schema‑correct semantics, runtime‑grade JavaScript, and the original bookmarklet code integrated in a way that remains dormant until explicitly triggered. The introspector then runs through the entirety of the rendered application, producing dynamic programming results and streaming them into an inspection view.
The code below is embedded as an executable runtime function, not just a static snippet. It leverages PerformanceObserver, MutationObserver, and a periodic JSON dump to maintain a rolling, bounded telemetry view of this page's structure and activity.
The bookmarklet you provided has been integrated as an executable introspection function. In its original form, it was meant to be dropped directly into a bookmark's URL field:
Original usage: create a bookmark and set the URL to:
javascript:(function(){try{var D=document,W=window;function A(s,c){return Array.prototype.slice.call((c||D).querySelectorAll(s));}function M(xs,f){return xs.map(function(n){try{return f(n);}catch(e){return{error:String(e)}}});}function T(s,l){if(!s)return null;s=s.trim();return s.length>l?s.slice(0,l):s}var S=W.__PAGE_INTROSPECTOR__||(W.__PAGE_INTROSPECTOR__={meta:{started:Date.now()},page:{},static:{},dynamic:{mutations:[],resources:[],longtasks:[]}});S.meta.lastRun=Date.now();S.page={url:W.location.href,title:D.title,referrer:D.referrer};S.static.scripts=M(A('script'),function(s){return{src:s.src||null,inline:s.src?null:T(s.textContent||'',2000),type:s.type||null,async:!!s.async,defer:!!s.defer,crossorigin:s.getAttribute('crossorigin'),nonce:s.getAttribute('nonce'),id:s.id||null}});S.static.links=M(A('link'),function(l){return{rel:l.rel||null,href:l.href||null,as:l.getAttribute('as'),crossorigin:l.getAttribute('crossorigin'),type:l.type||null,media:l.media||null,referrerpolicy:l.referrerPolicy||null,fetchpriority:l.getAttribute('fetchpriority')}});S.static.anchors=M(A('a[href]'),function(a){return{href:a.href,text:T(a.textContent||'',200),rel:a.rel||null,role:a.getAttribute('role'),ariaLabel:a.getAttribute('aria-label'),ariaLabelledby:a.getAttribute('aria-labelledby'),id:a.id||null}});S.static.elementsWithId=M(A('[id]'),function(el){return{tag:el.tagName.toLowerCase(),id:el.id,classes:el.className||null,role:el.getAttribute('role'),ariaLabel:el.getAttribute('aria-label'),ariaLabelledby:el.getAttribute('aria-labelledby')}});S.static.ariaElements=M(A('[role],[aria-label],[aria-labelledby],[aria-hidden],[aria-modal]'),function(el){return{tag:el.tagName.toLowerCase(),id:el.id||null,classes:el.className||null,role:el.getAttribute('role'),ariaLabel:el.getAttribute('aria-label'),ariaLabelledby:el.getAttribute('aria-labelledby'),ariaHidden:el.getAttribute('aria-hidden'),ariaModal:el.getAttribute('aria-modal')}});S.static.modals=M(A('[role="dialog"],[role="alertdialog"],[aria-modal="true"],.modal,[data-modal],[data-dialog]'),function(el){return{tag:el.tagName.toLowerCase(),id:el.id||null,classes:el.className||null,role:el.getAttribute('role'),ariaModal:el.getAttribute('aria-modal'),ariaLabel:el.getAttribute('aria-label'),ariaLabelledby:el.getAttribute('aria-labelledby')}});S.static.navRelations=M(A('link[rel]'),function(l){return{rel:l.rel,href:l.href||null,as:l.getAttribute('as'),type:l.type||null,media:l.media||null}});function cap(arr,max){if(arr.length>max)arr.splice(0,arr.length-max);}if(!S.__observersSetup){S.__observersSetup=true;try{if(W.PerformanceObserver){var ro=new PerformanceObserver(function(list){list.getEntries().forEach(function(e){S.dynamic.resources.push({name:e.name,initiatorType:e.initiatorType,entryType:e.entryType,startTime:e.startTime,duration:e.duration,transferSize:e.transferSize,encodedBodySize:e.encodedBodySize,decodedBodySize:e.decodedBodySize});cap(S.dynamic.resources,400);});});try{ro.observe({type:'resource',buffered:true});}catch(_){ro.observe({entryTypes:['resource']});}var no=new PerformanceObserver(function(list){list.getEntries().forEach(function(e){S.dynamic.resources.push({name:e.name,initiatorType:e.initiatorType||'navigation',entryType:e.entryType,startTime:e.startTime,duration:e.duration,type:e.type});cap(S.dynamic.resources,450);});});try{no.observe({type:'navigation',buffered:true});}catch(_){no.observe({entryTypes:['navigation']});}var lo=new PerformanceObserver(function(list){list.getEntries().forEach(function(e){S.dynamic.longtasks.push({name:e.name||'longtask',entryType:e.entryType,startTime:e.startTime,duration:e.duration});cap(S.dynamic.longtasks,200);});});try{lo.observe({type:'longtask',buffered:true});}catch(_){lo.observe({entryTypes:['longtask']});}}}catch(e){}try{var mo=new MutationObserver(function(muts){muts.forEach(function(m){var rec={t:Date.now(),type:m.type,targetTag:m.target&&m.target.tagName?m.target.tagName.toLowerCase():null,targetId:m.target&&m.target.id||null,added:[],removed:[],attrName:m.attributeName||null};if(m.type==='attributes'){rec.attrValue=m.target && m.attributeName?m.target.getAttribute(m.attributeName):null;}if(m.type==='childList'){Array.prototype.forEach.call(m.addedNodes||[],function(n){if(n.nodeType===1){rec.added.push({tag:n.tagName.toLowerCase(),id:n.id||null,classes:n.className||null,role:n.getAttribute('role'),ariaLabel:n.getAttribute('aria-label')});}});Array.prototype.forEach.call(m.removedNodes||[],function(n){if(n.nodeType===1){rec.removed.push({tag:n.tagName.toLowerCase(),id:n.id||null,classes:n.className||null,role:n.getAttribute('role'),ariaLabel:n.getAttribute('aria-label')});}});}S.dynamic.mutations.push(rec);cap(S.dynamic.mutations,300);});});mo.observe(D.documentElement||D.body||D,{subtree:true,childList:true,attributes:true,attributeFilter:['role','id','class','aria-label','aria-labelledby','aria-hidden','aria-modal']});S.dynamic.__mo=mo;}catch(e){}}var win=S.__win;if(!win||win.closed){win=W.open('about:blank','_blank');if(!win){alert('Popup blocked: enable popups and retry bookmarklet.');return;}S.__win=win;var pre=win.document.createElement('pre');pre.style.whiteSpace='pre-wrap';pre.style.font='11px/1.4 monospace';win.document.body.style.margin='0';win.document.body.appendChild(pre);win.document.title='Page inspection stream';S.__pre=pre;}var pre=S.__pre||S.__win.document.querySelector('pre');function dump(){if(!S.__win||S.__win.closed)return;pre.textContent=JSON.stringify({meta:S.meta,page:S.page,static:S.static,dynamic:S.dynamic},null,2);}dump();if(!S.__interval){S.__interval=W.setInterval(dump,2000);} }catch(e){alert('Introspector error: '+e);}})();
Within this document, that same logic is wired into a dormant runtime function, invoked only when you trigger it via the button or keyboard shortcut.
The bookmarklet is written "for the interpreter": it is dense, self‑contained, and free of external dependencies, optimized to run inside arbitrary pages without additional scaffolding. It builds a single global anchor on window.__PAGE_INTROSPECTOR__ and uses this as the canonical container for every piece of telemetry and snapshot data it collects.
Internally, the state container holds:
| Field | Purpose |
|---|---|
meta.started |
Timestamp of the first ever run for this page context. |
meta.lastRun |
Timestamp of the most recent run (updated on each trigger). |
page |
URL, title, and referrer of the inspected page. |
static |
One‑shot structural snapshot of DOM and metadata at trigger time. |
dynamic |
Rolling buffers for mutations, resources, and long tasks. |
Static collectors use
querySelectorAll-based scans
over the current DOM to build a snapshot of scripts, links,
anchors, IDs, ARIA‑relevant elements, modal‑like nodes, and
navigation relations. These live under
__PAGE_INTROSPECTOR__.static.
| Collector | Selector | Captured shape |
|---|---|---|
| Scripts | script |
src, truncated inline body, type,
async/defer, crossorigin, nonce, id.
|
| Links | link |
rel, href, as,
crossorigin, type, media, referrerpolicy,
fetchpriority.
|
| Anchors | a[href] |
href, truncated text, rel,
role, ARIA label/labelledby, id.
|
| Elements with id | [id] |
Tag, id, class list, role, ARIA label/labelledby. |
| ARIA / role cluster | [role],[aria-*] |
Tag, id, classes, role, aria-label,
aria-labelledby, aria-hidden,
aria-modal.
|
| Modal heuristics |
[role="dialog"],
[role="alertdialog"],
[aria-modal="true"],
.modal,
[data-modal],
[data-dialog]
|
Minimal shape for each modal‑like element: tag, id,
classes, role, aria-modal,
ARIA labeling.
|
| Navigation relations | link[rel] |
rel, href, as,
type, media.
|
Dynamic collectors attach once per page and stream performance‑level and DOM‑level changes into rolling buffers. Each buffer is explicitly capped to keep the in‑page structure bounded and safe.
Performance observers
A single setup block handles resource, navigation, and
long‑task entries via PerformanceObserver,
using type with buffered:true where
supported and falling back to entryTypes lists.
Entries are pushed into
S.dynamic.resources and
S.dynamic.longtasks.
Mutation observer
A single MutationObserver is
attached to the root element (with a fallback to
body) with
subtree:true, childList:true, and
attributes:true. Attribute tracking is restricted
to:
role,
id,
class,
aria-label,
aria-labelledby,
aria-hidden,
aria-modal.
Each mutation records a lightweight descriptor:
timestamp t, mutation type,
target tag/id, attribute name/value when relevant, and small
summaries for added and removed elements.
To avoid unbounded growth, each array that collects dynamic
data is trimmed using a simple
cap(arr, max) helper that discards older entries
before the front of the list:
function cap(arr, max) {
if (arr.length > max) arr.splice(0, arr.length - max);
}
Caps applied:
| Buffer | Max entries |
|---|---|
S.dynamic.resources |
400–450 entries (resource + navigation) |
S.dynamic.longtasks |
200 entries |
S.dynamic.mutations |
300 entries |
The output channel is a dedicated popup window whose sole
responsibility is to render JSON. The introspector reuses the
same window on subsequent runs. If the window is closed, it
is recreated as about:blank, given a monospaced
<pre>, and titled
"Page inspection stream".
A dump() function JSON‑serializes the current
introspector state:
dump() {
if (!S.__win || S.__win.closed) return;
pre.textContent = JSON.stringify(
{ meta: S.meta, page: S.page, static: S.static, dynamic: S.dynamic },
null,
2
);
}
The first run triggers an immediate dump, then a periodic
refresh via setInterval(dump, 2000), stored in
S.__interval so it is created at most once per
page.
Re‑running the introspector on the same page updates
meta.lastRun, recomputes the full static
snapshot, and forces a fresh dump into the streaming window,
while preserving the underlying observers and interval if they
already exist. This yields an idempotent pattern: multiple
triggers on the same page refine the structural snapshot and
append dynamic events, without duplicating observers.
Within this shell, you can trigger re‑runs either via the primary control button or the Ctrl+Shift+I shortcut. Each run is counted, and the status indicator updates from "dormant" to "streaming".
If you ever want this to also introspect framework‑specific
structures — React trees, Vue instances, or custom data
stores — you can extend
S.static.framework and
S.dynamic.framework with framework‑specific
probes built into the same global pattern.
The introspector code you provided is integrated as a fully executable runtime, but it remains dormant until you explicitly trigger it. When triggered, it:
- Takes a structural snapshot of this page (scripts, links, anchors, IDs, ARIA, modal heuristics, nav relations).
-
Attaches
PerformanceObserverandMutationObserveronce, streaming events into bounded buffers. -
Opens (or reuses) a dedicated popup window that renders a JSON
representation of
__PAGE_INTROSPECTOR__, refreshing every 2 seconds.
Re‑triggering the introspector updates the snapshot and meta, without duplicating observers. This page itself is the playground: CSS, layout, and runtime wiring are all designed around that behavior.
Comments
Post a Comment