[object Object]

← back to Commercialrealestate

Fix broker-grid column resize (adjust column not working)

ed0652fb269792a36d9699e10d1ce2990a7d85f9 · 2026-07-31 10:53:44 -0700 · Steve Abrams

Column resize was visually inert and, after any interaction, fully dead.
Four compounding root causes, all fixed:

1. table-layout:fixed + width:auto made the browser ignore <col> widths
   entirely — resizing set the width but nothing changed on screen. Pin the
   table width to the sum of column widths (syncTableWidth) so <col> widths
   are authoritative and the table scrolls in its overflow-x wrapper.
2. render() rebuilt <thead> innerHTML on every sort/search/filter, wiping the
   drag handles; re-init was gated on column-set change so handles never
   returned. Added ColResize.reattach() + call it on same-column re-renders.
3. draggable="true" ths (column reorder) hijacked the resize gesture via a
   native HTML5 drag. Handle now sits inside the edge (right:0, not straddling
   the next sticky th) + disable ancestor draggable while over the handle.
4. The app's thead click->sort handler didn't ignore handle clicks, so
   grabbing/double-clicking the handle sorted + re-rendered mid-gesture
   (spurious sorts; autofit collapsed to 40px). Guard sort on .cr-handle /
   cr-dragging. Also read startW from style, not the flaky <col> rect.

Verified real-mouse (Playwright): resize applies + persists across reload,
survives sort/search/toggle/reorder, double-click autofit content-fits,
reorder intact, no spurious sort, 0 console errors. TK-10088.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit ed0652fb269792a36d9699e10d1ce2990a7d85f9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Jul 31 10:53:44 2026 -0700

    Fix broker-grid column resize (adjust column not working)
    
    Column resize was visually inert and, after any interaction, fully dead.
    Four compounding root causes, all fixed:
    
    1. table-layout:fixed + width:auto made the browser ignore <col> widths
       entirely — resizing set the width but nothing changed on screen. Pin the
       table width to the sum of column widths (syncTableWidth) so <col> widths
       are authoritative and the table scrolls in its overflow-x wrapper.
    2. render() rebuilt <thead> innerHTML on every sort/search/filter, wiping the
       drag handles; re-init was gated on column-set change so handles never
       returned. Added ColResize.reattach() + call it on same-column re-renders.
    3. draggable="true" ths (column reorder) hijacked the resize gesture via a
       native HTML5 drag. Handle now sits inside the edge (right:0, not straddling
       the next sticky th) + disable ancestor draggable while over the handle.
    4. The app's thead click->sort handler didn't ignore handle clicks, so
       grabbing/double-clicking the handle sorted + re-rendered mid-gesture
       (spurious sorts; autofit collapsed to 40px). Guard sort on .cr-handle /
       cr-dragging. Also read startW from style, not the flaky <col> rect.
    
    Verified real-mouse (Playwright): resize applies + persists across reload,
    survives sort/search/toggle/reorder, double-click autofit content-fits,
    reorder intact, no spurious sort, 0 console errors. TK-10088.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/broker-grid.html | 9 ++++++++-
 public/col-resize.js    | 9 ++++++++-
 public/crcp.html        | 7 +++++++
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/public/broker-grid.html b/public/broker-grid.html
index 14465c0..4d6fe20 100644
--- a/public/broker-grid.html
+++ b/public/broker-grid.html
@@ -342,7 +342,14 @@ async function openContact(name,id){
     +((!(d.closed&&d.closed.length)||!(d.expired&&d.expired.length))?'<div class="mut" style="margin-top:6px;opacity:.85">📊 Coverage: active listings only'+(d.current.length?'':' — none attributed here yet')+'. '+[!(d.closed&&d.closed.length)?'closed':'',!(d.expired&&d.expired.length)?'withdrawn/expired':''].filter(Boolean).join(' & ')+' history isn’t in free public records (needs a paid records source).</div>':'');
 }
 document.addEventListener('click',e=>{ const fm=e.target.closest('.findmail'); if(fm){ findEmail(fm.dataset.id); return; } const row=e.target.closest('.brow'); if(row && e.target.tagName!=='A' && e.target.tagName!=='BUTTON'){ openContact(row.dataset.name,row.dataset.id); } if(e.target.id==='ov') $('#ov').classList.remove('on'); });
