pack/static/index.html

606 lines
28 KiB
HTML

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Pack</title>
<link rel="icon" href="assets/favicon.ico?v=2">
<link rel="stylesheet" href="assets/index.css">
<link href="https://fonts.googleapis.com/css?family=Quicksand:300,400" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<div id="themeSwitchContainer">
<input type="checkbox" id="themeSwitch">
<span></span><span></span><span></span>
</div>
<div id="package">
<img src="assets/fragile.svg">
<img src="assets/keep_dry.svg">
<img src="assets/recycle.svg">
<img src="assets/qr_code.svg">
</div><svg id="packageTape" viewbox="0 0 100 10">
<rect width="100" height="0.3" x="0" y="4.85" style="fill:#483320;fill-opacity:0.8" />
<rect width="100" height="10" x="0" y="0" style="fill:#111;fill-opacity:0.8" />
<polygon points="21,0.0 20,0.625 21,1.25 20,1.875 21,2.5 20,3.125 21,3.75 20,4.375 21,5.0 20,5.625 21,6.25 20,6.875 21,7.5 20,8.125 21,8.75 20,9.375 21,10.0 100,10 100,0" style="fill:#111;fill-opacity:0.5"/>
<text>
<textPath href="#packTape0">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape1">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape2">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape3">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape4">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape5">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape6">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape7">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape8">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape9">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape10">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape11">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape12">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape13">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape14">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape15">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape16">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape17">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape18">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape19">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape20">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape21">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape22">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape23">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape24">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape25">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape26">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape27">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape28">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape29">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape30">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape31">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape32">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape33">PACK.PACK.PACK.PACK.</textPath>
<textPath href="#packTape34">PACK.PACK.PACK.PACK.</textPath>
</text>
<path id="packTape0" fill="none" stroke="none" d="M-3.00 -0.00 l6 20"/>
<path id="packTape1" fill="none" stroke="none" d="M-0.60 -2.00 l6 20"/>
<path id="packTape2" fill="none" stroke="none" d="M1.80 -4.00 l6 20"/>
<path id="packTape3" fill="none" stroke="none" d="M6.00 -0.00 l6 20"/>
<path id="packTape4" fill="none" stroke="none" d="M8.40 -2.00 l6 20"/>
<path id="packTape5" fill="none" stroke="none" d="M10.80 -4.00 l6 20"/>
<path id="packTape6" fill="none" stroke="none" d="M15.00 -0.00 l6 20"/>
<path id="packTape7" fill="none" stroke="none" d="M17.40 -2.00 l6 20"/>
<path id="packTape8" fill="none" stroke="none" d="M19.80 -4.00 l6 20"/>
<path id="packTape9" fill="none" stroke="none" d="M24.00 -0.00 l6 20"/>
<path id="packTape10" fill="none" stroke="none" d="M26.40 -2.00 l6 20"/>
<path id="packTape11" fill="none" stroke="none" d="M28.80 -4.00 l6 20"/>
<path id="packTape12" fill="none" stroke="none" d="M33.00 -0.00 l6 20"/>
<path id="packTape13" fill="none" stroke="none" d="M35.40 -2.00 l6 20"/>
<path id="packTape14" fill="none" stroke="none" d="M37.80 -4.00 l6 20"/>
<path id="packTape15" fill="none" stroke="none" d="M42.00 -0.00 l6 20"/>
<path id="packTape16" fill="none" stroke="none" d="M44.40 -2.00 l6 20"/>
<path id="packTape17" fill="none" stroke="none" d="M46.80 -4.00 l6 20"/>
<path id="packTape18" fill="none" stroke="none" d="M51.00 -0.00 l6 20"/>
<path id="packTape19" fill="none" stroke="none" d="M53.40 -2.00 l6 20"/>
<path id="packTape20" fill="none" stroke="none" d="M55.80 -4.00 l6 20"/>
<path id="packTape21" fill="none" stroke="none" d="M60.00 -0.00 l6 20"/>
<path id="packTape22" fill="none" stroke="none" d="M62.40 -2.00 l6 20"/>
<path id="packTape23" fill="none" stroke="none" d="M64.80 -4.00 l6 20"/>
<path id="packTape24" fill="none" stroke="none" d="M69.00 -0.00 l6 20"/>
<path id="packTape25" fill="none" stroke="none" d="M71.40 -2.00 l6 20"/>
<path id="packTape26" fill="none" stroke="none" d="M73.80 -4.00 l6 20"/>
<path id="packTape27" fill="none" stroke="none" d="M78.00 -0.00 l6 20"/>
<path id="packTape28" fill="none" stroke="none" d="M80.40 -2.00 l6 20"/>
<path id="packTape29" fill="none" stroke="none" d="M82.80 -4.00 l6 20"/>
<path id="packTape30" fill="none" stroke="none" d="M87.00 -0.00 l6 20"/>
<path id="packTape31" fill="none" stroke="none" d="M89.40 -2.00 l6 20"/>
<path id="packTape32" fill="none" stroke="none" d="M91.80 -4.00 l6 20"/>
<path id="packTape33" fill="none" stroke="none" d="M96.00 -0.00 l6 20"/>
<path id="packTape34" fill="none" stroke="none" d="M98.40 -2.00 l6 20"/>
</svg><div id="packageLabel">
<div id="packageLabelTop"><div>
<svg width="48" height="48" viewBox="0 0 12.7 12.7" version="1.1">
<defs id="defs2" />
<path d="m 12.323869,4.1992062 -6.2301843,2.5959093 -1e-7,0.095169 6.3500004,-2.6458336 z" />
<path d="M 12.443685,4.2444508 V 4.3735617 L 9.2686845,4.925839 V 4.7967281 Z" />
<path d="M 6.0936845,1.6003079 12.443177,4.2450847 9.2686845,4.796728 2.9191918,2.1519511 Z" />
<path d="m 9.2686845,3.8880996 0.062387,0.1201924 -3.237387,3.0585598 2e-7,-0.17699 z" />
<path d="M 9.2686845,4.7967281 V 4.925839 L 8.6378103,4.6632589 8.7123025,4.564976 Z" />
<rect width="6.8791666" height="5.8977885" x="-13.480659" y="9.4293194" transform="matrix(-0.92307692,0.3846154,0,1,0,0)" />
<rect width="6.8791666" height="5.8977885" x="-0.27767482" y="4.3512492" transform="matrix(0.92307692,0.3846154,0,1,0,0)" />
<path d="M 2.9186843,1.2431113 9.2686845,3.8880996 6.0936849,6.8898618 -0.2563155,4.2448735 Z" />
</svg>
</div>
<div>
<div>
<p><b>BYTE TRANSIT FEES PAID</b></p>
<p>64 OF 64</p>
<p>6.28 TB FIBRE OPTIC EXPRESS RATE</p>
<p>ACCEPTS TAR.GZ, ZIP</p>
</div>
<div>
<svg width="618" height="124" viewBox="0 0 618 124" version="1.1">
<path d="M 2.1999999e-6,0 H 41.200002 V 123.6 H 2.1999999e-6 Z M 46.350002,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 20.6,0 H 113.3 v 15.45 h 5.15 V 30.9 h -5.15 v 15.45 h -5.15 V 30.9 H 103 V 46.35 H 97.850002 V 30.9 h -5.15 v 15.45 h 5.15 V 61.8 H 103 v 15.450002 h 5.15 V 61.8 h 5.15 v 61.8 H 87.550002 Z M 118.45,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 25.75 v 15.45 h 5.15 V 30.9 H 154.5 V 15.45 h -15.45 z m 36.05,0 h 15.45 v 30.9 h -5.15 v 30.9 h 5.15 v 15.450002 h -5.15 v 15.45 h -5.15 V 108.15 h 10.3 V 123.6 H 175.1 Z m 20.6,0 h 5.15 V 15.45 H 195.7 Z M 206,0 h 10.3 v 15.45 h -5.15 V 30.9 h 5.15 V 15.45 h 10.3 V 30.9 h -5.15 v 15.45 h 5.15 V 61.8 h 5.15 v 15.450002 h -5.15 v 15.45 h 5.15 V 108.15 H 226.6 V 123.6 H 216.3 V 92.700002 H 206 V 123.6 h -5.15 V 108.15 H 195.7 V 92.700002 h 5.15 v -15.45 H 206 V 61.8 h 5.15 v 15.450002 h 10.3 V 61.8 H 216.3 V 46.35 H 206 V 61.8 H 190.55 V 46.35 h 5.15 V 30.9 H 206 Z m 20.6,0 h 20.6 v 46.35 h -5.15 V 15.45 H 226.6 Z m 36.05,0 h 10.3 v 30.9 h -5.15 v 15.45 h 5.15 v 30.900002 h -5.15 v 15.45 h 10.3 V 108.15 h 5.15 v 15.45 h -10.3 v -15.45 h -5.15 v 15.45 h -5.15 z m 30.9,0 h 10.3 V 30.9 H 309 V 0 h 5.15 v 30.9 h 5.15 v 15.45 h -5.15 V 61.8 h 5.15 v 15.450002 h 5.15 v 15.45 h -10.3 v -15.45 h -10.3 v 15.45 H 298.7 V 108.15 H 288.4 V 77.250002 h 10.3 V 61.8 h 5.15 V 46.35 H 298.7 V 30.9 h -10.3 v 30.9 h -5.15 V 15.45 h 10.3 z m 25.75,0 h 5.15 v 15.45 h 20.6 V 30.9 H 319.3 Z m 30.9,0 h 5.15 v 15.45 h 5.15 V 0 h 15.45 v 15.45 h -10.3 V 30.9 h -10.3 v 15.45 h 5.15 v 46.350002 h 5.15 V 108.15 h 5.15 v 15.45 h -20.6 z m 46.35,0 H 412 v 15.45 h 5.15 v 30.9 H 412 V 61.8 h 5.15 v 15.450002 h 5.15 V 61.8 h 10.3 v 15.450002 h -5.15 v 15.45 h -20.6 v -15.45 h -10.3 V 61.8 h 10.3 V 46.35 h -10.3 V 30.9 h 5.15 V 15.45 h -5.15 z m 20.6,0 h 5.15 v 15.45 h -5.15 z m 20.6,0 h 25.75 v 15.45 h -5.15 V 30.9 h -5.15 v 15.45 h -5.15 V 61.8 h 5.15 V 46.35 h 5.15 V 77.250002 H 453.2 V 123.6 h -5.15 v -15.45 h -5.15 v 15.45 h -5.15 z m 30.9,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 H 515 V 15.45 H 494.4 V 30.9 h 25.75 V 61.8 H 515 v 15.450002 h -10.3 v 15.45 h 15.45 V 108.15 h -10.3 V 123.6 H 494.4 V 92.700002 h 5.15 V 61.8 H 494.4 V 46.35 h -5.15 z m 36.05,0 h 36.05 V 123.6 H 525.3 Z m 41.2,0 h 5.15 v 123.6 h -5.15 z m 20.6,0 h 5.15 v 123.6 h -5.15 z m 10.3,0 h 5.15 v 123.6 h -5.15 z m 15.45,0 H 618 v 123.6 h -5.15 z M 123.6,15.45 h 5.15 V 30.9 h 5.15 V 15.45 h 5.15 V 30.9 h 5.15 v 15.45 h -10.3 v 30.900002 h 15.45 v 15.45 h 5.15 V 61.8 H 144.2 V 46.35 h 25.75 V 61.8 h -5.15 v 30.900002 h 5.15 V 108.15 H 154.5 V 123.6 H 144.2 V 92.700002 h -5.15 V 123.6 H 133.9 V 108.15 H 123.6 V 92.700002 h 5.15 v -15.45 h -5.15 v 15.45 h -5.15 V 61.8 H 113.3 V 46.35 h 10.3 z m 257.5,0 h 5.15 V 30.9 h -5.15 z m 41.2,0 h 10.3 V 30.9 h -10.3 z m 41.2,0 h 5.15 V 30.9 h -5.15 z m 10.3,0 h 5.15 V 30.9 H 473.8 Z M 231.75,30.9 h 5.15 v 15.45 h -5.15 z m 41.2,0 h 5.15 v 15.45 h -5.15 z m 97.85,0 h 5.15 v 15.45 h 5.15 v 30.900002 h -5.15 V 61.8 h -5.15 z m 15.45,0 h 5.15 v 15.45 h -5.15 z m 72.1,0 h 5.15 v 15.45 h -5.15 z m 10.3,0 h 5.15 v 15.45 h 10.3 V 61.8 h 5.15 v 15.450002 h 5.15 v 15.45 h -5.15 V 123.6 h -30.9 V 77.250002 h 5.15 V 108.15 h 10.3 V 92.700002 h -5.15 v -15.45 h 5.15 V 61.8 h -5.15 V 77.250002 H 463.5 V 46.35 h 5.15 z M 103,46.35 h 5.15 V 61.8 H 103 Z m 149.35,0 h 5.15 v 77.25 h -5.15 V 108.15 H 247.2 V 92.700002 h 5.15 z m 77.25,0 h 15.45 V 61.8 h -10.3 v 15.450002 h 10.3 v 15.45 H 339.9 V 108.15 H 329.6 V 123.6 H 303.85 V 92.700002 h 10.3 V 108.15 h 10.3 V 92.700002 h 5.15 v -15.45 h -5.15 V 61.8 h 5.15 z m 61.8,0 h 5.15 V 61.8 H 391.4 Z M 278.1,61.8 h 5.15 v 15.450002 h -5.15 z m -41.2,15.450002 h 5.15 v 15.45 h -5.15 z m 128.75,0 h 10.3 v 15.45 h 5.15 v -15.45 h 5.15 v 15.45 h 5.15 V 108.15 h -5.15 v 15.45 h -10.3 V 108.15 H 370.8 V 92.700002 h -5.15 z M 103,92.700002 V 108.15 h 5.15 V 92.700002 Z m 293.55,0 h 10.3 V 108.15 h -10.3 z m 30.9,0 h 5.15 V 123.6 h -5.15 z M 118.45,108.15 h 5.15 v 15.45 h -5.15 z m 221.45,0 h 5.15 v 15.45 h -5.15 z m 66.95,0 h 10.3 v 15.45 h -10.3 z" fill-rule="evenodd" style="stroke-width:0.858333" />
</svg>
<h1 id="login"></h1>
</div>
</div></div>
<div id="packageLabelTitle">
<h1><b></b></h1>
</div>
<div id="packageLabelContent">
<h1>AWAITING AUTHORIZATION...</h1><div>
<div id="repoSelect">
<h1>REPOSITORY:</h1>
<input id="repoSelectInput" type="text" size="32" placeholder="<user>/<repository>">
<input class="enabled" id="repoSelectButton" type="submit" value="Select">
<p id="repoSelectError"></p>
</div>
<div id="repoInfo">
<h1>ACTIONS:</h1>
<div id="repoActions">
<input class="enabled" id="repoCreate" type="submit" value="Create">
<input id="repoDelete" type="submit" value="Delete">
<input id="repoSecret" type="submit" value="Regenerate Secret">
</div>
<div id="repoFeatures">
<h1>LINK:</h1>
<input id="repoLinkInput" type="text" size="32" readonly>
<input class="enabled" id="repoLinkButton" type="submit" value="Copy">
<h1>FEATURES:</h1>
<div id="featureBox"><input class="feature" type="submit" data-tag="docs" value="Docs"><input class="feature" type="submit" data-tag="builds" value="Builds"><input class="feature" type="submit" data-tag="nightly" value="Nightly"><input class="feature" type="submit" data-tag="preprod" value="PreProd"></div>
</div>
</div>
</div>
<div id="confirmOverlay">
<div>
<div>
<h1>CONFIRMATION:</h1>
<input id="confirmInput" type="text" size="32" placeholder="<user>/<repository>">
<input class="enabled" id="confirmButtonYes" type="submit" value="Confirm">
<input class="enabled" id="confirmButtonNo" type="submit" value="Cancel">
<p>This will (irreversibly) delete all associated files! Please type in the full repository name to confirm.</p>
</div>
</div>
</div></div>
<div id="packageLabelBot"><svg width="1596" height="432" viewBox="0 0 1596 432" version="1.1">
<path d="M 0,432 H 12 V 0 H 0 Z" />
<path d="m 18,432 h 6 V 0 h -6 z" />
<path d="m 36,432 h 6 V 0 h -6 z" />
<path d="m 66,432 h 6 V 0 h -6 z" />
<path d="M 84,432 H 96 V 0 H 84 Z" />
<path d="m 120,432 h 6 V 0 h -6 z" />
<path d="m 132,432 h 6 V 0 h -6 z" />
<path d="m 150,432 h 24 V 0 h -24 z" />
<path d="m 180,432 h 6 V 0 h -6 z" />
<path d="m 198,432 h 6 V 0 h -6 z" />
<path d="m 216,432 h 24 V 0 h -24 z" />
<path d="m 246,432 h 6 V 0 h -6 z" />
<path d="m 264,432 h 6 V 0 h -6 z" />
<path d="m 276,432 h 6 V 0 h -6 z" />
<path d="m 294,432 h 24 V 0 h -24 z" />
<path d="m 330,432 h 6 V 0 h -6 z" />
<path d="m 342,432 h 24 V 0 h -24 z" />
<path d="m 378,432 h 6 V 0 h -6 z" />
<path d="m 396,432 h 18 V 0 h -18 z" />
<path d="m 426,432 h 6 V 0 h -6 z" />
<path d="m 444,432 h 12 V 0 h -12 z" />
<path d="m 462,432 h 6 V 0 h -6 z" />
<path d="m 474,432 h 18 V 0 h -18 z" />
<path d="m 504,432 h 12 V 0 h -12 z" />
<path d="m 528,432 h 6 V 0 h -6 z" />
<path d="m 540,432 h 18 V 0 h -18 z" />
<path d="m 570,432 h 12 V 0 h -12 z" />
<path d="m 594,432 h 6 V 0 h -6 z" />
<path d="m 606,432 h 6 V 0 h -6 z" />
<path d="m 624,432 h 24 V 0 h -24 z" />
<path d="m 660,432 h 6 V 0 h -6 z" />
<path d="m 678,432 h 6 V 0 h -6 z" />
<path d="m 690,432 h 12 V 0 h -12 z" />
<path d="m 726,432 h 6 V 0 h -6 z" />
<path d="m 756,432 h 6 V 0 h -6 z" />
<path d="m 768,432 h 12 V 0 h -12 z" />
<path d="m 792,432 h 12 V 0 h -12 z" />
<path d="m 828,432 h 6 V 0 h -6 z" />
<path d="m 846,432 h 6 V 0 h -6 z" />
<path d="m 858,432 h 6 V 0 h -6 z" />
<path d="m 876,432 h 12 V 0 h -12 z" />
<path d="m 900,432 h 18 V 0 h -18 z" />
<path d="m 924,432 h 12 V 0 h -12 z" />
<path d="m 960,432 h 6 V 0 h -6 z" />
<path d="m 978,432 h 6 V 0 h -6 z" />
<path d="m 990,432 h 6 V 0 h -6 z" />
<path d="m 1020,432 h 12 V 0 h -12 z" />
<path d="m 1044,432 h 6 V 0 h -6 z" />
<path d="m 1056,432 h 6 V 0 h -6 z" />
<path d="m 1074,432 h 6 V 0 h -6 z" />
<path d="m 1086,432 h 12 V 0 h -12 z" />
<path d="m 1122,432 h 6 V 0 h -6 z" />
<path d="m 1146,432 h 24 V 0 h -24 z" />
<path d="m 1176,432 h 6 V 0 h -6 z" />
<path d="m 1188,432 h 6 V 0 h -6 z" />
<path d="m 1206,432 h 12 V 0 h -12 z" />
<path d="m 1230,432 h 18 V 0 h -18 z" />
<path d="m 1254,432 h 24 V 0 h -24 z" />
<path d="m 1284,432 h 18 V 0 h -18 z" />
<path d="m 1308,432 h 6 V 0 h -6 z" />
<path d="m 1320,432 h 6 V 0 h -6 z" />
<path d="m 1332,432 h 12 V 0 h -12 z" />
<path d="m 1356,432 h 6 V 0 h -6 z" />
<path d="m 1386,432 h 6 V 0 h -6 z" />
<path d="m 1398,432 h 18 V 0 h -18 z" />
<path d="m 1428,432 h 12 V 0 h -12 z" />
<path d="m 1452,432 h 6 V 0 h -6 z" />
<path d="m 1470,432 h 6 V 0 h -6 z" />
<path d="m 1488,432 h 24 V 0 h -24 z" />
<path d="m 1518,432 h 12 V 0 h -12 z" />
<path d="m 1548,432 h 18 V 0 h -18 z" />
<path d="m 1572,432 h 6 V 0 h -6 z" />
<path d="m 1584,432 h 12 V 0 h -12 z" />
</svg><a href="/">http://127.0.0.1:3000/</a>
</div>
</div>
</body>
<script>const CONFIG = {
client_id: "3d463405-d098-4038-8b25-a44ca5b9ab9c",
redirect_uri: "http://127.0.0.1:3000/",
authorization_endpoint: "https://git.kjao.me/login/oauth/authorize",
token_endpoint: "https://git.kjao.me/login/oauth/access_token",
requested_scopes: "read:repository,write:repository"
};
var G_AUTH = window.localStorage.getItem("token") !== null;
document.on = document.addEventListener;
function sugar(obj) {
obj.on = obj.addEventListener;
obj.addClass = (x) => obj.classList.add(x);
obj.delClass = (x) => obj.classList.remove(x);
obj.hasClass = (x) => obj.classList.contains(x);
obj.setClass = (x, y) => obj.classList.toggle(x, y);
return obj;
}
function get(s) {
let x = [...document.querySelectorAll(s)].map(sugar);
return (x.length === 1) ? x[0] : x;
}
// Check if object is empty.
function isEmpty(obj) {
for (const prop in obj) {
if (Object.hasOwn(obj, prop)) {
return false;
}
}
return true;
}
// Returns error and resolves promise if necessary.
function getErr(f) {
return (err) => {
if (err instanceof Promise) {
return err.then(f);
} else {
return err;
}
}
}
get("#login").on("click", async (e) => {
e.preventDefault();
if (G_AUTH) {
window.localStorage.clear();
window.location = "/";
} else {
// Build the authorization URL
let url = CONFIG.authorization_endpoint
+ "?response_type=code"
+ "&client_id="+encodeURIComponent(CONFIG.client_id)
+ "&scope="+encodeURIComponent(CONFIG.requested_scopes)
+ "&redirect_uri="+encodeURIComponent(CONFIG.redirect_uri);
// Redirect to the authorization server
window.location = url;
}
});// Fetch function for applet use case.
async function jfetch(url, method, obj={}) {
let request = {
headers: {
"Content-Type": "application/json",
"Authorization": window.localStorage.getItem("token"),
},
method: method,
};
if (!isEmpty(obj)) request["body"] = JSON.stringify(obj);
return fetch(url, request)
.then((response) => {
let contentType = response.headers.get("Content-Type");
let json;
if (contentType && contentType.indexOf("application/json" !== -1)) {
json = response.json();
} else { // Reprocess non-json into json.
json = response.text().then((text) => {
return { status: response.status, "message": text };
});
}
if (!response.ok) { throw json; }
return json;
});
}
// OAUTH //
async function getToken() {
let response;
if (G_QUERY.code) {
response = await jfetch("/api/token", "POST", { code: G_QUERY.code });
} else {
response = await jfetch("/api/token", "PATCH", { code: window.localStorage.getItem("refresh_token") });
}
window.localStorage.setItem("token", response.access_token);
window.localStorage.setItem("token_expiry", (Date.now() + response.expires_in*1000).toString());
window.localStorage.setItem("refresh_token", response.refresh_token);
}
async function tryRefresh() {
if (Date.now() < parseInt(window.localStorage.getItem("token_expiry"))) return; // Not expired.
await getToken().catch((err) => {
let json = err.json();
if (json.status == 401 && json.code === 0) { // Could not refresh, so refresh token expired.
window.localStorage.clear();
alert(`Could not get new session, did you remove access from Gitea?`);
window.location = "/";
} else {
throw json;
}
});
}const STATES = { // Either the non-d
auth: "auth",
error: "error",
loading: "loading",
repoSelected: "repoSelected",
repoCreated: "repoCreated",
buttonOn: "enabled",
featureOn: "fEnabled",
confirmOn: "enabled",
}
var G_REPO_VALUE = "",
G_CONFIRM_VALUE = "",
G_CONFIRM = -1;
// UTILITY //
// Parse a query string into an object
function parseQueryString(string) {
if(string == "") { return {}; }
var segments = string.split("&").map(s => s.split("=") );
var queryString = {};
segments.forEach(s => queryString[s[0]] = s[1]);
return queryString;
}
// BUTTON ONCLICK MIDDLEWARE //
// Refresh token if necessary.
function tryAuth(f) {
return async (e) => {
e.preventDefault();
if (!G_AUTH) return;
await tryRefresh();
await f(e);
}
}
// Adds loading classes for UI while awaiting.
function doLoading(f) {
return async (e) => {
if (e.target.hasClass("loading")) return;
e.target.addClass(STATES["loading"]);
await f(e);
e.target.delClass(STATES["loading"]);
}
}
// BUTTON ONCLICK HELPERS //
function setRepoError(s, err) {
const input = get("#repoSelectInput"),
error = get("#repoSelectError"),
info = get("#repoInfo");
error.innerText = s;
info.setClass(STATES["repoSelected"], !err);
input.setClass(STATES["error"], err);
}
function setRepoActions(s) {
get("#repoCreate").setClass(STATES["buttonOn"], !s);
get("#repoDelete").setClass(STATES["buttonOn"], s);
get("#repoSecret").setClass(STATES["buttonOn"], s);
get("#repoFeatures").setClass(STATES["repoCreated"], s);
}
async function getConfirm() {
get("#confirmOverlay").addClass(STATES["confirmOn"]);
return new Promise((resolve, reject) => {
const check = function() {
if (G_CONFIRM == -1) {
setTimeout(check, 100);
} else {
get("#confirmOverlay").delClass(STATES["confirmOn"]);
resolve(G_CONFIRM);
G_CONFIRM = -1;
}
}
check();
});
}
document.on("keydown", (e) => {
if (e.keyCode == 27) get("#confirmOverlay").delClass(STATES["confirmOn"]);
});
// BUTTON ONCLICK FUNCTIONS //
get("#repoSelectInput").on("keydown", (e) => {
if (e.keyCode === 13) {
get("#repoSelectButton").click();
return;
}
let value = e.target.value;
if (value !== G_REPO_VALUE) {
get("#repoSelectError").innerText = ""; // Delete error text.
get("#repoSelectInput").delClass(STATES["error"]); // Remove error class.
get("#repoInfo").delClass(STATES["repoSelected"]); // Remove repoSelect class.
setRepoActions(false); // Set actions to default.
get(".feature").forEach((feature) => feature.delClass(STATES["featureOn"]));
G_REPO_VALUE = value;
}
});
get("#repoSelectButton").on("click", tryAuth(doLoading(selectRepo)));
async function selectRepo(e) {
const input = get("#repoSelectInput");
let repo = input.value.trim();
input.value = repo;
if (repo === "") {
setRepoError("Field cannot be empty.", true);
return;
}
await jfetch("/api/repo/" + repo, "GET")
.then((json) => {
setRepoError("OK", false);
setRepoActions(json["exists"]);
if (json["exists"]) {
json["features"].forEach((feature) => {
get(`.feature[data-tag=${feature}]`).addClass(STATES["featureOn"]);
});
}
get("#repoLinkInput").value = CONFIG["redirect_uri"] + repo;
get("#repoInfo").addClass(STATES["repoSelected"]);
})
.catch(getErr((err) => {
console.log(err);
setRepoError("Unable to find repository or you have insufficient permissions.", true);
}));
}
get("#repoCreate").on("click", tryAuth(doLoading(createRepo)));
async function createRepo(e) {
const input = get("#repoSelectInput");
await jfetch("/api/repo/" + input.value, "POST")
.then((json) => {
setRepoActions(true);
})
.catch(getErr((err) => {
console.log(err);
alert("An unexpected error occurred! Check console for more details.");
}));
}
get("#repoDelete").on("click", tryAuth(doLoading(deleteRepo)));
async function deleteRepo(e) {
const input = get("#repoSelectInput");
if (!(await getConfirm())) return;
await jfetch("/api/repo/" + input.value, "DELETE")
.then((json) => {
setRepoActions(false);
})
.catch(getErr((err) => {
console.log(err);
alert("An unexpected error occurred! Check console for more details.");
}));
}
get("#repoSecret").on("click", tryAuth(doLoading(regenSecret)));
async function regenSecret(e) {
const input = get("#repoSelectInput");
await jfetch("/api/repo/" + input.value, "PATCH", { secret: true, feature: "" })
.then((json) => {
setRepoActions(true);
})
.catch(getErr((err) => {
console.log(err);
alert("An unexpected error occurred! Check console for more details.");
}));
}
get("#repoLinkButton").on("click", async (e) => {
const input = get("#repoLinkInput");
input.select();
input.setSelectionRange(0, 99999);
navigator.clipboard.writeText(input.value);
});
get(".feature").forEach((el) => el.on("click", tryAuth(doLoading(toggleFeature))));
async function toggleFeature(e) {
const input = get("#repoSelectInput");
let attr = e.target.getAttribute("data-tag");
if (e.target.hasClass(STATES["featureOn"]) && !(await getConfirm())) return;
await jfetch("/api/repo/" + input.value, "PATCH", { secret: false, feature: attr })
.then((json) => {
e.target.setClass(STATES["featureOn"]);
})
.catch(getErr((err) => {
console.log(err);
alert("An unexpected error occurred! Check console for more details.");
}));
}
get("#confirmInput").on("keydown", function(e) {
if (e.keyCode === 13) {
get("#confirmButtonYes").click();
return;
}
if (e.keyCode === 27) {
get("#confirmButtonNo").click();
return;
}
let value = e.target.value;
if (value !== G_CONFIRM_VALUE) {
get("#confirmInput").delClass(STATES["error"]);
G_REPO_VALUE = value;
}
});
get("#confirmButtonNo").on("click", (e) => {
G_CONFIRM = false;
get("#confirmInput").value = "";
});
get("#confirmButtonYes").on("click", (e) => {
let confirmValue = get("#confirmInput").value.trim();
let repoValue = get("#repoSelectInput").value;
if (confirmValue === repoValue) {
G_CONFIRM = true;
get("#confirmInput").value = "";
} else {
get("#confirmInput").addClass(STATES["error"]);
}
});
async function init() {
// Get query and delete URL parameters.
if(G_QUERY.error) alert("Error returned from authorization server: "+q.error); // Check for auth errors.
if(G_QUERY.code) {
await getToken();
G_AUTH = true;
window.history.replaceState({}, document.title, window.location.pathname);
}
get("body").setClass(STATES["auth"], G_AUTH);
}
var G_QUERY = parseQueryString(window.location.search.substring(1));
init();</script>
</html>