Implement autoredirect

This commit is contained in:
CenTdemeern1 2025-01-15 06:44:47 +01:00 committed by git.gay
parent 6861a549ac
commit e66b399961
4 changed files with 88 additions and 13 deletions

View file

@ -61,6 +61,14 @@ abbr[title] {
height: 100%; height: 100%;
} }
.flex-hcenter {
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
height: 100%;
}
.flex-row { .flex-row {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -76,6 +84,13 @@ abbr[title] {
flex-direction: column-reverse; flex-direction: column-reverse;
} }
.flex-vevenly {
display: flex;
flex-direction: column;
justify-content: space-evenly;
height: 100%;
}
.half-width { .half-width {
min-width: 50%; min-width: 50%;
} }

View file

@ -29,7 +29,12 @@
<button onclick="showAddInstanceDialog()">Add an instance</button> <button onclick="showAddInstanceDialog()">Add an instance</button>
</div> </div>
<div class="half-width"> <div class="half-width">
<div class="flex-hcenter">
<div class="flex-vevenly">
<button id="redirect">Redirect</button> <button id="redirect">Redirect</button>
<button id="redirectAlways">Redirect always</button>
</div>
</div>
</div> </div>
</div> </div>
</dialog> </dialog>

View file

@ -13,6 +13,7 @@ const detailsDialog = findDialogOrFail(document.body, "#instanceDetails");
const addDialog = findDialogOrFail(document.body, "#addInstance"); const addDialog = findDialogOrFail(document.body, "#addInstance");
const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm"); const instanceSelectForm = findFormOrFail(document.body, "#instanceSelectForm");
const redirectButton = findButtonOrFail(document.body, "#redirect"); const redirectButton = findButtonOrFail(document.body, "#redirect");
const redirectAlwaysButton = findButtonOrFail(document.body, "#redirectAlways");
export const { export const {
showAddInstanceDialog, showAddInstanceDialog,
@ -48,24 +49,73 @@ function createInstanceSelectOptions() {
instanceSelectForm.appendChild(div); instanceSelectForm.appendChild(div);
} }
const firstInput = instanceSelectForm.querySelector("input"); const firstInput = instanceSelectForm.querySelector("input");
if (firstInput) { if (firstInput) firstInput.checked = true;
firstInput.checked = true; setRedirectButtonState(firstInput !== null);
redirectButton.disabled = false;
} else {
redirectButton.disabled = true;
}
} }
createInstanceSelectOptions(); createInstanceSelectOptions();
storageManager.addSaveCallback(createInstanceSelectOptions); storageManager.addSaveCallback(createInstanceSelectOptions);
function redirect() { function setRedirectButtonState(enabled: boolean) {
// Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default redirectButton.disabled = !enabled;
const option = findInputOrFail(instanceSelectForm, `input[name="${radioButtonName}"]:checked`).value; redirectAlwaysButton.disabled = !enabled;
const url = URL.parse(option)!; }
export function getTargetSoftwareOrGroup(): string {
const currentURL = URL.parse(location.href)!; const currentURL = URL.parse(location.href)!;
url.pathname = currentURL.pathname.replace(/\/.*?\//, "/"); const target = currentURL.pathname.match(/\/+([^\/]*)\/?/)?.[1];
if (target == null) throw new Error("Crossroad was served on an invalid path (likely a backend routing mistake)");
const softwareName = Object.entries(knownSoftware.software).find(([name, software]) => software.aliases.includes(target))?.[0];
if (softwareName) return softwareName;
const groupName = Object.entries(knownSoftware.groups).find(([name, group]) => group.aliases.includes(target))?.[0];
if (groupName) return groupName;
throw new Error("Could not identify target software or group");
}
function getTargetPath(): string {
const currentURL = URL.parse(location.href)!;
return currentURL.pathname.replace(/\/+[^\/]*\/?/, "/");
}
function getSelectedOption(): string | null {
try {
return findInputOrFail(instanceSelectForm, `input[name="${radioButtonName}"]:checked`).value;
} catch {
return null;
}
}
function autoRedirect() {
const targetSoftware = getTargetSoftwareOrGroup();
const preferredFor = storageManager.storage.instances.find(instance => instance.preferredFor?.includes(targetSoftware));
if (preferredFor) redirect(preferredFor.origin);
}
autoRedirect();
function setAutoRedirect(option: string) {
const instance = storageManager.storage.instances.find(e => e.origin === option);
if (!instance) throw new Error("Invalid argument");
instance.preferredFor ??= [];
instance.preferredFor.push(getTargetSoftwareOrGroup());
storageManager.save();
}
redirectAlwaysButton.addEventListener("click", e => {
// Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default
const option = getSelectedOption()!;
setAutoRedirect(option);
redirect(option);
});
function redirect(to: string) {
const url = URL.parse(to);
if (url === null) throw new Error("Couldn't parse destination");
url.pathname = getTargetPath();
location.href = url.toString(); location.href = url.toString();
} }
redirectButton.addEventListener("click", e => redirect()); redirectButton.addEventListener("click", e => {
// Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default
redirect(getSelectedOption()!);
});

View file

@ -25,6 +25,11 @@ export type Instance = {
* Make sure to sanitize this! Could lead to XSS * Make sure to sanitize this! Could lead to XSS
*/ */
iconURL?: string, iconURL?: string,
/**
* The list of software names and groups the user prefers to autoredirect to this instance
* @example ["sharkey", "misskey-compliant"]
*/
preferredFor?: string[],
} }
type LocalStorage = { type LocalStorage = {