diff --git a/src/stat/Stat.tsx b/src/stat/Stat.tsx index 8c1b382..697276b 100644 --- a/src/stat/Stat.tsx +++ b/src/stat/Stat.tsx @@ -8,7 +8,9 @@ export default function Stat({ org, repo, branch }: Props) { return ( { return new Promise((resolve) => { - const root = document.evaluate( - '//h2[text()="About" and not(@class="heading-element")]', - document, - null, - XPathResult.FIRST_ORDERED_NODE_TYPE, - null, - ).singleNodeValue?.parentElement - - const repoVisibility = document.evaluate( - '//*[@id="repo-title-component"]/span[2]', - document, - null, - XPathResult.FIRST_ORDERED_NODE_TYPE, - null, - ).singleNodeValue - - if (root && !isInjected(root)) { - resolve([root, repoVisibility?.textContent !== "Private"]) + let observer: MutationObserver | undefined + + const tryLocate = () => { + const root = document.evaluate( + '//h2[normalize-space(.)="About" and not(@class="heading-element")]', + document, + null, + XPathResult.FIRST_ORDERED_NODE_TYPE, + null, + ).singleNodeValue?.parentElement + + if (!root) { + return false + } + + observer?.disconnect() + resolve([root, isPublicRepository()]) + return true + } + + if (!tryLocate()) { + observer = new MutationObserver(tryLocate) + observer.observe(document.documentElement, { childList: true, subtree: true }) } }) } export function injectStat(root: Element, stat: JSX.Element) { - const div = document.createElement("div") - div.className = "mt-2" - div.id = "github-loc" - - if (root.lastElementChild?.firstElementChild?.textContent?.includes("Report")) { - root.insertBefore(div, root.lastElementChild) - } else { - root.appendChild(div) + const existing = root.querySelector("#github-loc") + const div = existing ?? document.createElement("div") + + if (!existing) { + div.className = "mt-2" + div.id = "github-loc" + + if (root.lastElementChild?.firstElementChild?.textContent?.includes("Report")) { + root.insertBefore(div, root.lastElementChild) + } else { + root.appendChild(div) + } } render(stat, div) diff --git a/src/stat/loader.ts b/src/stat/loader.ts index 3e27bce..08e97f6 100644 --- a/src/stat/loader.ts +++ b/src/stat/loader.ts @@ -41,7 +41,8 @@ export function loadLoc(org: string, repo: string, branch: string): Promise { - let url = `https://ghloc-api.vercel.app/${org}/${repo}/${branch}` + const branchPath = branch ? `/${branch}` : "" + let url = `https://ghloc-api.vercel.app/${org}/${repo}${branchPath}` const accessToken = await chrome.storage.sync.get("accessToken") const ignoredFiles = await chrome.storage.sync.get("ignoredFiles") diff --git a/src/stat/util.ts b/src/stat/util.ts index 70204f7..930404c 100644 --- a/src/stat/util.ts +++ b/src/stat/util.ts @@ -5,23 +5,22 @@ export function now(): number { return Math.floor(Date.now() / 1000) } +function getBranchFromSelector() { + const branchSelector = + document.querySelector("#ref-picker-repos-header-ref-selector") ?? + document.querySelector('[data-testid="anchor-button"][aria-label$=" branch"]') + const ariaLabel = branchSelector?.getAttribute("aria-label") + + return ariaLabel?.replace(/\s+branch$/i, "").trim() || branchSelector?.textContent?.trim() +} + export function getTarget() { const path = window.location.pathname.split("/") - let branch: string | undefined = path.slice(4).join("/") - - if (!branch) { - branch = document - .evaluate( - '//*[@id="ref-picker-repos-header-ref-selector"]/span/span[1]/div/div[2]/span', - document, - null, - XPathResult.FIRST_ORDERED_NODE_TYPE, - null, - ) - .singleNodeValue?.textContent?.trim() - } + const branchFromPath = + path[3] === "tree" || path[3] === "blob" ? path.slice(4).join("/") : undefined + const branch = branchFromPath || getBranchFromSelector() || "" - return [path[1], path[2], branch || "main"] + return [path[1], path[2], branch] } export function getFilter(): Promise {