← back to Rentv V1
fix(rentv-v1): repair search/feed article+post links, kill rentv.com deal hotlink, admin/desk bugs
95fdcd3408bc463326d81ad1066c6f76bd4ce0c2 · 2026-07-24 08:20:59 -0700 · Steve Abrams
- article.html/post.html: read id from ?id= (search results + RSS/JSON feeds) AND /news/:id|/post/:id path — search-linked stories/posts were 404-blank
- deals.html: deal cards linked out to rentv.com (hard-rule violation) → now open /news/:id in-app reader
- desk-admin.html: send sqft/asking_rate/term_months/lat/lng as numbers, not FormData strings
- versions/render.js: remove stray </a> in broadsheet template (malformed DOM)
- admin/render.js: add credentials:same-origin to the 5 gated admin fetches
- review.html: add missing .ham/.navlinks CSS — mobile nav was permanently open, hamburger inert
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M admin/desk-admin.htmlM public/admin/render.jsM public/article.htmlM public/deals.htmlM public/post.htmlM public/review.htmlM public/versions/render.js
Diff
commit 95fdcd3408bc463326d81ad1066c6f76bd4ce0c2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Jul 24 08:20:59 2026 -0700
fix(rentv-v1): repair search/feed article+post links, kill rentv.com deal hotlink, admin/desk bugs
- article.html/post.html: read id from ?id= (search results + RSS/JSON feeds) AND /news/:id|/post/:id path — search-linked stories/posts were 404-blank
- deals.html: deal cards linked out to rentv.com (hard-rule violation) → now open /news/:id in-app reader
- desk-admin.html: send sqft/asking_rate/term_months/lat/lng as numbers, not FormData strings
- versions/render.js: remove stray </a> in broadsheet template (malformed DOM)
- admin/render.js: add credentials:same-origin to the 5 gated admin fetches
- review.html: add missing .ham/.navlinks CSS — mobile nav was permanently open, hamburger inert
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
admin/desk-admin.html | 4 +++-
public/admin/render.js | 11 ++++++-----
public/article.html | 3 ++-
public/deals.html | 3 ++-
public/post.html | 3 ++-
public/review.html | 10 ++++++++++
public/versions/render.js | 2 +-
7 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/admin/desk-admin.html b/admin/desk-admin.html
index f987f7d..cdc2e92 100644
--- a/admin/desk-admin.html
+++ b/admin/desk-admin.html
@@ -105,7 +105,9 @@ async function load(){
}
$('f').onsubmit=async e=>{
e.preventDefault();const m=$('msg');m.className='msg';m.textContent='';
- const body={};new FormData(e.target).forEach((v,k)=>{if(String(v).trim()!=='')body[k]=v;});
+ // Numeric inputs must go up as numbers, not FormData strings, so the backend stores them cleanly.
+ const NUMK=['sqft','asking_rate','term_months','lat','lng'];
+ const body={};new FormData(e.target).forEach((v,k)=>{if(String(v).trim()!=='')body[k]=NUMK.includes(k)?Number(v):v;});
try{
const r=await fetch('/api/admin/sublease',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'same-origin',body:JSON.stringify(body)});
const j=await r.json();
diff --git a/public/admin/render.js b/public/admin/render.js
index bf206e2..7533226 100644
--- a/public/admin/render.js
+++ b/public/admin/render.js
@@ -77,12 +77,13 @@
document.getElementById('app').innerHTML = (T[ver] || T.classic)();
}
+ var opt = { credentials: 'same-origin' }; // keep Basic-Auth creds on the gated admin APIs
Promise.allSettled([
- fetch('/api/subscribers').then(function (r) { return r.json(); }),
- fetch('/api/news').then(function (r) { return r.json(); }),
- fetch('/api/videos').then(function (r) { return r.json(); }),
- fetch('/api/markets').then(function (r) { return r.json(); }),
- fetch('/api/ticker').then(function (r) { return r.json(); }),
+ fetch('/api/subscribers', opt).then(function (r) { return r.json(); }),
+ fetch('/api/news', opt).then(function (r) { return r.json(); }),
+ fetch('/api/videos', opt).then(function (r) { return r.json(); }),
+ fetch('/api/markets', opt).then(function (r) { return r.json(); }),
+ fetch('/api/ticker', opt).then(function (r) { return r.json(); }),
]).then(function (res) {
var g = function (i) { return res[i].status === 'fulfilled' ? res[i].value : {}; };
build({ subs: g(0), news: g(1), vids: g(2), mk: g(3), tk: g(4) });
diff --git a/public/article.html b/public/article.html
index e48d29a..5c10170 100644
--- a/public/article.html
+++ b/public/article.html
@@ -91,7 +91,8 @@
<script>
document.getElementById('today').textContent = new Date().toLocaleDateString(undefined,{weekday:'long',year:'numeric',month:'long',day:'numeric'});
const esc=s=>(s||'').replace(/[&<>"]/g,c=>({'&':'&','<':'<','>':'>','"':'"'}[c]));
-const id=(location.pathname.split('/').filter(Boolean).pop()||'').replace(/[^0-9]/g,'');
+// Accept both link forms: /news/:id (homepage) AND /article.html?id= (search results + RSS/JSON feeds).
+const id=((new URLSearchParams(location.search).get('id'))||location.pathname.split('/').filter(Boolean).pop()||'').replace(/[^0-9]/g,'');
// Generic titles the reader proxy returns when rentv.com doesn't server-render the story.
const GENERIC=/^RENTV\.com\b|commercial real estate news and property/i;
async function load(){
diff --git a/public/deals.html b/public/deals.html
index b1369fa..66c8ac9 100644
--- a/public/deals.html
+++ b/public/deals.html
@@ -99,7 +99,8 @@ function render(){
$('#grid').innerHTML=rows.length?rows.map(d=>{
const loc=[d.city,d.state].filter(Boolean).join(', ');
const ph=d.image?`background-image:url('${esc(d.image)}')`:'';
- return `<a class="card" href="${esc(d.url)}" target="_blank" rel="noopener">
+ // HARD RULE: never link out to rentv.com. Open the story in OUR in-app reader (/news/:id → article.html).
+ return `<a class="card" href="${d.id?('/news/'+encodeURIComponent(d.id)):'/deals'}">
<div class="ph" style="${ph}">
<div class="badges"><span class="badge txn">${esc(d.txn_type)}</span><span class="badge">${esc(d.property_type)}</span></div>
${d.amount_label?`<span class="amt">${esc(d.amount_label)}</span>`:''}
diff --git a/public/post.html b/public/post.html
index 2c4ee23..0b37837 100644
--- a/public/post.html
+++ b/public/post.html
@@ -25,7 +25,8 @@ footer{border-top:1px solid var(--line);color:var(--sub);font-size:12px;padding:
<footer><div class="wrap">RENTV.com · Original reporting — <a href="/blog" style="color:var(--red)">more RENTV Originals</a></div></footer>
<script>
var esc=function(s){return (s||'').replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c];});};
-var id=location.pathname.split('/').filter(Boolean).pop();
+// Accept both /post/:id (blog index) AND /post.html?id= (global search results).
+var id=(new URLSearchParams(location.search).get('id'))||location.pathname.split('/').filter(Boolean).pop();
fetch('/api/posts/'+encodeURIComponent(id)).then(function(r){return r.ok?r.json():null;}).then(function(p){
var a=document.getElementById('art');
if(!p){a.innerHTML='<p class="err">This story isn\'t available. <a href="/blog">← Back to the blog</a></p>';return;}
diff --git a/public/review.html b/public/review.html
index 2a4c531..8208920 100644
--- a/public/review.html
+++ b/public/review.html
@@ -77,6 +77,16 @@
footer .fine{border-top:1px solid #2a2f34;margin-top:26px;padding-top:16px;font-size:12px;color:#7c848b}
@media(max-width:980px){.cards{grid-template-columns:1fr 1fr 1fr}}
@media(max-width:720px){.cards{grid-template-columns:1fr 1fr}.rhero h1{font-size:26px}}
+ /* mobile hamburger nav — the .ham/.navlinks markup + JS toggle exist but the CSS was missing (parity with article.html) */
+ .ham{display:none;background:none;border:0;font-size:24px;line-height:1;color:var(--ink);cursor:pointer;padding:8px 12px 8px 0}
+ @media(max-width:720px){
+ nav .wrap{overflow:visible}
+ .ham{display:block;margin-left:auto}
+ .navlinks{display:none;position:absolute;top:100%;left:0;right:0;background:#fff;flex-direction:column;align-items:stretch;border-bottom:2px solid var(--ink);box-shadow:0 10px 24px rgba(0,0,0,.14);z-index:30;max-height:78vh;overflow-y:auto}
+ .navlinks.open{display:flex}
+ .navlinks a{padding:15px 20px;border-bottom:1px solid var(--line);border-left:4px solid transparent;white-space:normal}
+ .navlinks a:hover{color:var(--red);border-left-color:var(--red)}
+ }
</style>
</head>
<body>
diff --git a/public/versions/render.js b/public/versions/render.js
index b3188aa..19a8699 100644
--- a/public/versions/render.js
+++ b/public/versions/render.js
@@ -19,7 +19,7 @@
// 2. BROADSHEET — dense two-column serif
broadsheet: function (a) {
css('.bs{column-count:2;column-gap:40px}.bs .it{break-inside:avoid;padding:14px 0;border-bottom:1px solid var(--ln)}.bs h3{font-size:21px;margin-bottom:4px}.bs .imgph{aspect-ratio:16/9;margin-bottom:8px}.bs .it:first-child{column-span:all;text-align:center;border-bottom:3px double var(--ink);padding-bottom:20px}.bs .it:first-child h3{font-size:36px}@media(max-width:720px){.bs{column-count:1}}');
- return '<div class="bs">' + a.slice(0, 16).map(function (x, i) { return '<div class="it"><span class="chip">' + esc(x.cat) + '</span><a href="' + href(x) + '"><h3>' + esc(x.title) + '</h3></a>' + (i < 4 ? img(x) : '') + '<div class="byl">RENTV Staff</div></a></div>'; }).join('') + '</div>';
+ return '<div class="bs">' + a.slice(0, 16).map(function (x, i) { return '<div class="it"><span class="chip">' + esc(x.cat) + '</span><a href="' + href(x) + '"><h3>' + esc(x.title) + '</h3></a>' + (i < 4 ? img(x) : '') + '<div class="byl">RENTV Staff</div></div>'; }).join('') + '</div>';
},
// 3. TERMINAL — dark data rows
terminal: function (a) {
← 73b5802 auto-save: 2026-07-24T07:56:29 (3 files) — data/markets.json
·
back to Rentv V1
·
auto-save: 2026-07-24T08:26:42 (3 files) — data/markets.json 9ebf0cf →