diff --git a/explorer.qmd b/explorer.qmd index fcd15ef..62571e3 100644 --- a/explorer.qmd +++ b/explorer.qmd @@ -540,6 +540,26 @@ format: white-space: nowrap; } .samples-table tr:last-child td { border-bottom: 0; } + /* #323: PID column — pids are long (ark:/28722/…); keep the column + compact with ellipsis, full pid available on hover (title attr) and + always complete in the CSV export. */ + .samples-table td.pid-cell { + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: 11px; + color: #555; + } + /* #323: Source URL column — dedicated external link (see activateRow's + anchor guard: clicking it must not also select/fly the row). */ + .samples-table a.row-source-link { + color: #1565c0; + white-space: nowrap; + text-decoration: none; + } + .samples-table a.row-source-link:hover { text-decoration: underline; } .table-badge { color: white; padding: 2px 7px; @@ -2654,6 +2674,21 @@ tableView = { const labelHtml = `${safeLabel}`; const pidAttr = escapeHtml(r.pid || ''); const selectedClass = (r.pid && r.pid === selectedPid) ? ' class="selected"' : ''; + // #323: PID column (Andrea) — pids are long (ark:/28722/…), so + // the cell ellipsizes via CSS with the full pid in title/hover. + // Source URL column: an explicit external link to the sample's + // landing page at its source repository. This does NOT reopen + // #226 (which removed the *label* cell's href because click- + // anywhere = open card): here the external link is its own + // dedicated, honestly-labeled cell; activateRow ignores clicks + // that originate inside an so the row doesn't also fly. + const rowSrcUrl = sourceUrl(r.pid); + // Row-specific aria-label (Codex review): screen-reader users + // tabbing the column hear WHICH record each identical + // "record ↗" link opens. + const srcUrlHtml = rowSrcUrl + ? `record ↗` + : ''; // #311: material/context/object_type are URIs (from facets_url, // joined in loadPage()); resolve to human labels the same way // the facet tree and search results already do. context is @@ -2666,6 +2701,7 @@ tableView = { return ` ${tableSourceBadge(r.source)} ${labelHtml} + ${pidAttr} ${escapeHtml(place)} ${escapeHtml(r.result_time || '')} ${uriLabel(r.material)} @@ -2673,11 +2709,12 @@ tableView = { ${uriLabel(r.context)} ${escapeHtml(lat)} ${escapeHtml(lng)} + ${srcUrlHtml} `; }).join(''); tableEl.innerHTML = `
- + ${body}
SourceLabelPlaceDateMaterialObject typeSampled featureLatLon
SourceLabelPIDPlaceDateMaterialObject typeSampled featureLatLonSource URL
`; @@ -2695,6 +2732,10 @@ tableView = { // #226: there is no longer an in the row, so // the activation is uniform across surfaces. const activateRow = async (e) => { + // #323: a click on the Source URL (or any future in-row + // anchor) means "open the external record", not "select this + // row" — let the browser handle the link alone. + if (e && e.target && e.target.closest && e.target.closest('a')) return; const pid = tr.dataset.pid; const sample = pid ? pageRowsByPid.get(pid) : null; if (!sample || sample.latitude == null || sample.longitude == null) return; @@ -2998,7 +3039,10 @@ tableView = { // (same "honesty" convention as the rest of this table) rather than // silently truncating. const CSV_ROW_CAP = 50000; - const CSV_HEADERS = ['pid', 'source', 'label', 'place', 'date', 'material', 'object_type', 'sampled_feature', 'latitude', 'longitude']; + // #323: source_url appended LAST so existing consumers of the #312 column + // order keep working; it's the same n2t.net resolver link the table's + // "Source URL" column shows. + const CSV_HEADERS = ['pid', 'source', 'label', 'place', 'date', 'material', 'object_type', 'sampled_feature', 'latitude', 'longitude', 'source_url']; function csvField(v) { let s = v == null ? '' : String(v); @@ -3023,7 +3067,7 @@ tableView = { : ''; return [r.pid, r.source, r.label, place, r.result_time, labelFor(r.material), labelFor(r.object_type), labelFor(r.context), - r.latitude, r.longitude].map(csvField).join(','); + r.latitude, r.longitude, sourceUrl(r.pid) || ''].map(csvField).join(','); } let downloadInFlight = false;