Switch an item between its HTML and its Markdown (#285)
A feed that sends <source:markdown> beside its HTML (Scripting News) has its Markdown kept in entries.markdown, added to existing databases by an ALTER. A stored item gets it when a scan finds it told differently, the Markdown counting as a change, the way corrections arrive (#141). The API sends it as written and made HTML, cleaned by ammonia like the description. The item's page has a choice between its meta line and its buttons: HTML, Markdown or Markdown source, remembered in the browser. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -376,6 +376,12 @@ function showDetail(e: Entry|null){
|
||||
box.innerHTML=detailHtml(e);
|
||||
if(files) files.innerHTML=narrow?'':`<div class="fhd">Files</div>${encs}`;
|
||||
$<HTMLButtonElement>('#dback').onclick=()=>showDetail(null);
|
||||
const view=box.querySelector<HTMLSelectElement>('.tview');
|
||||
if(view) view.onchange=()=>{
|
||||
textView=view.value;
|
||||
try{ localStorage.setItem('ipx.textview',textView); }catch{}
|
||||
box.querySelector('.dbody')!.innerHTML=textOf(e);
|
||||
};
|
||||
for(const root of [box,files]) if(root) $$('button[data-a]',root).forEach(b=>
|
||||
b.onclick=()=>epAction(b.dataset.a!,e,null,b.dataset.enc?Number(b.dataset.enc):undefined));
|
||||
syncPlayButtons();
|
||||
@@ -401,6 +407,8 @@ function detailHtml(e: Entry){
|
||||
[f&&esc(f.title||f.id), num, dateOf(e.published), e.duration&&clock(e.duration),
|
||||
e.enclosures.some(x=>x.deadair_pending)&&DEAD_PENDING]
|
||||
.filter(Boolean).map(s=>`<span>${s}</span>`).join('<span class="dot"></span>')}
|
||||
${e.markdown?`<select class="tview" aria-label="Show the text as">${TEXT_VIEWS.map(([v,label])=>
|
||||
`<option value="${v}"${v===textView?' selected':''}>${label}</option>`).join('')}</select>`:''}
|
||||
<span class="dacts"><button class="btn ico" data-a="read" title="Mark ${e.read?'unread':'read'}"
|
||||
aria-label="Mark ${e.read?'unread':'read'}" aria-pressed="${!!e.read}">${e.read?ICON.check:ICON.unread}</button>
|
||||
<button class="btn ico" data-a="flag" title="${e.flagged?'Pinned: never deleted. Unpin':'Pin, so it is never deleted'}"
|
||||
@@ -410,7 +418,18 @@ function detailHtml(e: Entry){
|
||||
<button class="btn ico" data-a="share" title="Share" aria-label="Share">${ICON.share}</button>`:''}</span>
|
||||
</div>
|
||||
${narrow?encs:''}
|
||||
<div class="dbody">${(e.description&&e.description.trim())||'<em>No show notes.</em>'}</div>`;
|
||||
<div class="dbody">${textOf(e)}</div>`;
|
||||
}
|
||||
|
||||
/// How an item whose feed sends Markdown beside its HTML is shown, kept from one item to the
|
||||
/// next (#285): the publisher's HTML, the Markdown made HTML, or the Markdown as written.
|
||||
const TEXT_VIEWS=[['html','HTML'],['markdown','Markdown'],['source','Markdown source']];
|
||||
let textView=(()=>{ try{ return localStorage.getItem('ipx.textview'); }catch{ return null; } })()||'html';
|
||||
function textOf(e: Entry){
|
||||
// Both cleaned server-side with ammonia, as the description is.
|
||||
if(e.markdown&&textView==='markdown'&&e.markdown_html) return e.markdown_html;
|
||||
if(e.markdown&&textView==='source') return `<pre class="mdsrc">${esc(e.markdown)}</pre>`;
|
||||
return (e.description&&e.description.trim())||'<em>No show notes.</em>';
|
||||
}
|
||||
|
||||
/// One enclosure: a play button when the file is here, otherwise what it is and a way to get it.
|
||||
|
||||
Reference in New Issue
Block a user