checkpoint-cli 0.1.4 → 0.1.6

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 +166 -17
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -235,6 +235,16 @@ function trackingScript() {
235
235
  textSelf=shortText(el&&el.textContent);
236
236
  textParent=shortText(el&&el.parentElement&&el.parentElement.textContent);
237
237
  }catch(e){}
238
+ var fallback=buildCoordFallback(clientX,clientY,metrics);
239
+ try{
240
+ var rect=el&&el.getBoundingClientRect?el.getBoundingClientRect():null;
241
+ if(rect){
242
+ var safeW=Math.max(1,rect.width||1);
243
+ var safeH=Math.max(1,rect.height||1);
244
+ fallback.element_x_percent=clampPercent(((clientX-rect.left)/safeW)*100);
245
+ fallback.element_y_percent=clampPercent(((clientY-rect.top)/safeH)*100);
246
+ }
247
+ }catch(e){}
238
248
  return {
239
249
  selector_chain:getSelectorChain(el),
240
250
  dom_fingerprint:getDomFingerprint(el),
@@ -243,11 +253,109 @@ function trackingScript() {
243
253
  parent:textParent
244
254
  },
245
255
  container_hint:getContainerHint(el),
246
- coord_fallback:buildCoordFallback(clientX,clientY,metrics)
256
+ coord_fallback:fallback
247
257
  };
248
258
  }
249
259
 
