diff options
| author | aura <nw@moneybot.cc> | 2026-02-16 22:43:04 +0100 |
|---|---|---|
| committer | aura <nw@moneybot.cc> | 2026-02-16 22:43:04 +0100 |
| commit | 2e8bcce422176922478c67118cb23d510d7784cf (patch) | |
| tree | 1310ed1af57edb8e102ff85a6bbe790b91724069 /web/cgit-extra.html | |
| parent | 3c89b7bb5b2df92b9d61d5c2c8fbeefcfef7f256 (diff) | |
git files
Diffstat (limited to 'web/cgit-extra.html')
| -rw-r--r-- | web/cgit-extra.html | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/web/cgit-extra.html b/web/cgit-extra.html new file mode 100644 index 0000000..7f0d9f9 --- /dev/null +++ b/web/cgit-extra.html @@ -0,0 +1,227 @@ +<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js" async></script> +<script> +const VROOT = "/"; + +function repoPathFromLink( a ) { + const href = new URL( a.getAttribute( "href" ), location.href ); + let p = href.pathname; + if( !p.startsWith( VROOT ) ) return null; + p = p.slice( VROOT.length ); + p = p.replace( /\/+$/, "" ); + if( !p ) return null; + return p; +} + +function branchFromForm() { + const formWrap = document.querySelector( ".form" ); + const form = formWrap.querySelector( "form" ); + + const branchEl = form.querySelector( "select" ); + if( !branchEl ) + return ""; + + const branch = branchEl.value; + if( !branch ) + return ""; + + return branch; +} + +async function getFile( repo, branch, file ) { + try { + const res = await fetch( `https://${location.host}/${repo}/plain/${file}` ); + if( !res.ok ) + return null; + return await res.text(); + } catch( e ) { + return null; + } +} + +function isWhiteChar( char ) { + return char === " " || char === "\t" || char === "\n" || char === "\r"; +} + +function removeTrailingWhiteSpace( text ) { + while( text.length > 1 + && isWhiteChar( text[text.length - 1] ) + && isWhiteChar( text[text.length - 2] ) + ) { + text = text.slice( 0, -1 ); + } + return text; +} + +async function getReadmeFile( repo, branch ) { + let file = await getFile( repo, branch, "README.md" ); + if( file ) + return { file: removeTrailingWhiteSpace( file ), isMd: true }; + + file = await getFile( repo, branch, "README" ); + if( file ) + return { file: removeTrailingWhiteSpace( file ), isMd: false }; + + return null; +} + +function isIndex( repo ) { + let path = location.pathname; + return path.replaceAll( "/", "" ) === repo; +} +function parseLink( text, start ) { + let isImg = 0; + + const open = text.indexOf( "[", start ); + if( open === -1 ) return null; + const close = text.indexOf( "]", open ); + if( close === -1 ) return null; + + const lopen = text.indexOf( "(", close ); + if( lopen === -1 ) return null; + const lclose = text.indexOf( ")", lopen ); + if( lclose === -1 ) return null; + + const title = text.substring( open + 1, close ); + const link = text.substring( lopen + 1, lclose ); + + if( open > 0 && text[open-1] == "!" ) isImg = 1; + return { title, link, start: open - (isImg?1:0), end: lclose + 1, img: isImg }; +} + +function parseLinks( text ) { + let start = 0; + const links = []; + + while( true ) { + const res = parseLink( text, start ); + if( !res ) + break; + + links.push( res ); + start = res.end + 1; + } + + return links; +} + +function replaceLinks( text, links ) { + let offset = 0; + for( let link of links ) { + const start = link.start + offset; + const end = link.end + offset; + + const textFirst = text.slice( 0, start ); + const textSecond = text.slice( end ); + + let textMid = ""; + if( link.img ) { + textMid = `<img src="${link.link}" alt="${link.title}" />`; + } else { + textMid = `<a href="${link.link}">${link.title}</a>`; + } + + text = textFirst + textMid + textSecond; + offset += textMid.length - ( link.end - link.start ); + } + + return text; +} + +function replaceCodeTicks( text ) { + let inBlock = 0; + let tick = text.indexOf( "```" ); + while( tick != -1 ) { + if( inBlock == 0 ) { + let second = text.slice( tick + 3 ); + while( isWhiteChar( second[0] ) ) + second = second.slice( 1 ); + text = text.slice( 0, tick ) + "<code>" + second; + tick = text.indexOf( "```", tick + 3 ); + } else { + let second = text.slice( tick + 3 ); + while( second.length > 1 && isWhiteChar( second[0] ) && isWhiteChar( second[1] ) ) + second = second.slice( 1 ); + text = text.slice( 0, tick ) + "</code>" + second; + tick = text.indexOf( "```", tick + 3 ); + } + inBlock = !inBlock; + } + + return text; +} + +function runHighlight() { + if( hljs === undefined || !hljs ) + return setTimeout( runHighlight, 200 ); + + hljs.highlightAll(); +} + + +function createReadme( text, isMd ) { + const tr = document.createElement( "tr" ); + const td = document.createElement( "td" ); + const pre = document.createElement( "pre" ); + tr.appendChild( td ); + td.appendChild( pre ); + td.setAttribute( "colspan", "4" ); + if( !isMd ) + pre.innerHTML = text; + else { + const noTicks = replaceCodeTicks( text ); + const links = parseLinks( noTicks ); + pre.innerHTML = replaceLinks( noTicks, links ); + } + + pre.style.whiteSpace = "pre-wrap"; + pre.style.fontFamily = "JPN12"; + pre.style.padding = 0; + pre.style.marginTop = "0px"; + pre.style.marginBottom = "0px"; + tr.classList.add( "nohover" ); + tr.style.backgroundColor = "#808080" + const list = document.querySelector( ".list" ); + const tbody = list.querySelector( "tbody" ); + tbody.insertBefore( tr, tbody.children[3] ); + + const th = document.createElement( "th" ); + th.classList.add( "left" ); + th.setAttribute( "colspan", "4" ); + th.innerHTML = "Readme"; + tbody.insertBefore( th, tr ); + + setTimeout( runHighlight ); +} + +function isCodeView() { + return location.pathname.includes( "/tree/src" ); +} + +const main = async () => { + if( isCodeView() ) { + return setTimeout( runHighlight ); + } + + const mainEl = document.querySelector( ".main" ); + if( !mainEl ) + return; + + const repoEl = mainEl.querySelectorAll( "a" )[1]; + if( !repoEl ) + return; + + const repo = repoPathFromLink( repoEl ); + if( !repo ) + return; + + if( !isIndex( repo ) ) + return; + + const branch = branchFromForm(); + const { file, isMd } = await getReadmeFile( repo, branch ); + createReadme( file, isMd ); +} + +setTimeout( main ); +</script> +<link rel="stylesheet" href="https://networkheaven.net/static/highlight.css" type="text/css" /> |
