checkpoint-cli 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +469 -54
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -208,6 +208,263 @@ function trackingScript() {
208
208
  };
209
209
  }
210
210
 
211
+ function parseZIndex(value){
212
+ var n=parseInt(String(value||''),10);
213
+ return isNaN(n)?0:n;
214
+ }
215
+
216
+ function detectTransientKind(el){
217
+ if(!el||!el.tagName) return 'unknown';
218
+ try{
219
+ var role=(el.getAttribute&&el.getAttribute('role')||'').toLowerCase();
220
+ var classes=(el.className&&typeof el.className==='string'?el.className:'').toLowerCase();
221
+ var id=(el.id||'').toLowerCase();
222
+ var label=(role+' '+classes+' '+id).trim();
223
+ if(role==='dialog'||el.getAttribute('aria-modal')==='true'||label.indexOf('modal')>=0||label.indexOf('dialog')>=0){
224
+ return 'dialog';
225
+ }
226
+ if(label.indexOf('drawer')>=0||label.indexOf('sheet')>=0||label.indexOf('sidebar')>=0){
227
+ return 'drawer';
228
+ }
229
+ if(label.indexOf('popover')>=0) return 'popover';
230
+ if(role==='menu'||label.indexOf('menu')>=0||label.indexOf('dropdown')>=0) return 'menu';
231
+ if(role==='tooltip'||label.indexOf('tooltip')>=0) return 'tooltip';
232
+ }catch(e){}
233
+ return 'unknown';
234
+ }
235
+
236
+ function isTransientRootCandidate(el){
237
+ if(!el||!el.tagName) return false;
238
+ try{
239
+ var role=(el.getAttribute&&el.getAttribute('role')||'').toLowerCase();
240
+ var ariaModal=(el.getAttribute&&el.getAttribute('aria-modal')||'').toLowerCase();
241
+ var dataState=(el.getAttribute&&el.getAttribute('data-state')||'').toLowerCase();
242
+ var classes=(el.className&&typeof el.className==='string'?el.className:'').toLowerCase();
243
+ var id=(el.id||'').toLowerCase();
244
+ var style=window.getComputedStyle?window.getComputedStyle(el):null;
245
+ var position=style?style.position:'';
246
+ var zIndex=parseZIndex(style?style.zIndex:0);
247
+ if(role==='dialog'||role==='menu'||role==='tooltip') return true;
248
+ if(ariaModal==='true') return true;
249
+ if(dataState==='open'&&(classes.indexOf('modal')>=0||classes.indexOf('popover')>=0||classes.indexOf('drawer')>=0)) return true;
250
+ if(classes.indexOf('modal')>=0||classes.indexOf('dialog')>=0||classes.indexOf('drawer')>=0||classes.indexOf('popover')>=0||classes.indexOf('tooltip')>=0||classes.indexOf('dropdown')>=0) return true;
251
+ if(id.indexOf('modal')>=0||id.indexOf('dialog')>=0||id.indexOf('drawer')>=0||id.indexOf('popover')>=0) return true;
252
+ if((position==='fixed'||position==='sticky')&&zIndex>=100) return true;
253
+ }catch(e){}
254
+ return false;
255
+ }
256
+
257
+ function isLikelyPortaled(el){
258
+ if(!el||!el.parentElement) return false;
259
+ try{
260
+ var root=el;
261
+ var steps=0;
262
+ while(root&&root.parentElement&&steps<8){
263
+ root=root.parentElement;
264
+ steps++;
265
+ }
266
+ if(!root||!root.parentElement) return false;
267
+ if(root===document.body) return true;
268
+ if(el.parentElement===document.body) return true;
269
+ if(el.parentElement&&el.parentElement.id&&String(el.parentElement.id).toLowerCase().indexOf('portal')>=0) return true;
270
+ var classes=(el.className&&typeof el.className==='string'?el.className:'').toLowerCase();
271
+ if(classes.indexOf('portal')>=0) return true;
272
+ }catch(e){}
273
+ return false;
274
+ }
275
+
276
+ function getOpenerCandidates(){
277
+ var out=[];
278
+ var seen={};
279
+ var selectors=[
280
+ '[aria-haspopup=\"dialog\"]',
281
+ '[aria-controls]',
282
+ '[data-modal-trigger]',
283
+ '[data-dialog-trigger]',
284
+ 'button',
285
+ '[role=\"button\"]',
286
+ 'a'
287
+ ];
288
+ for(var s=0;s<selectors.length;s++){
289
+ var selector=selectors[s];
290
+ try{
291
+ var nodes=document.querySelectorAll(selector);
292
+ for(var i=0;i<nodes.length&&out.length<8;i++){
293
+ var node=nodes[i];
294
+ if(!node||node.nodeType!==1) continue;
295
+ var sel=elementSelector(node);
296
+ if(!sel||seen[sel]) continue;
297
+ seen[sel]=true;
298
+ var score=0.3;
299
+ var label=(node.getAttribute&&node.getAttribute('aria-label')||'').toLowerCase();
300
+ var text=shortText(node.textContent).toLowerCase();
301
+ if(label.indexOf('setting')>=0||text.indexOf('setting')>=0) score=0.9;
302
+ else if(label.indexOf('open')>=0||text.indexOf('open')>=0) score=0.7;
303
+ out.push({selector:sel,score:score});
304
+ }
305
+ }catch(e){}
306
+ }
307
+ out.sort(function(a,b){ return b.score-a.score; });
308
+ return out.slice(0,6);
309
+ }
310
+
311
+ function getTransientContext(el){
312
+ if(!el||typeof el.closest!=='function') return null;
313
+ var current=el;
314
+ var depth=0;
315
+ while(current&&current.nodeType===1&&depth<8){
316
+ if(isTransientRootCandidate(current)){
317
+ var style=window.getComputedStyle?window.getComputedStyle(current):null;
318
+ return {
319
+ kind:detectTransientKind(current),
320
+ root_selector_chain:getSelectorChain(current),
321
+ root_fingerprint:getDomFingerprint(current),
322
+ is_portaled:isLikelyPortaled(current),
323
+ z_index:parseZIndex(style?style.zIndex:0),
324
+ is_fixed:style?style.position==='fixed':false,
325
+ opener_candidates:getOpenerCandidates()
326
+ };
327
+ }
328
+ current=current.parentElement;
329
+ depth++;
330
+ }
331
+ return null;
332
+ }
333
+
334
+ function getVisibleText(node){
335
+ try{
336
+ if(!node||!node.textContent) return '';
337
+ return shortText(String(node.textContent).replace(/\\s+/g,' ').trim()).toLowerCase();
338
+ }catch(e){}
339
+ return '';
340
+ }
341
+
342
+ function getNavSignature(){
343
+ try{
344
+ var candidates=[];
345
+ var activeSelectors=[
346
+ '[aria-current=\"page\"]',
347
+ '[aria-selected=\"true\"]',
348
+ '[data-state=\"active\"]',
349
+ '.active',
350
+ '.is-active',
351
+ '.selected'
352
+ ];
353
+ for(var i=0;i<activeSelectors.length;i++){
354
+ var nodes=document.querySelectorAll(activeSelectors[i]);
355
+ for(var j=0;j<nodes.length&&candidates.length<8;j++){
356
+ var text=getVisibleText(nodes[j]);
357
+ if(text) candidates.push(text);
358
+ }
359
+ }
360
+ if(candidates.length===0){
361
+ var heading=document.querySelector('main h1, [role=\"main\"] h1, h1, h2');
362
+ var fallbackText=getVisibleText(heading);
363
+ if(fallbackText) candidates.push(fallbackText);
364
+ }
365
+ if(candidates.length===0) return '';
366
+ return candidates.slice(0,4).join('|');
367
+ }catch(e){}
368
+ return '';
369
+ }
370
+
371
+ function getHeadingSignature(){
372
+ try{
373
+ var heading=document.querySelector('main h1, [role=\"main\"] h1, h1, h2');
374
+ return getVisibleText(heading);
375
+ }catch(e){}
376
+ return '';
377
+ }
378
+
379
+ function getViewContext(){
380
+ return {
381
+ nav_signature:getNavSignature()||undefined,
382
+ heading_signature:getHeadingSignature()||undefined
383
+ };
384
+ }
385
+
386
+ function viewContextMatches(expected){
387
+ if(!expected||typeof expected!=='object') return true;
388
+ var current=getViewContext();
389
+ if(expected.nav_signature&&current.nav_signature&&expected.nav_signature!==current.nav_signature){
390
+ return false;
391
+ }
392
+ if(expected.heading_signature&&current.heading_signature&&expected.heading_signature!==current.heading_signature){
393
+ return false;
394
+ }
395
+ return true;
396
+ }
397
+
398
+ function isScrollable(el){
399
+ if(!el||el.nodeType!==1||!window.getComputedStyle) return false;
400
+ try{
401
+ var style=window.getComputedStyle(el);
402
+ var overflowY=String(style.overflowY||'').toLowerCase();
403
+ var overflowX=String(style.overflowX||'').toLowerCase();
404
+ var canScrollY=(overflowY==='auto'||overflowY==='scroll'||overflowY==='overlay')&&(el.scrollHeight-el.clientHeight>1);
405
+ var canScrollX=(overflowX==='auto'||overflowX==='scroll'||overflowX==='overlay')&&(el.scrollWidth-el.clientWidth>1);
406
+ return !!(canScrollX||canScrollY);
407
+ }catch(e){}
408
+ return false;
409
+ }
410
+
411
+ function getNearestScrollContainer(el){
412
+ if(!el) return null;
413
+ var current=el.parentElement;
414
+ var depth=0;
415
+ while(current&&depth<10){
416
+ if(current===document.body||current===document.documentElement) return null;
417
+ if(isScrollable(current)) return current;
418
+ current=current.parentElement;
419
+ depth++;
420
+ }
421
+ return null;
422
+ }
423
+
424
+ function getScrollContext(el,clientX,clientY){
425
+ var container=getNearestScrollContainer(el);
426
+ if(!container) return null;
427
+ var rect=container.getBoundingClientRect?container.getBoundingClientRect():null;
428
+ if(!rect) return null;
429
+ var safeW=Math.max(1,rect.width||1);
430
+ var safeH=Math.max(1,rect.height||1);
431
+ return {
432
+ container_selector_chain:getSelectorChain(container),
433
+ container_fingerprint:getDomFingerprint(container),
434
+ container_x_percent:clampPercent(((clientX-rect.left)/safeW)*100),
435
+ container_y_percent:clampPercent(((clientY-rect.top)/safeH)*100)
436
+ };
437
+ }
438
+
439
+ function getPointFromScrollContext(scrollContext){
440
+ if(!scrollContext||typeof scrollContext!=='object') return null;
441
+ var container=null;
442
+ if(Array.isArray(scrollContext.container_selector_chain)){
443
+ for(var i=0;i<scrollContext.container_selector_chain.length;i++){
444
+ var candidate=scrollContext.container_selector_chain[i];
445
+ if(!candidate||typeof candidate.selector!=='string') continue;
446
+ var nodes=querySelectorAllSafe(document,candidate.selector);
447
+ var match=pickBestElement(nodes,{coord_fallback:null},getMetrics(),null);
448
+ if(match&&match.element){
449
+ container=match.element;
450
+ break;
451
+ }
452
+ }
453
+ }
454
+ if(!container&&scrollContext.container_fingerprint){
455
+ var fp=resolveFromFingerprint(scrollContext.container_fingerprint,{coord_fallback:null},getMetrics(),document);
456
+ container=fp&&fp.element?fp.element:null;
457
+ }
458
+ if(!container||!container.getBoundingClientRect) return null;
459
+ var rect=container.getBoundingClientRect();
460
+ var relX=typeof scrollContext.container_x_percent==='number'?clampPercent(scrollContext.container_x_percent)/100:0.5;
461
+ var relY=typeof scrollContext.container_y_percent==='number'?clampPercent(scrollContext.container_y_percent)/100:0.5;
462
+ return {
463
+ clientX:rect.left+(rect.width*relX),
464
+ clientY:rect.top+(rect.height*relY)
465
+ };
466
+ }
467
+
211
468
  function buildCoordFallback(clientX,clientY,metrics){
212
469
  var safeViewW=metrics.viewWidth||1;
213
470
  var safeViewH=metrics.viewHeight||1;
@@ -253,6 +510,9 @@ function trackingScript() {
253
510
  parent:textParent
254
511
  },
255
512
  container_hint:getContainerHint(el),
513
+ transient_context:getTransientContext(el),
514
+ view_context:getViewContext(),
515
+ scroll_context:getScrollContext(el,clientX,clientY),
256
516
  coord_fallback:fallback
257
517
  };