250
- function resolveFromFingerprint(fingerprint){
260
+ function getTargetDocPoint(payload,metrics){
261
+ var fallback=payload&&payload.coord_fallback;
262
+ if(!fallback||typeof fallback!=='object') return null;
263
+ var docW=(typeof fallback.doc_width==='number'&&fallback.doc_width>0)
264
+ ? fallback.doc_width
265
+ : (metrics.docWidth||metrics.viewWidth||1);
266
+ var docH=(typeof fallback.doc_height==='number'&&fallback.doc_height>0)
267
+ ? fallback.doc_height
268
+ : (metrics.docHeight||metrics.viewHeight||1);
269
+ if(typeof fallback.doc_x_percent==='number'&&typeof fallback.doc_y_percent==='number'){
270
+ return {
271
+ x:(fallback.doc_x_percent/100)*docW,
272
+ y:(fallback.doc_y_percent/100)*docH
273
+ };
274
+ }
275
+ if(typeof fallback.x_percent==='number'&&typeof fallback.y_percent==='number'){
276
+ var viewW=(typeof fallback.viewport_width==='number'&&fallback.viewport_width>0)
277
+ ? fallback.viewport_width
278
+ : (metrics.viewWidth||1);
279
+ var viewH=(typeof fallback.viewport_height==='number'&&fallback.viewport_height>0)
280
+ ? fallback.viewport_height
281
+ : (metrics.viewHeight||1);
282
+ var scrollX=typeof fallback.scroll_x==='number'?fallback.scroll_x:metrics.scrollX;
283
+ var scrollY=typeof fallback.scroll_y==='number'?fallback.scroll_y:metrics.scrollY;
284
+ return {
285
+ x:(fallback.x_percent/100)*viewW+scrollX,
286
+ y:(fallback.y_percent/100)*viewH+scrollY
287
+ };
288
+ }
289
+ return null;
290
+ }
291
+
292
+ function getAnchorClientPoint(el,payload){
293
+ var rect=el.getBoundingClientRect();
294
+ var safeW=Math.max(2,rect.width||2);
295
+ var safeH=Math.max(2,rect.height||2);
296
+ var relX=0.5;
297
+ var relY=0.5;
298
+ var fallback=payload&&payload.coord_fallback;
299
+ if(fallback&&typeof fallback.element_x_percent==='number'){
300
+ relX=clampPercent(fallback.element_x_percent)/100;
301
+ }
302
+ if(fallback&&typeof fallback.element_y_percent==='number'){
303
+ relY=clampPercent(fallback.element_y_percent)/100;
304
+ }
305
+ return {
306
+ clientX:rect.left+Math.max(1,Math.min(safeW-1,safeW*relX)),
307
+ clientY:rect.top+Math.max(1,Math.min(safeH-1,safeH*relY))
308
+ };
309
+ }
310
+
311
+ function siblingPathDistance(el,path){
312
+ if(!Array.isArray(path)||path.length===0) return 0;
313
+ var current=getSiblingPath(el);
314
+ var maxLen=Math.max(current.length,path.length);
315
+ var dist=Math.abs(current.length-path.length)*5;
316
+ var cOffset=maxLen-current.length;
317
+ var pOffset=maxLen-path.length;
318
+ for(var i=0;i<maxLen;i++){
319
+ var cVal=current[i-cOffset];
320
+ var pVal=path[i-pOffset];
321
+ if(typeof cVal==='number'&&typeof pVal==='number'){
322
+ dist+=Math.abs(cVal-pVal);
323
+ }else{
324
+ dist+=2;
325
+ }
326
+ }
327
+ return dist;
328
+ }
329
+
330
+ function pickBestElement(nodes,payload,metrics,fingerprintPath){
331
+ if(!nodes||nodes.length===0) return null;
332
+ var target=getTargetDocPoint(payload,metrics);
333
+ var best=null;
334
+ var bestScore=Infinity;
335
+ for(var i=0;i<nodes.length;i++){
336
+ var node=nodes[i];
337
+ if(!node||node.nodeType!==1) continue;
338
+ var anchorPoint=getAnchorClientPoint(node,payload);
339
+ var docX=anchorPoint.clientX+metrics.scrollX;
340
+ var docY=anchorPoint.clientY+metrics.scrollY;
341
+ var score=0;
342
+ if(target){
343
+ var dx=docX-target.x;
344
+ var dy=docY-target.y;
345
+ score+=Math.sqrt(dx*dx+dy*dy);
346
+ }
347
+ if(Array.isArray(fingerprintPath)&&fingerprintPath.length>0){
348
+ score+=siblingPathDistance(node,fingerprintPath)*40;
349
+ }
350
+ if(score<bestScore){
351
+ best=node;
352
+ bestScore=score;
353
+ }
354
+ }
355
+ return best;
356
+ }
357
+
358
+ function resolveFromFingerprint(fingerprint,payload,metrics){
251
359
  if(!fingerprint) return null;
252
360
  if(fingerprint.id){
253
361
  var byId=document.getElementById(fingerprint.id);
@@ -260,41 +368,72 @@ function trackingScript() {
260
368
  }
261
369
  try{
262
370
  var nodes=document.querySelectorAll(selector);
263
- if(nodes&&nodes.length>0) return nodes[0];
371
+ return pickBestElement(nodes,payload,metrics,fingerprint.sibling_path);
264
372
  }catch(e){}
265
373
  return null;
266
374
  }
267
375
 
376
+ function isStrongContainerHint(hint){
377
+ if(!hint||typeof hint!=='object') return false;
378
+ if(typeof hint.id==='string'&&hint.id.length>0) return true;
379
+ if(typeof hint.selector==='string'){
380
+ if(hint.selector.indexOf('#')===0) return true;
381
+ if(hint.selector.indexOf('[data-testid')>=0) return true;
382
+ if(hint.selector.indexOf('[role=')>=0) return true;
383
+ }
384
+ return false;
385
+ }
386
+
268
387
  function resolveAnchor(payload){
269
- if(!payload||typeof payload!=='object') return null;
388
+ if(!payload||typeof payload!=='object') return {coordFallback:null,strategy:'none',matchedSelector:null};
270
389
  var element=null;
390
+ var strategy='none';
391
+ var matchedSelector=null;
392
+ var metrics=getMetrics();
271
393
  if(Array.isArray(payload.selector_chain)){
272
394
  for(var i=0;i<payload.selector_chain.length;i++){
273
395
  var candidate=payload.selector_chain[i];
274
396
  if(!candidate||typeof candidate.selector!=='string') continue;
275
397
  try{
276
- var found=document.querySelector(candidate.selector);
398
+ var nodes=document.querySelectorAll(candidate.selector);
399
+ var found=pickBestElement(nodes,payload,metrics,null);
277
400
  if(found){
278
401
  element=found;
402
+ strategy='selector';
403
+ matchedSelector=candidate.selector;
279
404
  break;
280
405
  }
281
406
  }catch(e){}
282
407
  }
283
408
  }
284
- if(!element&&payload.container_hint&&typeof payload.container_hint.selector==='string'){
409
+ if(
410
+ !element&&
411
+ payload.container_hint&&
412
+ typeof payload.container_hint.selector==='string'&&
413
+ isStrongContainerHint(payload.container_hint)
414
+ ){
285
415
  try{
286
- element=document.querySelector(payload.container_hint.selector);
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
+ }
287
423
  }catch(e){}
288
424
  }
289
425
  if(!element){
290
- element=resolveFromFingerprint(payload.dom_fingerprint);
426
+ var fpEl=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics);
427
+ if(fpEl){
428
+ element=fpEl;
429
+ strategy='fingerprint';
430
+ }
291
431
  }
292
- if(!element) return null;
293
- var rect=element.getBoundingClientRect();
294
- var clientX=rect.left+Math.max(1,Math.min(rect.width-1,rect.width*0.5));
295
- var clientY=rect.top+Math.max(1,Math.min(rect.height-1,rect.height*0.5));
296
- var metrics=getMetrics();
297
- return buildCoordFallback(clientX,clientY,metrics);
432
+ if(!element) return {coordFallback:null,strategy:'none',matchedSelector:null};
433
+ var point=getAnchorClientPoint(element,payload);
434
+ var clientX=point.clientX;
435
+ var clientY=point.clientY;
436
+ return {coordFallback:buildCoordFallback(clientX,clientY,metrics),strategy:strategy,matchedSelector:matchedSelector};
298
437
  }
299
438
 
300
439
  function setPickMode(enabled){
@@ -409,12 +548,22 @@ function trackingScript() {
409
548
  for(var i=0;i<e.data.items.length;i++){
410
549
  var item=e.data.items[i];
411
550
  if(!item||typeof item.id!=='string') continue;
412
- var coordFallback=resolveAnchor(item.anchorPayload);
413
- if(coordFallback){
551
+ var result=resolveAnchor(item.anchorPayload);
552
+ if(result.coordFallback){
414
553
  positions.push({
415
554
  id:item.id,
416
555
  found:true,
417
- coordFallback:coordFallback
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
418
567
  });
419
568
  }
420
569
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Share your localhost with reviewers — get visual feedback directly on the page",
5
5
  "keywords": [
6
6
  "checkpoint",