-$('#thead').addEventListener('click',e=>{const th=e.target.closest('th');if(!th)return;const k=th.dataset.k;
+$('#thead').addEventListener('click',e=>{
+  // A click on the resize handle (or the tail of a resize drag) must NOT sort —
+  // otherwise grabbing/double-clicking the handle re-renders the thead mid-gesture,
+  // detaching the cell col-resize is measuring (collapsed autofit) and firing a
+  // spurious sort on every resize. col-resize owns the handle; the app owns sort.
+  if(e.target.closest('.cr-handle'))return;
+  if(document.body.classList.contains('cr-dragging'))return;
+  const th=e.target.closest('th');if(!th)return;const k=th.dataset.k;
   if(sortKey===k)sortDir*=-1;else{sortKey=k;sortDir=(k==='listings'||k==='total_assets'||k==='created_at')?-1:1;}
   localStorage.setItem('brokSortKey',sortKey);localStorage.setItem('brokSortDir',sortDir);if(window.__syncSortSel)window.__syncSortSel();render();});
 // ── drag-to-reorder columns (Steve rule 2026-07-31: move columns around) ──
diff --git a/public/col-resize.js b/public/col-resize.js
index 679a8b7..79e7785 100644
--- a/public/col-resize.js
+++ b/public/col-resize.js
@@ -259,7 +259,11 @@
     function down(e) {
       dragging = true;
       startX = (e.touches ? e.touches[0].clientX : e.clientX);
-      startW = cols[idx].getBoundingClientRect().width;
+      // Read the width we SET, not <col>.getBoundingClientRect() — that rect is
+      // unreliable for a <col> (Chromium returns stale/tiny values, same quirk as
+      // TK-10089). A bad startW + a zero-delta move (e.g. the mousedowns inside a
+      // double-click) would otherwise collapse the column to MIN (40px).
+      startW = parseFloat(cols[idx].style.width) || cols[idx].getBoundingClientRect().width;
       document.body.classList.add('cr-dragging');
       window.addEventListener('pointermove', move);
       window.addEventListener('pointerup', up);
@@ -299,12 +303,15 @@
       // Remember every column's current width, let this one go auto, measure, restore.
       var widths = [];
       for (var i = 0; i < cols.length; i++) widths[i] = cols[i].style.width;
+      var savedTableW = table.style.width;
       table.style.tableLayout = 'auto';
+      table.style.width = '';                 // release the pinned width so the column can size to content
       cols[idx].style.width = '';
       var natural = Math.max(MIN, Math.round(headers[idx].getBoundingClientRect().width));
       for (var j = 0; j < cols.length; j++) cols[j].style.width = widths[j];
       cols[idx].style.width = natural + 'px';
       table.style.tableLayout = 'fixed';
+      table.style.width = savedTableW;
       syncTableWidth(table, cols);
       save(sig, idx, natural);
     }
diff --git a/public/crcp.html b/public/crcp.html
index 780d0d0..26257f8 100644
--- a/public/crcp.html
+++ b/public/crcp.html
@@ -368,6 +368,13 @@ async function poll(){
 })();
 poll(); setInterval(poll, 3000);
 loadSegments(); setInterval(loadSegments, 20000);
+// deep-link from the graphics dashboard: ?broker=<id>[&name=…]  ·  ?firm=<name>
+(function(){ try{
+  const P=new URLSearchParams(location.search);
+  const bid=P.get('broker'), fm=P.get('firm');
+  if(bid){ openContact(P.get('name')||'', bid); }
+  else if(fm){ openFirm(fm); }
+}catch(e){} })();
 </script>
   <script src="/col-resize.js" defer></script>
 </body>

← 22eb700 CRCP lending layer: FDIC lenders slice — 95 banks w/ LA-Coun  ·  back to Commercialrealestate  ·  crcp graphics.html: make every datum drillable (TK-10091) f5e7a1a →