[object Object]

← back to Rentv

News map: add From/To year-range filter (2015-present)

7ac0a3d5b1445cbe98143b1fc8e2c232c8c15eaf · 2026-08-06 09:12:23 -0700 · Steve Abrams

Makes the 11-year archive navigable — scope pins + list to any year span. Wired
into passFilter (composes with freshness + type filters); Reset restores full range.

TK-10284

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

Files touched

Diff

commit 7ac0a3d5b1445cbe98143b1fc8e2c232c8c15eaf
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Aug 6 09:12:23 2026 -0700

    News map: add From/To year-range filter (2015-present)
    
    Makes the 11-year archive navigable — scope pins + list to any year span. Wired
    into passFilter (composes with freshness + type filters); Reset restores full range.
    
    TK-10284
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 public/map.html | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/public/map.html b/public/map.html
index 4f2e02af..2956a25e 100644
--- a/public/map.html
+++ b/public/map.html
@@ -71,6 +71,12 @@ aside .ah{padding:12px 16px;border-bottom:1px solid var(--line);font-size:12px;f
   <label>Type
     <select id="txn"><option value="">All</option></select>
   </label>
+  <label>Years
+    <select id="yfrom" title="From year"></select>
+  </label>
+  <label style="margin-left:-8px">–
+    <select id="yto" title="To year"></select>
+  </label>
   <button class="btn" id="near">📍 Near me</button>
   <button class="btn ghost" id="reset">Reset view</button>
 </div></div>
@@ -113,7 +119,7 @@ setTimeout(function(){map.invalidateSize();},200);
 window.addEventListener('resize',function(){map.invalidateSize();});
 
 var ALL=[], markers=[], meMarker=null, meLatLng=null;
-var fFresh='all', fTxn='';
+var fFresh='all', fTxn='', fYFrom=0, fYTo=9999;
 
 function popupHtml(a){
   var meta=[a.city+(a.state?', '+a.state:''), a.txn, a.ptype, a.amt].filter(Boolean).join(' · ');
@@ -125,6 +131,8 @@ function passFilter(a){
   if(fFresh==='new' && !a._fresh) return false;
   if(fFresh==='old' && a._fresh) return false;
   if(fTxn && a.txn!==fTxn) return false;
+  var y=parseInt((a.date||'').slice(0,4),10)||0;
+  if(y && (y<fYFrom || y>fYTo)) return false;
   return true;
 }
 function buildMarkers(){
@@ -192,7 +200,10 @@ map.on('moveend',function(){ if(!meLatLng) refreshList(); });
 $('fresh').onchange=function(e){fFresh=e.target.value;buildMarkers();};
 $('txn').onchange=function(e){fTxn=e.target.value;buildMarkers();};
 $('reset').onclick=function(){ meLatLng=null; if(meMarker){map.removeLayer(meMarker);meMarker=null;}
-  map.setView([37.5,-119],5); refreshList(); };
+  fFresh='all';$('fresh').value='all'; fTxn='';$('txn').value='';
+  if($('yfrom').options.length){fYFrom=parseInt($('yfrom').options[$('yfrom').options.length-1].value,10);$('yfrom').value=fYFrom;
+    fYTo=parseInt($('yto').options[0].value,10);$('yto').value=fYTo;}
+  map.setView([37.5,-119],5); buildMarkers(); };
 $('near').onclick=function(){
   if(!navigator.geolocation){alert('Location isn’t available in this browser.');return;}
   $('near').textContent='📍 Locating…';
@@ -214,6 +225,17 @@ fetch('/api/map-articles').then(function(r){return r.json();}).then(function(d){
   // populate txn filter from data
   var txns={}; ALL.forEach(function(a){if(a.txn)txns[a.txn]=1;});
   Object.keys(txns).sort().forEach(function(t){var o=document.createElement('option');o.value=t;o.textContent=t;$('txn').appendChild(o);});
+  // populate year range from data (spans ~2015..present)
+  var yrs=ALL.map(function(a){return parseInt((a.date||'').slice(0,4),10)||0;}).filter(Boolean);
+  var yMin=Math.min.apply(null,yrs), yMax=Math.max.apply(null,yrs);
+  fYFrom=yMin; fYTo=yMax;
+  for(var y=yMax;y>=yMin;y--){
+    var of=document.createElement('option'); of.value=y; of.textContent=y; $('yfrom').appendChild(of);
+    var ot=document.createElement('option'); ot.value=y; ot.textContent=y; $('yto').appendChild(ot);
+  }
+  $('yfrom').value=yMin; $('yto').value=yMax;
+  $('yfrom').onchange=function(e){fYFrom=parseInt(e.target.value,10); if(fYFrom>fYTo){fYTo=fYFrom;$('yto').value=fYTo;} buildMarkers();};
+  $('yto').onchange=function(e){fYTo=parseInt(e.target.value,10); if(fYTo<fYFrom){fYFrom=fYTo;$('yfrom').value=fYFrom;} buildMarkers();};
   if(!ALL.length){ $('list').innerHTML='<p class="empty">The map data is still building. Check back shortly.</p>'; return; }
   buildMarkers();
 }).catch(function(){ $('list').innerHTML='<p class="empty">The map is temporarily unavailable.</p>'; });

← 10ac233d harden(deals/closings): Cody gate — word-boundary match for  ·  back to Rentv  ·  PR intel: Gmail correspondence sync + per-contact timeline 0884d55a →