Skip to content

Commit

Permalink
Citation + Case Links (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdellabitta authored Feb 5, 2024
1 parent dcb3778 commit 3df1a9c
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 22 deletions.
116 changes: 104 additions & 12 deletions src/components/cap-case.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { LitElement, html, css, unsafeHTML, nothing } from "../lib/lit.js";

import { fetchCaselawBody, fetchCaseMetadata } from "../lib/data.js";
import {
fetchCaselawBody,
fetchCaseMetadata,
fetchCasesList,
} from "../lib/data.js";

export default class CapCase extends LitElement {
static properties = {
Expand Down Expand Up @@ -411,6 +415,102 @@ export default class CapCase extends LitElement {
}
}

removeLink = (a) => {
a.replaceWith(a.innerHTML);
};

doNothing = () => {};

rewriteLinks = () => {
this.shadowRoot.querySelectorAll("a").forEach((a) => {
const oldLink = a.getAttribute("href");
// skip links without hrefs or that point back at the same page
if (!oldLink || oldLink.startsWith("#")) {
return;
}
const oldUrl = new URL(oldLink);
if (oldUrl.hostname === "cite.case.law") {
const pathComponents = oldUrl.pathname
.split("/")
// remove empty strings. Deals with paths that start
// or end with / and double slashes
.filter((x) => x !== "");
if (pathComponents.length === 3) {
/*
Case: /reporter/volume/page
E.g.: https://cite.case.law/ill-app-3d/16/850/
This represents a citation to a particular page
where only one case starts.
*/
const [reporter, volume, page] = pathComponents;
//http://localhost:5501/caselaw/?reporter=ark-app&volume=12&case=0028
const newUrl = new URL(
`/caselaw/?reporter=${reporter}&volume=${volume}&case=${page.padStart(4, "0")}-01`,
window.location,
);
a.setAttribute("href", newUrl);
return;
} else if (pathComponents.length === 4) {
/*
Case: /reporter/volume/page/caseId
E.g.: https://cite.case.law/mass/400/1006/880059/
This represents a citation to a particular page
where more than one case begins, so an
additional disambiguating suffix is added to
the URL. We need to translate that to the ordinal
number of the case on the page.
*/
const [reporter, volume, page, caseId] = pathComponents;

// First we need to load CasesMetadata for the cited case
new Promise((resolve, reject) => {
fetchCasesList(reporter, volume, (data) => {
try {
resolve(data);
} catch (e) {
reject(e);
}
});
}).then(
(casesList) => {
// Find the one with the correct case id
const citedCase = casesList.find(
(x) => x.id.toString() === caseId,
);

// construct the proper link to the case
const newUrl = new URL(
`/caselaw/?reporter=${reporter}&volume=${volume}&case=${page.padStart(4, "0")}-${citedCase.ordinal.toString().padStart(2, "0")}`,
window.location,
);

///set the href of the link to the new url
a.setAttribute("href", newUrl);
},
(error) => {
// Got an error looking up the CasesMetadata. Remove the link because we can't resolve it
this.removeLink(a);
return;
},
);
return;
} else if (oldUrl.searchParams.has("q")) {
/*
Case: https://cite.case.law/citations/?q=42%20U.S.C.%20%C2%A7%201983
This represents a link to a statute we
don't actually have the copy for, so
instead, we do a search on other cases
that cite the same statute. We'll remove
this.
*/
this.removeLink(a);
return;
}
}
// If we're here, we don't know what this url is, so leave it be.
});
};

render() {
/*
This render method uses requestAnimationFrame to alter the links in
Expand All @@ -420,19 +520,11 @@ export default class CapCase extends LitElement {
*/

// Skip the first frame which is the shadow DOM render
const doNothing = () => {};
window.requestAnimationFrame(this.doNothing);
// Rewrite the links on the second frame
const rewriteLinks = () => {
this.shadowRoot.querySelectorAll("a").forEach((a) => {
const oldLink = a.getAttribute("href");
//todo we need to fix this when ENG-523 happens
// (and we should make sure we don't break footnotes when we do)
a.href = oldLink + "#todo";
});
};
window.requestAnimationFrame(doNothing);
window.requestAnimationFrame(rewriteLinks);
window.document.title = `${this.createCaseHeaderHeader(this.caseMetadata)} | Caselaw Access Project`;
window.requestAnimationFrame(this.rewriteLinks);

return html`
<div class="case-container">
<div class="case-header">
Expand Down
6 changes: 4 additions & 2 deletions src/components/cap-volume.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ export default class CapVolume extends LitElement {
}

render() {
//todo this will need to be updated to deal with multiple cases on the same page
window.document.title = `Volume: ${this.reporterData.short_name} volume ${this.volume} | Caselaw Access Project`;
return html`
<cap-caselaw-layout>
Expand All @@ -128,7 +127,10 @@ export default class CapVolume extends LitElement {
html`<li>
<a
href="/caselaw/?reporter=${this.reporter}&volume=${this
.volume}&case=${String(c.first_page).padStart(4, "0")}"
.volume}&case=${String(c.first_page).padStart(
4,
"0",
)}-${String(c.ordinal).padStart(2, "0")}"
>
${c.name_abbreviation},
${c.citations.filter((c) => c.type == "official")[0].cite}
Expand Down
31 changes: 23 additions & 8 deletions src/lib/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,26 @@ export const fetchVolumeData = async (reporter, volume, callback) => {

export const fetchCasesList = async (reporter, volume, callback) => {
const url = `${window.BUCKET_ROOT}/${reporter}/${volume}/CasesMetadata.json`;
callback(await fetchJson(url));
const rawJson = await fetchJson(url);

// This sets the ordinal property on each case to the order in which it appears on the page.
// Usually 1 because there's only one case starting on a page.
const combined = new Map();
rawJson.forEach((element) => {
if (combined.has(element.first_page)) {
combined.get(element.first_page).push(element);
} else {
combined.set(element.first_page, [element]);
}
});
for (const key of combined.keys()) {
let index = 0;
for (const element of combined.get(key)) {
index += 1;
element.ordinal = index;
}
}
callback(rawJson);
};

export const fetchCaselawBody = async (
Expand All @@ -39,9 +58,7 @@ export const fetchCaselawBody = async (
caseName,
callback,
) => {
// TODO this is a hack to get around the fact that we don't have the case ordinal yet.
// See: ENG-522, ENG-523, ENG-533, and ENG-558
const url = `${window.BUCKET_ROOT}/${reporter}/${volume}/html/${caseName}-01.html`;
const url = `${window.BUCKET_ROOT}/${reporter}/${volume}/html/${caseName}.html`;
const response = await fetch(url);
callback(await response.text());
};
Expand All @@ -52,10 +69,8 @@ export const fetchCaseMetadata = async (
caseName,
callback,
) => {
// TODO this is a hack to get around the fact that we don't have the case ordinal yet.
// See: ENG-522, ENG-523, ENG-533, and ENG-558
const url = `${window.BUCKET_ROOT}/${reporter}/${volume}/cases/${caseName}-01.json`;
callback(await fetchJson(url));
const url = `${window.BUCKET_ROOT}/${reporter}/${volume}/cases/${caseName}.json`;
callback(await fetchJson(url)); //here return {} if it didn't fetch
};

export const fetchMapData = async (callback) => {
Expand Down

0 comments on commit 3df1a9c

Please sign in to comment.