checkpoint-cli 0.1.5 → 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 +137 -11
  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,22 +368,35 @@ 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
388
  if(!payload||typeof payload!=='object') return {coordFallback:null,strategy:'none',matchedSelector:null};
270
389
  var element=null;
271
390
  var strategy='none';
272
391
  var matchedSelector=null;
392
+ var metrics=getMetrics();
273
393
  if(Array.isArray(payload.selector_chain)){
274
394
  for(var i=0;i<payload.selector_chain.length;i++){
275
395
  var candidate=payload.selector_chain[i];
276
396
  if(!candidate||typeof candidate.selector!=='string') continue;
277
397
  try{
278
- var found=document.querySelector(candidate.selector);
398
+ var nodes=document.querySelectorAll(candidate.selector);
399
+ var found=pickBestElement(nodes,payload,metrics,null);
279
400
  if(found){
280
401
  element=found;
281
402
  strategy='selector';
@@ -285,9 +406,15 @@ function trackingScript() {
285
406
  }catch(e){}
286
407
  }
287
408
  }
288
- 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
+ ){
289
415
  try{
290
- var containerEl=document.querySelector(payload.container_hint.selector);
416
+ var containerNodes=document.querySelectorAll(payload.container_hint.selector);
417
+ var containerEl=pickBestElement(containerNodes,payload,metrics,null);
291
418
  if(containerEl){
292
419
  element=containerEl;
293
420
  strategy='container';
@@ -296,17 +423,16 @@ function trackingScript() {
296
423
  }catch(e){}
297
424
  }
298
425
  if(!element){
299
- var fpEl=resolveFromFingerprint(payload.dom_fingerprint);
426
+ var fpEl=resolveFromFingerprint(payload.dom_fingerprint,payload,metrics);
300
427
  if(fpEl){
301
428
  element=fpEl;
302
429
  strategy='fingerprint';
303
430
  }
304
431
  }
305
432
  if(!element) return {coordFallback:null,strategy:'none',matchedSelector:null};
306
- var rect=element.getBoundingClientRect();
307
- var clientX=rect.left+Math.max(1,Math.min(rect.width-1,rect.width*0.5));
308
- var clientY=rect.top+Math.max(1,Math.min(rect.height-1,rect.height*0.5));
309
- var metrics=getMetrics();
433
+ var point=getAnchorClientPoint(element,payload);
434
+ var clientX=point.clientX;
435
+ var clientY=point.clientY;
310
436
  return {coordFallback:buildCoordFallback(clientX,clientY,metrics),strategy:strategy,matchedSelector:matchedSelector};
311
437
  }
312
438
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.1.5",
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",