274-transect: copy object name on click; stop clobbering text selection
Row clicks called draw(), which rebuilt the whole tbody — so any attempt to drag-select text in the roster was wiped on mousedown. Selection was never blocked, just destroyed. Row clicks now call select(), which swaps the highlight class and repaints the SVG marks in place. Object names sit in a bare button with a dotted underline and cursor:copy; clicking copies the name and flashes "copied" beside it. Propagation is stopped so copying and row-selecting stay independent. Clipboard uses navigator.clipboard with a hidden-textarea fallback, since the vendored copy opens over file:// where the async API is often absent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6MpcBisZYhX45oDGRRJoz
This commit is contained in:
+59
-11
@@ -83,6 +83,15 @@ footer{margin-top:38px;padding-top:16px;border-top:1px solid var(--rule);
|
||||
}
|
||||
|
||||
.frow.oaza .chip{font-size:11px}
|
||||
button.copy{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;
|
||||
cursor:copy;text-align:left;border-bottom:1px dotted var(--rule)}
|
||||
button.copy:hover{border-bottom-color:var(--ink-3)}
|
||||
button.copy:focus-visible{outline:2px solid var(--ochre);outline-offset:2px}
|
||||
button.copy.copied{background:color-mix(in srgb,var(--ochre) 22%,transparent);
|
||||
border-bottom-color:transparent}
|
||||
button.copy.copied::after{content:' copied';font-size:10px;letter-spacing:.08em;
|
||||
color:var(--ink-3);text-transform:uppercase}
|
||||
.tblwrap{user-select:text}
|
||||
.chip.quick{font-size:10px;padding:3px 8px;letter-spacing:.08em;text-transform:uppercase;
|
||||
color:var(--ink-3);border-style:dashed;margin-right:2px}
|
||||
.chip.quick:hover{color:var(--ink);border-style:solid}
|
||||
@@ -126,8 +135,8 @@ north to south, so the road reads nearly straight apart from the swing south thr
|
||||
|
||||
<h2>Roster</h2>
|
||||
<div class="tblwrap"><table id="tbl">
|
||||
<thead><tr><th style="text-align:right">km</th><th>Name</th><th>Object</th><th>Kana</th><th>Romaji</th>
|
||||
<th>Kind</th><th>大字</th><th style="text-align:right">Built</th><th>Grade</th></tr></thead>
|
||||
<thead><tr><th style="text-align:right">km</th><th>Object</th><th>Kana</th>
|
||||
<th>Kind</th><th style="text-align:right">Offset (m)</th><th>Address</th></tr></thead>
|
||||
<tbody id="tbody"></tbody>
|
||||
</table></div>
|
||||
|
||||
@@ -207,6 +216,15 @@ document.getElementById('legend').innerHTML=
|
||||
.map(function(g){return '<span><i style="background:'+FAM[g[0]]+'"></i>'+g[1]+'</span>'}).join('');
|
||||
|
||||
var NS='http://www.w3.org/2000/svg';
|
||||
var rowOf=null, markOf=new Map();
|
||||
function paintMarks(){
|
||||
markOf.forEach(function(m,k){
|
||||
var on=(k===sel);
|
||||
if(m.c){m.c.setAttribute('r',on?6:m.r0);}
|
||||
if(m.t){m.t.setAttribute('font-weight',on?'700':'400');}
|
||||
if(m.g){m.g.setAttribute('r',on?6:3);m.g.setAttribute('opacity',on?1:.85);}
|
||||
});
|
||||
}
|
||||
function el(n,a){var e=document.createElementNS(NS,n);for(var k in a)e.setAttribute(k,a[k]);return e}
|
||||
function draw(){
|
||||
var W=Math.max(2600,(K1-K0)*36),H=450,AX=272,PADL=54,PADR=54;
|
||||
@@ -227,6 +245,7 @@ function draw(){
|
||||
t.textContent=k;s.appendChild(t);
|
||||
}
|
||||
s.appendChild(el('line',{x1:PADL,y1:AX,x2:W-PADR,y2:AX,stroke:'var(--road)','stroke-width':2.5}));
|
||||
markOf=new Map();
|
||||
var vis=items.filter(function(o){return onK[o.kind]&&onO[o.oaza]});
|
||||
document.getElementById('count').innerHTML='showing <b>'+vis.length+'</b> of '+items.length+' entries';
|
||||
var lu=[],ld=[];
|
||||
@@ -242,7 +261,8 @@ function draw(){
|
||||
tx.textContent=o.obj;
|
||||
if(sel===o)tx.setAttribute('font-weight','700');
|
||||
tx.style.cursor='pointer';r.style.cursor='pointer';
|
||||
var pick=function(){sel=o;draw()};tx.onclick=pick;r.onclick=pick;
|
||||
var pick=function(){select(o)};tx.onclick=pick;r.onclick=pick;
|
||||
var e0=markOf.get(o)||{};e0.c=r;e0.t=tx;e0.r0=(up?4:3);markOf.set(o,e0);
|
||||
s.appendChild(r);s.appendChild(tx);
|
||||
var km=el('text',{x:px,y:up?y-13:y+16,fill:'var(--ink-3)','font-size':9.5,'text-anchor':'middle'});
|
||||
km.textContent=o.km.toFixed(2)+(o.name&&o.name!==o.obj?' \u00b7 '+o.name:'');
|
||||
@@ -271,23 +291,51 @@ function draw(){
|
||||
vis.forEach(function(o){
|
||||
var cir=el('circle',{cx:gx(o.lon),cy:gy(o.lat),r:(sel===o?6:3),fill:FAM[o._f],
|
||||
opacity:(sel===o?1:.85),class:'mark'});
|
||||
cir.style.cursor='pointer';cir.onclick=function(){sel=o;draw()};
|
||||
cir.style.cursor='pointer';cir.onclick=function(){select(o)};
|
||||
var e1=markOf.get(o)||{};e1.g=cir;markOf.set(o,e1);
|
||||
var t=el('title');t.textContent=o.obj+' \u00b7 '+o.km.toFixed(2)+' km \u00b7 '+o.oaza;cir.appendChild(t);
|
||||
g.appendChild(cir);
|
||||
});
|
||||
|
||||
var tb=document.getElementById('tbody');tb.innerHTML='';
|
||||
var tb=document.getElementById('tbody');tb.innerHTML='';rowOf=new Map();
|
||||
vis.forEach(function(o){
|
||||
var tr=document.createElement('tr');
|
||||
if(sel===o)tr.className='hit';
|
||||
tr.innerHTML='<td class="km">'+o.km.toFixed(2)+'</td><td class="jp">'+o.name+'</td>'+
|
||||
'<td class="jp" style="color:var(--ink-2)">'+o.obj+'</td><td class="jp" style="color:var(--ink-3)">'+(o.kana||'')+'</td>'+
|
||||
'<td class="kind">'+o.kind+'</td><td class="jp">'+o.oaza+'</td>'+
|
||||
'<td class="num">'+(o.y||'')+'</td><td class="kind">'+(o.g||'')+'</td>';
|
||||
tr.style.cursor='pointer';tr.onclick=function(){sel=o;draw()};
|
||||
tb.appendChild(tr);
|
||||
tr.innerHTML='<td class="km">'+o.km.toFixed(2)+'</td>'+
|
||||
'<td class="jp"><button type="button" class="copy" title="Copy name">'+o.obj+'</button></td>'+
|
||||
'<td class="jp" style="color:var(--ink-3)">'+(o.kana||'')+'</td>'+
|
||||
'<td class="kind">'+o.kind+'</td>'+
|
||||
'<td class="num">'+Math.round(o.off)+'</td>'+
|
||||
'<td class="jp" style="color:var(--ink-2)">'+(o.addr||'')+'</td>';
|
||||
tr.querySelector('.copy').onclick=function(e){e.stopPropagation();copyName(o,this)};
|
||||
tr.onclick=function(){select(o)};
|
||||
rowOf.set(o,tr);tb.appendChild(tr);
|
||||
});
|
||||
}
|
||||
|
||||
function select(o){
|
||||
sel=o;
|
||||
if(rowOf)rowOf.forEach(function(tr,k){tr.className=(k===o?'hit':'')});
|
||||
paintMarks();
|
||||
}
|
||||
|
||||
function copyName(o,btn){
|
||||
var t=o.obj, done=function(){
|
||||
btn.classList.add('copied');
|
||||
setTimeout(function(){btn.classList.remove('copied')},900);
|
||||
};
|
||||
if(navigator.clipboard&&navigator.clipboard.writeText){
|
||||
navigator.clipboard.writeText(t).then(done,function(){fallback(t,done)});
|
||||
} else fallback(t,done);
|
||||
}
|
||||
function fallback(t,done){
|
||||
var ta=document.createElement('textarea');
|
||||
ta.value=t;ta.setAttribute('readonly','');
|
||||
ta.style.position='fixed';ta.style.left='-9999px';
|
||||
document.body.appendChild(ta);ta.select();
|
||||
try{document.execCommand('copy');done()}catch(e){}
|
||||
document.body.removeChild(ta);
|
||||
}
|
||||
draw();
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user