const STATES = { // Either the non-d auth: "{{ state.auth }}", error: "{{ state.error }}", loading: "{{ state.loading }}", repoSelected: "{{ state.repo_selected }}", repoCreated: "{{ state.repo_created }}", buttonOn: "{{ state.button_on }}", featureOn: "{{ state.feature_on }}", confirmOn: "{{ state.confirm_on }}", } 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();