258
518
  }
@@ -328,13 +588,16 @@ function trackingScript() {
328
588
  }
329
589
 
330
590
  function pickBestElement(nodes,payload,metrics,fingerprintPath){
331
- if(!nodes||nodes.length===0) return null;
591
+ if(!nodes||nodes.length===0) return { element:null, ambiguous:false, bestScore:Infinity };
332
592
  var target=getTargetDocPoint(payload,metrics);
333
593
  var best=null;
334
594
  var bestScore=Infinity;
595
+ var secondScore=Infinity;
596
+ var matchCount=0;
335
597
  for(var i=0;i<nodes.length;i++){
336
598
  var node=nodes[i];
337
599
  if(!node||node.nodeType!==1) continue;
600
+ matchCount++;
338
601
  var anchorPoint=getAnchorClientPoint(node,payload);
339
602
  var docX=anchorPoint.clientX+metrics.scrollX;
340
603
  var docY=anchorPoint.clientY+metrics.scrollY;
@@ -348,29 +611,51 @@ function trackingScript() {
348
611
  score+=siblingPathDistance(node,fingerprintPath)*40;
349
612
  }
350
613
  if(score<bestScore){
614
+ secondScore=bestScore;
351
615
  best=node;
352
616
  bestScore=score;
617
+ }else if(score<secondScore){
618
+ secondScore=score;
353
619
  }
354
620
  }
355
- return best;
621
+ if(!best) return { element:null, ambiguous:false, bestScore:Infinity };
622
+ var ambiguous=false;
623
+ if(matchCount>1){
624
+ if(!target){
625
+ ambiguous=true;
626
+ }else if((secondScore-bestScore)<18){
627
+ ambiguous=true;
628
+ }
629
+ }
630
+ return { element:best, ambiguous:ambiguous, bestScore:bestScore };
631
+ }
632
+
633
+ function querySelectorAllSafe(scope,selector){
634
+ if(!scope||!selector) return [];
635
+ try{
636
+ var nodeList=scope.querySelectorAll(selector);
637
+ return nodeList?Array.prototype.slice.call(nodeList):[];
638
+ }catch(e){}
639
+ return [];
356
640
  }
