checkpoint-cli 0.3.5 → 0.3.7

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.
package/dist/index.js CHANGED
@@ -1606,7 +1606,7 @@ const program = new commander_1.Command();
1606
1606
  program
1607
1607
  .name('checkpoint')
1608
1608
  .description('Share your localhost with reviewers — get visual feedback directly on the page')
1609
- .version('0.3.5');
1609
+ .version('0.3.7');
1610
1610
  // ── checkpoint login ──
1611
1611
  program
1612
1612
  .command('login')
@@ -43,6 +43,49 @@ function buildMinimalTrackingScript() {
43
43
  return String(value).replace(/\s+/g,' ').trim().slice(0,120);
44
44
  }
45
45
 
46
+ function normalizedText(value){
47
+ return shortText(value).toLowerCase();
48
+ }
49
+
50
+ function getNodeText(node){
51
+ try{
52
+ if(!node||!node.textContent) return '';
53
+ return normalizedText(node.textContent);
54
+ }catch(e){}
55
+ return '';
56
+ }
57
+
58
+ function getTextContext(target){
59
+ if(!target||target.nodeType!==1) return null;
60
+ var self=getNodeText(target);
61
+ var parent=getNodeText(target.parentElement);
62
+ var before=getNodeText(target.previousElementSibling);
63
+ var after=getNodeText(target.nextElementSibling);
64
+
65
+ // If clicked node has no text (e.g. image/icon), borrow nearest parent text.
66
+ if(!self){
67
+ var current=target.parentElement;
68
+ var depth=0;
69
+ while(current&&depth<4&&!self){
70
+ var candidate=getNodeText(current);
71
+ if(candidate&&candidate.length>=3){
72
+ self=candidate;
73
+ break;
74
+ }
75
+ current=current.parentElement;
76
+ depth++;
77
+ }
78
+ }
79
+
80
+ if(!self&&!parent&&!before&&!after) return null;
81
+ return {
82
+ self:self||undefined,
83
+ parent:parent||undefined,
84
+ before:before||undefined,
85
+ after:after||undefined
86
+ };
87
+ }
88
+
46
89
  function cssEscape(value){
47
90
  try{
48
91
  if(window.CSS&&typeof window.CSS.escape==='function') return window.CSS.escape(value);
@@ -209,6 +252,38 @@ function buildMinimalTrackingScript() {
209
252
  return score;
210
253
  }
211
254
 
255
+ function getTargetDocPoint(payload,metrics){
256
+ var fallback=payload&&payload.coord_fallback;
257
+ if(!fallback||typeof fallback!=='object') return null;
258
+ var docW=(typeof fallback.doc_width==='number'&&fallback.doc_width>0)
259
+ ? fallback.doc_width
260
+ : (metrics.docWidth||metrics.viewWidth||1);
261
+ var docH=(typeof fallback.doc_height==='number'&&fallback.doc_height>0)
262
+ ? fallback.doc_height
263
+ : (metrics.docHeight||metrics.viewHeight||1);
264
+ if(typeof fallback.doc_x_percent==='number'&&typeof fallback.doc_y_percent==='number'){
265
+ return {
266
+ x:(fallback.doc_x_percent/100)*docW,
267
+ y:(fallback.doc_y_percent/100)*docH
268
+ };
269
+ }
270
+ if(typeof fallback.x_percent==='number'&&typeof fallback.y_percent==='number'){
271
+ var viewW=(typeof fallback.viewport_width==='number'&&fallback.viewport_width>0)
272
+ ? fallback.viewport_width
273
+ : (metrics.viewWidth||1);
274
+ var viewH=(typeof fallback.viewport_height==='number'&&fallback.viewport_height>0)
275
+ ? fallback.viewport_height
276
+ : (metrics.viewHeight||1);
277
+ var scrollX=typeof fallback.scroll_x==='number'?fallback.scroll_x:metrics.scrollX;
278
+ var scrollY=typeof fallback.scroll_y==='number'?fallback.scroll_y:metrics.scrollY;
279
+ return {
280
+ x:(fallback.x_percent/100)*viewW+scrollX,
281
+ y:(fallback.y_percent/100)*viewH+scrollY
282
+ };
283
+ }
284
+ return null;
285
+ }
286
+
212
287
  function getElementAtPoint(x,y){
213
288
  try{
214
289
  if(pickShield) pickShield.style.pointerEvents='none';
@@ -258,10 +333,11 @@ function buildMinimalTrackingScript() {
258
333
  var metrics=getMetrics();
259
334
  var sourceTarget=findBestAnchorableElement(el);
260
335
  var anchorEl=sourceTarget.element||el;
336
+ var textContext=getTextContext(el)||getTextContext(anchorEl);
261
337
  return {
262
338
  selector_chain:[],
263
339
  dom_fingerprint:null,
264
- text_context:null,
340
+ text_context:textContext,
265
341
  container_hint:null,
266
342
  transient_context:null,
267
343
  source_anchor:sourceTarget.sourceAnchor||getSourceAnchorFromElement(anchorEl),
@@ -269,7 +345,32 @@ function buildMinimalTrackingScript() {
269
345
  };
270
346
  }
271
347
 
272
- function findBySource(sourceAnchor,scope){
348
+ function textMatchBonus(node,textContext){
349
+ if(!textContext||typeof textContext!=='object') return 0;
350
+ var score=0;
351
+ var self=getNodeText(node);
352
+ var parent=getNodeText(node&&node.parentElement);
353
+ if(textContext.self&&self){
354
+ if(self===textContext.self) score+=280;
355
+ else if(self.indexOf(textContext.self)>=0||textContext.self.indexOf(self)>=0) score+=130;
356
+ else score-=40;
357
+ }
358
+ if(textContext.parent&&parent){
359
+ if(parent===textContext.parent) score+=180;
360
+ else if(parent.indexOf(textContext.parent)>=0||textContext.parent.indexOf(parent)>=0) score+=90;
361
+ }
362
+ if(textContext.before){
363
+ var prev=getNodeText(node&&node.previousElementSibling);
364
+ if(prev&&prev===textContext.before) score+=55;
365
+ }
366
+ if(textContext.after){
367
+ var next=getNodeText(node&&node.nextElementSibling);
368
+ if(next&&next===textContext.after) score+=55;
369
+ }
370
+ return score;
371
+ }
372
+
373
+ function findBySource(sourceAnchor,payload,scope){
273
374
  if(!sourceAnchor||typeof sourceAnchor!=='object') return null;
274
375
  var searchScope=scope||document;
275
376
  if(sourceAnchor.explicit_id){
@@ -283,10 +384,23 @@ function buildMinimalTrackingScript() {
283
384
  }catch(e){ nodes=[]; }
284
385
  if(nodes.length>1800) nodes=nodes.slice(0,1800);
285
386
  var best=null;
286
- var bestScore=0;
387
+ var bestScore=-Infinity;
388
+ var metrics=getMetrics();
389
+ var targetDocPoint=getTargetDocPoint(payload,metrics);
287
390
  for(var i=0;i<nodes.length;i++){
288
391
  var node=nodes[i];
289
392
  var score=sourceMatchScore(node,sourceAnchor);
393
+ if(score<=0) continue;
394
+ score+=textMatchBonus(node,payload&&payload.text_context);
395
+ if(targetDocPoint&&node.getBoundingClientRect){
396
+ var r=node.getBoundingClientRect();
397
+ var centerX=r.left+(r.width/2)+metrics.scrollX;
398
+ var centerY=r.top+(r.height/2)+metrics.scrollY;
399
+ var dx=centerX-targetDocPoint.x;
400
+ var dy=centerY-targetDocPoint.y;
401
+ var distance=Math.sqrt(dx*dx+dy*dy);
402
+ score-=Math.min(280,distance*0.85);
403
+ }
290
404
  if(score>bestScore){
291
405
  best=node;
292
406
  bestScore=score;
@@ -300,7 +414,7 @@ function buildMinimalTrackingScript() {
300
414
  return { coordFallback:null, strategy:'none', matchedSelector:null, status:'none' };
301
415
  }
302
416
  if(payload.source_anchor){
303
- var match=findBySource(payload.source_anchor,document);
417
+ var match=findBySource(payload.source_anchor,payload,document);
304
418
  if(match&&match.getBoundingClientRect){
305
419
  var rect=match.getBoundingClientRect();
306
420
  var clientX=rect.left+Math.max(1,Math.min(Math.max(2,rect.width)-1,rect.width/2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "checkpoint-cli",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Share your localhost with reviewers — get visual feedback directly on the page",
5
5
  "keywords": [
6
6
  "checkpoint",