357
641
 
358
- function resolveFromFingerprint(fingerprint,payload,metrics){
359
- if(!fingerprint) return null;
642
+ function resolveFromFingerprint(fingerprint,payload,metrics,scope){
643
+ if(!fingerprint) return { element:null, ambiguous:false, bestScore:Infinity };
644
+ var searchScope=scope||document;
360
645
  if(fingerprint.id){
361
- var byId=document.getElementById(fingerprint.id);
362
- if(byId) return byId;
646
+ var byId=searchScope.getElementById?searchScope.getElementById(fingerprint.id):null;
647
+ if(!byId&&searchScope.querySelector){
648
+ try{ byId=searchScope.querySelector('#'+cssEscape(fingerprint.id)); }catch(e){}
649
+ }
650
+ if(byId) return { element:byId, ambiguous:false, bestScore:0 };
363
651
  }
364
652
  var tag=fingerprint.tag||'*';
365
653
  var selector=tag;
366
654
  if(Array.isArray(fingerprint.classes)&&fingerprint.classes.length>0){
367
655
  selector+= '.'+fingerprint.classes.map(cssEscape).join('.');
368
656
  }
369
- try{
370
- var nodes=document.querySelectorAll(selector);
371
- return pickBestElement(nodes,payload,metrics,fingerprint.sibling_path);
372
- }catch(e){}
373
- return null;
657
+ var nodes=querySelectorAllSafe(searchScope,selector);
658
+ return pickBestElement(nodes,payload,metrics,fingerprint.sibling_path);
374
659
  }
375
660
 
376
661
  function isStrongContainerHint(hint){
@@ -384,56 +669,142 @@ function trackingScript() {
384
669
  return false;
385
670
  }
386
671
 
672
+ function resolveTransientRoot(payload,metrics){
673
+ var transient=payload&&payload.transient_context;
674
+ if(!transient||typeof transient!=='object') return null;
675
+ var root=null;
676
+ if(Array.isArray(transient.root_selector_chain)){
677
+ for(var i=0;i<transient.root_selector_chain.length;i++){
678
+ var candidate=transient.root_selector_chain[i];
679
+ if(!candidate||typeof candidate.selector!=='string') continue;
680
+ var nodes=querySelectorAllSafe(document,candidate.selector);
681
+ var rootMatch=pickBestElement(nodes,payload,metrics,transient.root_fingerprint&&transient.root_fingerprint.sibling_path);
682
+ root=rootMatch.element;
683
+ if(root) return root;
684
+ }
685
+ }
686
+ root=resolveFromFingerprint(transient.root_fingerprint,payload,metrics,document).element;
687
+ return root;
688
+ }
689
+
387
690
  function resolveAnchor(payload){
388
- if(!payload||typeof payload!=='object') return {coordFallback:null,strategy:'none',matchedSelector:null};
691
+ if(!payload||typeof payload!=='object') return {coordFallback:null,strategy:'none',matchedSelector:null,status:'none'};
692
+ if(!viewContextMatches(payload.view_context)){
693
+ return {
694
+ coordFallback:payload.coord_fallback||null,
695
+ strategy:'context_mismatch',
696
+ matchedSelector:null,
697
+ status:'context_mismatch'
698
+ };
699
+ }
389
700
  var element=null;
390
701
  var strategy='none';
391
702
  var matchedSelector=null;
392
703
  var metrics=getMetrics();
393
- if(Array.isArray(payload.selector_chain)){
704
+ var ambiguous=false;
705
+ var transientRoot=null;
706
+ var hasTransientContext=!!(payload.transient_context&&typeof payload.transient_context==='object');
707
+ if(hasTransientContext){
708
+ transientRoot=resolveTransientRoot(payload,metrics);
709
+ if(!transientRoot){
710
+ return {coordFallback:null,strategy:'transient_missing',matchedSelector:null,status:'transient_missing'};
711
+ }
712
+ }
713
+
714
+ function trySelectorChain(scope,scopeTag){
715
+ if(!Array.isArray(payload.selector_chain)) return false;
394
716
  for(var i=0;i<payload.selector_chain.length;i++){
395
717
  var candidate=payload.selector_chain[i];
396
718
  if(!candidate||typeof candidate.selector!=='string') continue;
397
- try{
398
- var nodes=document.querySelectorAll(candidate.selector);
399
- var found=pickBestElement(nodes,payload,metrics,null);
400
- if(found){
401
- element=found;
402
- strategy='selector';
403
- matchedSelector=candidate.selector;
404
- break;
405
- }
406
- }catch(e){}
719
+ var nodes=querySelectorAllSafe(scope,candidate.selector);
720
+ var found=pickBestElement(nodes,payload,metrics,null);
721
+ if(found&&found.element){
722
+ element=found.element;
723
+ ambiguous=!!found.ambiguous;
724
+ strategy='selector';
725
+ matchedSelector=(scopeTag?scopeTag+': ':'')+candidate.selector;
726
+ return true;
727
+ }
407
728
  }
729
+ return false;
730
+ }
731
+
732
+ if(transientRoot){
733
+ trySelectorChain(transientRoot,'transient_root');
408
734
  }
735
+ if(!element){
736
+ trySelectorChain(document,'document');
737
+ }
738
+
409
739
  if(
410
740
  !element&&
411
741
  payload.container_hint&&
412
742
  typeof payload.container_hint.selector==='string'&&
413
743
  isStrongContainerHint(payload.container_hint)
414
744
  ){
415
- try{
416
- var containerNodes=document.querySelectorAll(payload.container_hint.selector);
417
- var containerEl=pickBestElement(containerNodes,payload,metrics,null);
418
- if(containerEl){
419
- element=containerEl;
420
- strategy='container';
421
- matchedSelector=payload.container_hint.selector;
422
- }
423
- }catch(e){}
745
+ var containerNodesInRoot=transientRoot?querySelectorAllSafe(transientRoot,payload.container_hint.selector):[];
746
+ var containerMatch=pickBestElement(containerNodesInRoot,payload,metrics,null);
747
+ if(!containerMatch.element){
748
+ var containerNodes=querySelectorAllSafe(document,payload.container_hint.selector);
749
+ containerMatch=pickBestElement(containerNodes,payload,metrics,null);
750
+ }
751
+ if(containerMatch.element){
752
+ element=containerMatch.element;
753
+ ambiguous=!!containerMatch.ambiguous;
754
+ strategy='container';
755
+ matchedSelector=payload.container_hint.selector;
756
+ }
424
757
  }
425
758
  if(!element){
426
- var fpEl=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics);
427
- if(fpEl){
428
- element=fpEl;
759
+ var fpMatch=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics,transientRoot||undefined);
760
+ if(!fpMatch.element){
761
+ fpMatch=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics,document);
762
+ }
763
+ if(fpMatch.element){
764
+ element=fpMatch.element;
765
+ ambiguous=!!fpMatch.ambiguous;
429
766
  strategy='fingerprint';
430
767
  }
431
768
  }
432
- if(!element) return {coordFallback:null,strategy:'none',matchedSelector:null};
769
+ if(!element&&payload.scroll_context){
770
+ var fromContainer=getPointFromScrollContext(payload.scroll_context);
771
+ if(fromContainer){
772
+ return {
773
+ coordFallback:buildCoordFallback(fromContainer.clientX,fromContainer.clientY,metrics),
774
+ strategy:'scroll_container',
775
+ matchedSelector:null,
776
+ status:'resolved'
777
+ };
778
+ }
779
+ }
780
+ if(!element) return {coordFallback:null,strategy:'fallback',matchedSelector:null,status:'fallback_only'};
781
+ if(ambiguous){
782
+ return {
783
+ coordFallback:payload.coord_fallback||null,
784
+ strategy:'ambiguous',
785
+ matchedSelector:matchedSelector,
786
+ status:'ambiguous'
787
+ };
788
+ }
789
+ var target=getTargetDocPoint(payload,metrics);
790
+ if(target){
791
+ var anchorPoint=getAnchorClientPoint(element,payload);
792
+ var distX=(anchorPoint.clientX+metrics.scrollX)-target.x;
793
+ var distY=(anchorPoint.clientY+metrics.scrollY)-target.y;
794
+ var dist=Math.sqrt(distX*distX+distY*distY);
795
+ if(dist>220){
796
+ return {
797
+ coordFallback:payload.coord_fallback||null,
798
+ strategy:'ambiguous',
799
+ matchedSelector:matchedSelector,
800
+ status:'ambiguous'
801
+ };
802
+ }
803
+ }
433
804
  var point=getAnchorClientPoint(element,payload);
434
805
  var clientX=point.clientX;
435
806
  var clientY=point.clientY;
436
- return {coordFallback:buildCoordFallback(clientX,clientY,metrics),strategy:strategy,matchedSelector:matchedSelector};
807
+ return {coordFallback:buildCoordFallback(clientX,clientY,metrics),strategy:strategy,matchedSelector:matchedSelector,status:'resolved'};
437
808
  }
438
809
 
439
810
  function setPickMode(enabled){
@@ -522,18 +893,71 @@ function trackingScript() {
522
893
  scrollTick=true;
523
894
  requestAnimationFrame(function(){
524
895
  reportScroll();
896
+ reportDomMutation('scroll');
525
897
  scrollTick=false;
526
898
  });
527
899
  }
528
900
  }
901
+
902
+ var mutationTick=false;
903
+ function reportDomMutation(reason){
904
+ try{
905
+ window.parent.postMessage({
906
+ type:'checkpoint:domMutation',
907
+ reason:reason||'mutation',
908
+ path:location.pathname+location.search+location.hash
909
+ },'*');
910
+ }catch(e){}
911
+ }
912
+
913
+ function onMutation(){
914
+ if(mutationTick) return;
915
+ mutationTick=true;
916
+ requestAnimationFrame(function(){
917
+ mutationTick=false;
918
+ reportScroll();
919
+ reportDomMutation('mutation');
920
+ });
921
+ }
922
+
923
+ function setupMutationObserver(){
924
+ try{
925
+ if(!window.MutationObserver||!document.documentElement) return;
926
+ var observer=new MutationObserver(function(mutations){
927
+ for(var i=0;i<mutations.length;i++){
928
+ var m=mutations[i];
929
+ if(m.type==='childList'){
930
+ if((m.addedNodes&&m.addedNodes.length>0)||(m.removedNodes&&m.removedNodes.length>0)){
931
+ onMutation();
932
+ return;
933
+ }
934
+ }
935
+ if(m.type==='attributes'){
936
+ onMutation();
937
+ return;
938
+ }
939
+ }
940
+ });
941
+ observer.observe(document.documentElement,{
942
+ childList:true,
943
+ subtree:true,
944
+ attributes:true,
945
+ attributeFilter:['class','style','aria-hidden','aria-modal','data-state','open']
946
+ });
947
+ window.addEventListener('beforeunload',function(){ try{observer.disconnect();}catch(e){}; });
948
+ }catch(e){}
949
+ }
950
+
529
951
  reportNav();
530
952
  reportScroll();
953
+ setupMutationObserver();
531
954
  var _ps=history.pushState,_rs=history.replaceState;
532
955
  history.pushState=function(){_ps.apply(this,arguments);reportNav();};
533
956
  history.replaceState=function(){_rs.apply(this,arguments);reportNav();};
534
957
  window.addEventListener('popstate',reportNav);
535
958
  window.addEventListener('hashchange',reportNav);
536
959
  window.addEventListener('scroll',onScroll,{passive:true});
960
+ document.addEventListener('scroll',onScroll,true);
537
961
  window.addEventListener('resize',reportScroll);
538
962
  window.addEventListener('message',function(e){
539
963
  try{
@@ -549,23 +973,14 @@ function trackingScript() {
549
973
  var item=e.data.items[i];
550
974
  if(!item||typeof item.id!=='string') continue;
551
975
  var result=resolveAnchor(item.anchorPayload);
552
- if(result.coordFallback){
553
- positions.push({
554
- id:item.id,
555
- found:true,
556
- strategy:result.strategy,
557
- matchedSelector:result.matchedSelector,
558
- coordFallback:result.coordFallback
559
- });
560
- } else {
561
- positions.push({
562
- id:item.id,
563
- found:false,
564
- strategy:'fallback',
565
- matchedSelector:null,
566
- coordFallback:null
567
- });
568
- }
976
+ positions.push({
977
+ id:item.id,
978
+ found:!!result.coordFallback,
979
+ status:result.status||'none',
980
+ strategy:result.strategy,
981
+ matchedSelector:result.matchedSelector,
982
+ coordFallback:result.coordFallback||null
983
+ });
569
984
  }
570
985
  window.parent.postMessage({
571
986
  type:'checkpoint:anchorsResolved',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Share your localhost with reviewers — get visual feedback directly on the page",
5
5
  "keywords": [
6
6
  "checkpoint",