mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-12-28 19:08:32 +08:00
refactor: remove JQuery from pages directory (@Leonabcd123) (#7237)
- [x] 404 - [x] about - [x] account-settings - [x] account - [x] friends - [x] leaderboards - [x] loading - [x] login - [x] page - [x] profile-search - [x] profile - [x] settings - [x] test Before merging make sure to load every changed page to check for the qsa notification. --------- Co-authored-by: Christian Fehmer <fehmer@users.noreply.github.com>
This commit is contained in:
parent
fd177c9ed4
commit
5d169e933a
10 changed files with 560 additions and 480 deletions
|
|
@ -10,11 +10,11 @@ import * as Skeleton from "../utils/skeleton";
|
|||
import { TypingStats, SpeedHistogram } from "@monkeytype/schemas/public";
|
||||
import { getNumberWithMagnitude, numberWithSpaces } from "../utils/numbers";
|
||||
import { tryCatch } from "@monkeytype/util/trycatch";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsr, onWindowLoad } from "../utils/dom";
|
||||
|
||||
function reset(): void {
|
||||
$(".pageAbout .contributors").empty();
|
||||
$(".pageAbout .supporters").empty();
|
||||
qs(".pageAbout .contributors")?.empty();
|
||||
qs(".pageAbout .supporters")?.empty();
|
||||
|
||||
ChartController.globalSpeedHistogram.getDataset("count").data = [];
|
||||
void ChartController.globalSpeedHistogram.updateColors();
|
||||
|
|
@ -43,11 +43,11 @@ function updateStatsAndHistogram(): void {
|
|||
end: secondsRounded * 1000,
|
||||
});
|
||||
|
||||
$(".pageAbout #totalTimeTypingStat .val").text(
|
||||
qs(".pageAbout #totalTimeTypingStat .val")?.setText(
|
||||
timeTypingDuration.years?.toString() ?? "",
|
||||
);
|
||||
$(".pageAbout #totalTimeTypingStat .valSmall").text("years");
|
||||
$(".pageAbout #totalTimeTypingStat").attr(
|
||||
qs(".pageAbout #totalTimeTypingStat .valSmall")?.setText("years");
|
||||
qs(".pageAbout #totalTimeTypingStat")?.setAttribute(
|
||||
"aria-label",
|
||||
numberWithSpaces(Math.round(secondsRounded / 3600)) + " hours",
|
||||
);
|
||||
|
|
@ -56,15 +56,15 @@ function updateStatsAndHistogram(): void {
|
|||
typingStatsResponseData.testsStarted,
|
||||
);
|
||||
|
||||
$(".pageAbout #totalStartedTestsStat .val").text(
|
||||
qs(".pageAbout #totalStartedTestsStat .val")?.setText(
|
||||
startedWithMagnitude.rounded < 10
|
||||
? startedWithMagnitude.roundedTo2
|
||||
: startedWithMagnitude.rounded,
|
||||
? startedWithMagnitude.roundedTo2.toString()
|
||||
: startedWithMagnitude.rounded.toString(),
|
||||
);
|
||||
$(".pageAbout #totalStartedTestsStat .valSmall").text(
|
||||
qs(".pageAbout #totalStartedTestsStat .valSmall")?.setText(
|
||||
startedWithMagnitude.orderOfMagnitude,
|
||||
);
|
||||
$(".pageAbout #totalStartedTestsStat").attr(
|
||||
qs(".pageAbout #totalStartedTestsStat")?.setAttribute(
|
||||
"aria-label",
|
||||
numberWithSpaces(typingStatsResponseData.testsStarted) + " tests",
|
||||
);
|
||||
|
|
@ -73,15 +73,15 @@ function updateStatsAndHistogram(): void {
|
|||
typingStatsResponseData.testsCompleted,
|
||||
);
|
||||
|
||||
$(".pageAbout #totalCompletedTestsStat .val").text(
|
||||
qs(".pageAbout #totalCompletedTestsStat .val")?.setText(
|
||||
completedWIthMagnitude.rounded < 10
|
||||
? completedWIthMagnitude.roundedTo2
|
||||
: completedWIthMagnitude.rounded,
|
||||
? completedWIthMagnitude.roundedTo2.toString()
|
||||
: completedWIthMagnitude.rounded.toString(),
|
||||
);
|
||||
$(".pageAbout #totalCompletedTestsStat .valSmall").text(
|
||||
qs(".pageAbout #totalCompletedTestsStat .valSmall")?.setText(
|
||||
completedWIthMagnitude.orderOfMagnitude,
|
||||
);
|
||||
$(".pageAbout #totalCompletedTestsStat").attr(
|
||||
qs(".pageAbout #totalCompletedTestsStat")?.setAttribute(
|
||||
"aria-label",
|
||||
numberWithSpaces(typingStatsResponseData.testsCompleted) + " tests",
|
||||
);
|
||||
|
|
@ -212,6 +212,6 @@ export const page = new Page({
|
|||
},
|
||||
});
|
||||
|
||||
$(() => {
|
||||
onWindowLoad(() => {
|
||||
Skeleton.save("pageAbout");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import { SnapshotResult } from "../constants/default-snapshot";
|
|||
import Ape from "../ape";
|
||||
import { AccountChart } from "@monkeytype/schemas/configs";
|
||||
import { SortedTableWithLimit } from "../utils/sorted-table";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsa, qsr, onWindowLoad, ElementWithUtils } from "../utils/dom";
|
||||
|
||||
let filterDebug = false;
|
||||
//toggle filterdebug
|
||||
|
|
@ -62,9 +62,9 @@ function loadMoreLines(lineIndex?: number): void {
|
|||
|
||||
visibleTableLines = newVisibleLines;
|
||||
if (visibleTableLines >= filteredResults.length) {
|
||||
$(".pageAccount .loadMoreButton").addClass("hidden");
|
||||
qs(".pageAccount .loadMoreButton")?.hide();
|
||||
} else {
|
||||
$(".pageAccount .loadMoreButton").removeClass("hidden");
|
||||
qs(".pageAccount .loadMoreButton")?.show();
|
||||
}
|
||||
|
||||
historyTable.setLimit(newVisibleLines);
|
||||
|
|
@ -284,7 +284,7 @@ async function fillContent(): Promise<void> {
|
|||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
|
||||
filteredResults = [];
|
||||
$(".pageAccount .history table tbody").empty();
|
||||
qs(".pageAccount .history table tbody")?.empty();
|
||||
|
||||
DB.getSnapshot()?.results?.forEach((result) => {
|
||||
// totalSeconds += tt;
|
||||
|
|
@ -673,7 +673,7 @@ async function fillContent(): Promise<void> {
|
|||
|
||||
historyTable.setData(filteredResults);
|
||||
|
||||
$(".pageAccount .group.history table thead tr td:nth-child(2)").text(
|
||||
qs(".pageAccount .group.history table thead tr td:nth-child(2)")?.setText(
|
||||
Config.typingSpeedUnit,
|
||||
);
|
||||
|
||||
|
|
@ -854,91 +854,95 @@ async function fillContent(): Promise<void> {
|
|||
}
|
||||
|
||||
if (chartData === undefined || chartData.length === 0) {
|
||||
$(".pageAccount .group.noDataError").removeClass("hidden");
|
||||
$(".pageAccount .group.chart").addClass("hidden");
|
||||
$(".pageAccount .group.dailyActivityChart").addClass("hidden");
|
||||
$(".pageAccount .group.histogramChart").addClass("hidden");
|
||||
$(".pageAccount .group.aboveHistory").addClass("hidden");
|
||||
$(".pageAccount .group.history").addClass("hidden");
|
||||
$(".pageAccount .triplegroup.stats").addClass("hidden");
|
||||
$(".pageAccount .group.estimatedWordsTyped").addClass("hidden");
|
||||
qs(".pageAccount .group.noDataError")?.show();
|
||||
qs(".pageAccount .group.chart")?.hide();
|
||||
qs(".pageAccount .group.dailyActivityChart")?.hide();
|
||||
qs(".pageAccount .group.histogramChart")?.hide();
|
||||
qs(".pageAccount .group.aboveHistory")?.hide();
|
||||
qs(".pageAccount .group.history")?.hide();
|
||||
qs(".pageAccount .triplegroup.stats")?.hide();
|
||||
qs(".pageAccount .group.estimatedWordsTyped")?.hide();
|
||||
} else {
|
||||
$(".pageAccount .group.noDataError").addClass("hidden");
|
||||
$(".pageAccount .group.chart").removeClass("hidden");
|
||||
$(".pageAccount .group.dailyActivityChart").removeClass("hidden");
|
||||
$(".pageAccount .group.histogramChart").removeClass("hidden");
|
||||
$(".pageAccount .group.aboveHistory").removeClass("hidden");
|
||||
$(".pageAccount .group.history").removeClass("hidden");
|
||||
$(".pageAccount .triplegroup.stats").removeClass("hidden");
|
||||
$(".pageAccount .group.estimatedWordsTyped").removeClass("hidden");
|
||||
qs(".pageAccount .group.noDataError")?.hide();
|
||||
qs(".pageAccount .group.chart")?.show();
|
||||
qs(".pageAccount .group.dailyActivityChart")?.show();
|
||||
qs(".pageAccount .group.histogramChart")?.show();
|
||||
qs(".pageAccount .group.aboveHistory")?.show();
|
||||
qs(".pageAccount .group.history")?.show();
|
||||
qs(".pageAccount .triplegroup.stats")?.show();
|
||||
qs(".pageAccount .group.estimatedWordsTyped")?.show();
|
||||
}
|
||||
|
||||
$(".pageAccount .timeTotalFiltered .val").text(
|
||||
qs(".pageAccount .timeTotalFiltered .val")?.setText(
|
||||
DateTime.secondsToString(Math.round(totalSecondsFiltered), true, true),
|
||||
);
|
||||
|
||||
const speedUnit = Config.typingSpeedUnit;
|
||||
|
||||
$(".pageAccount .highestWpm .title").text(`highest ${speedUnit}`);
|
||||
$(".pageAccount .highestWpm .val").text(Format.typingSpeed(topWpm));
|
||||
qs(".pageAccount .highestWpm .title")?.setText(`highest ${speedUnit}`);
|
||||
qs(".pageAccount .highestWpm .val")?.setText(Format.typingSpeed(topWpm));
|
||||
|
||||
$(".pageAccount .averageWpm .title").text(`average ${speedUnit}`);
|
||||
$(".pageAccount .averageWpm .val").text(
|
||||
qs(".pageAccount .averageWpm .title")?.setText(`average ${speedUnit}`);
|
||||
qs(".pageAccount .averageWpm .val")?.setText(
|
||||
Format.typingSpeed(totalWpm / testCount),
|
||||
);
|
||||
|
||||
$(".pageAccount .averageWpm10 .title").text(
|
||||
qs(".pageAccount .averageWpm10 .title")?.setText(
|
||||
`average ${speedUnit} (last 10 tests)`,
|
||||
);
|
||||
$(".pageAccount .averageWpm10 .val").text(
|
||||
qs(".pageAccount .averageWpm10 .val")?.setText(
|
||||
Format.typingSpeed(wpmLast10total / last10),
|
||||
);
|
||||
|
||||
$(".pageAccount .highestRaw .title").text(`highest raw ${speedUnit}`);
|
||||
$(".pageAccount .highestRaw .val").text(Format.typingSpeed(rawWpm.max));
|
||||
qs(".pageAccount .highestRaw .title")?.setText(`highest raw ${speedUnit}`);
|
||||
qs(".pageAccount .highestRaw .val")?.setText(Format.typingSpeed(rawWpm.max));
|
||||
|
||||
$(".pageAccount .averageRaw .title").text(`average raw ${speedUnit}`);
|
||||
$(".pageAccount .averageRaw .val").text(
|
||||
qs(".pageAccount .averageRaw .title")?.setText(`average raw ${speedUnit}`);
|
||||
qs(".pageAccount .averageRaw .val")?.setText(
|
||||
Format.typingSpeed(rawWpm.total / rawWpm.count),
|
||||
);
|
||||
|
||||
$(".pageAccount .averageRaw10 .title").text(
|
||||
qs(".pageAccount .averageRaw10 .title")?.setText(
|
||||
`average raw ${speedUnit} (last 10 tests)`,
|
||||
);
|
||||
$(".pageAccount .averageRaw10 .val").text(
|
||||
qs(".pageAccount .averageRaw10 .val")?.setText(
|
||||
Format.typingSpeed(rawWpm.last10Total / rawWpm.last10Count),
|
||||
);
|
||||
|
||||
$(".pageAccount .highestWpm .mode").html(topMode);
|
||||
$(".pageAccount .testsTaken .val").text(testCount);
|
||||
qs(".pageAccount .highestWpm .mode")?.setHtml(topMode);
|
||||
qs(".pageAccount .testsTaken .val")?.setText(testCount.toString());
|
||||
|
||||
$(".pageAccount .highestAcc .val").text(Format.accuracy(topAcc));
|
||||
$(".pageAccount .avgAcc .val").text(Format.accuracy(totalAcc / testCount));
|
||||
$(".pageAccount .avgAcc10 .val").text(Format.accuracy(totalAcc10 / last10));
|
||||
qs(".pageAccount .highestAcc .val")?.setText(Format.accuracy(topAcc));
|
||||
qs(".pageAccount .avgAcc .val")?.setText(
|
||||
Format.accuracy(totalAcc / testCount),
|
||||
);
|
||||
qs(".pageAccount .avgAcc10 .val")?.setText(
|
||||
Format.accuracy(totalAcc10 / last10),
|
||||
);
|
||||
|
||||
if (totalCons === 0 || totalCons === undefined) {
|
||||
$(".pageAccount .avgCons .val").text("-");
|
||||
$(".pageAccount .avgCons10 .val").text("-");
|
||||
qs(".pageAccount .avgCons .val")?.setText("-");
|
||||
qs(".pageAccount .avgCons10 .val")?.setText("-");
|
||||
} else {
|
||||
$(".pageAccount .highestCons .val").text(Format.percentage(topCons));
|
||||
qs(".pageAccount .highestCons .val")?.setText(Format.percentage(topCons));
|
||||
|
||||
$(".pageAccount .avgCons .val").text(
|
||||
qs(".pageAccount .avgCons .val")?.setText(
|
||||
Format.percentage(totalCons / consCount),
|
||||
);
|
||||
|
||||
$(".pageAccount .avgCons10 .val").text(
|
||||
qs(".pageAccount .avgCons10 .val")?.setText(
|
||||
Format.percentage(totalCons10 / Math.min(last10, consCount)),
|
||||
);
|
||||
}
|
||||
|
||||
$(".pageAccount .testsStarted .val").text(`${testCount + testRestarts}`);
|
||||
$(".pageAccount .testsCompleted .val").text(
|
||||
qs(".pageAccount .testsStarted .val")?.setText(`${testCount + testRestarts}`);
|
||||
qs(".pageAccount .testsCompleted .val")?.setText(
|
||||
`${testCount}(${Math.floor(
|
||||
(testCount / (testCount + testRestarts)) * 100,
|
||||
)}%)`,
|
||||
);
|
||||
|
||||
$(".pageAccount .testsCompleted .avgres").text(`
|
||||
qs(".pageAccount .testsCompleted .avgres")?.setText(`
|
||||
${(testRestarts / testCount).toFixed(1)} restarts per completed test
|
||||
`);
|
||||
|
||||
|
|
@ -949,13 +953,15 @@ async function fillContent(): Promise<void> {
|
|||
const wpmChange = trend[1][1] - trend[0][1];
|
||||
const wpmChangePerHour = wpmChange * (3600 / totalSecondsFiltered);
|
||||
const plus = wpmChangePerHour > 0 ? "+" : "";
|
||||
$(".pageAccount .group.chart .below .text").text(
|
||||
qs(".pageAccount .group.chart .below .text")?.setText(
|
||||
`Speed change per hour spent typing: ${
|
||||
plus + Format.typingSpeed(wpmChangePerHour, { showDecimalPlaces: true })
|
||||
} ${Config.typingSpeedUnit}`,
|
||||
);
|
||||
}
|
||||
$(".pageAccount .estimatedWordsTyped .val").text(totalEstimatedWords);
|
||||
qs(".pageAccount .estimatedWordsTyped .val")?.setText(
|
||||
totalEstimatedWords.toString(),
|
||||
);
|
||||
|
||||
if (chartData.length || accChartData.length) {
|
||||
ChartController.updateAccountChartButtons();
|
||||
|
|
@ -967,7 +973,7 @@ async function fillContent(): Promise<void> {
|
|||
ChartController.accountActivity.update();
|
||||
ChartController.accountHistogram.update();
|
||||
Focus.set(false);
|
||||
$(".page.pageAccount").css("height", "unset"); //weird safari fix
|
||||
qs(".page.pageAccount")?.setStyle({ height: "unset" }); //weird safari fix
|
||||
setTimeout(() => {
|
||||
Profile.updateNameFontSize("account");
|
||||
}, 0);
|
||||
|
|
@ -1012,56 +1018,56 @@ export function updateTagsForResult(resultId: string, tagIds: string[]): void {
|
|||
}
|
||||
}
|
||||
|
||||
const el = $(
|
||||
const el = qs(
|
||||
`.pageAccount .resultEditTagsButton[data-result-id='${resultId}']`,
|
||||
);
|
||||
|
||||
el.attr("data-tags", JSON.stringify(tagIds));
|
||||
el?.setAttribute("data-tags", JSON.stringify(tagIds));
|
||||
|
||||
if (tagIds.length > 0) {
|
||||
el.attr("aria-label", tagNames.join(", "));
|
||||
el.addClass("active");
|
||||
el?.setAttribute("aria-label", tagNames.join(", "));
|
||||
el?.addClass("active");
|
||||
if (tagIds.length > 1) {
|
||||
el.html(`<i class="fas fa-fw fa-tags"></i>`);
|
||||
el?.setHtml(`<i class="fas fa-fw fa-tags"></i>`);
|
||||
} else {
|
||||
el.html(`<i class="fas fa-fw fa-tag"></i>`);
|
||||
el?.setHtml(`<i class="fas fa-fw fa-tag"></i>`);
|
||||
}
|
||||
} else {
|
||||
el.attr("aria-label", "no tags");
|
||||
el.removeClass("active");
|
||||
el.html(`<i class="fas fa-fw fa-tag"></i>`);
|
||||
el?.setAttribute("aria-label", "no tags");
|
||||
el?.removeClass("active");
|
||||
el?.setHtml(`<i class="fas fa-fw fa-tag"></i>`);
|
||||
}
|
||||
}
|
||||
|
||||
$(".pageAccount button.toggleResultsOnChart").on("click", () => {
|
||||
qs(".pageAccount button.toggleResultsOnChart")?.on("click", () => {
|
||||
const newValue = [...Config.accountChart] as AccountChart;
|
||||
newValue[0] = newValue[0] === "on" ? "off" : "on";
|
||||
setConfig("accountChart", newValue);
|
||||
});
|
||||
|
||||
$(".pageAccount button.toggleAccuracyOnChart").on("click", () => {
|
||||
qs(".pageAccount button.toggleAccuracyOnChart")?.on("click", () => {
|
||||
const newValue = [...Config.accountChart] as AccountChart;
|
||||
newValue[1] = newValue[1] === "on" ? "off" : "on";
|
||||
setConfig("accountChart", newValue);
|
||||
});
|
||||
|
||||
$(".pageAccount button.toggleAverage10OnChart").on("click", () => {
|
||||
qs(".pageAccount button.toggleAverage10OnChart")?.on("click", () => {
|
||||
const newValue = [...Config.accountChart] as AccountChart;
|
||||
newValue[2] = newValue[2] === "on" ? "off" : "on";
|
||||
setConfig("accountChart", newValue);
|
||||
});
|
||||
|
||||
$(".pageAccount button.toggleAverage100OnChart").on("click", () => {
|
||||
qs(".pageAccount button.toggleAverage100OnChart")?.on("click", () => {
|
||||
const newValue = [...Config.accountChart] as AccountChart;
|
||||
newValue[3] = newValue[3] === "on" ? "off" : "on";
|
||||
setConfig("accountChart", newValue);
|
||||
});
|
||||
|
||||
$(".pageAccount .loadMoreButton").on("click", () => {
|
||||
qs(".pageAccount .loadMoreButton")?.on("click", () => {
|
||||
loadMoreLines();
|
||||
});
|
||||
|
||||
$(".pageAccount #accountHistoryChart").on("click", () => {
|
||||
qs(".pageAccount #accountHistoryChart")?.on("click", () => {
|
||||
const index: number = ChartController.accountHistoryActiveIndex;
|
||||
loadMoreLines(index);
|
||||
if (window === undefined) return;
|
||||
|
|
@ -1070,98 +1076,109 @@ $(".pageAccount #accountHistoryChart").on("click", () => {
|
|||
if (resultId === undefined) {
|
||||
throw new Error("Cannot find result for index " + index);
|
||||
}
|
||||
const element = $(`.resultRow[data-id="${resultId}"`);
|
||||
$(".resultRow").removeClass("active");
|
||||
const element = qs(`.resultRow[data-id="${resultId}"`);
|
||||
qsa(".resultRow").removeClass("active");
|
||||
|
||||
element[0]?.scrollIntoView({
|
||||
element?.scrollIntoView({
|
||||
block: "center",
|
||||
});
|
||||
|
||||
element.addClass("active");
|
||||
element?.addClass("active");
|
||||
});
|
||||
|
||||
$(".pageAccount").on("click", ".miniResultChartButton", async (event) => {
|
||||
const target = $(event.currentTarget);
|
||||
const resultId: string = target.parents("tr").data("id") as string;
|
||||
if (target.hasClass("loading")) return;
|
||||
if (target.hasClass("disabled")) return;
|
||||
|
||||
const result = filteredResults.find((it) => it._id === resultId);
|
||||
if (result === undefined) return;
|
||||
|
||||
let chartData = result.chartData as ChartData;
|
||||
|
||||
if (chartData === undefined) {
|
||||
//need to load full result
|
||||
target.addClass("loading");
|
||||
target.attr("aria-label", null);
|
||||
target.html('<i class="fas fa-fw fa-spin fa-circle-notch"></i>');
|
||||
Loader.show();
|
||||
|
||||
const response = await Ape.results.getById({
|
||||
params: { resultId: result._id },
|
||||
});
|
||||
Loader.hide();
|
||||
|
||||
target.html('<i class="fas fa-fw fa-chart-line"></i>');
|
||||
target.removeClass("loading");
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Error fetching result", -1, { response });
|
||||
return;
|
||||
}
|
||||
|
||||
chartData = response.body.data.chartData as ChartData;
|
||||
|
||||
//update local cache
|
||||
result.chartData = chartData;
|
||||
const dbResult = DB.getSnapshot()?.results?.find(
|
||||
(it) => it._id === result._id,
|
||||
);
|
||||
if (dbResult !== undefined) {
|
||||
dbResult["chartData"] = result.chartData;
|
||||
}
|
||||
|
||||
if (response.body.data.chartData === "toolong") {
|
||||
target.attr(
|
||||
"aria-label",
|
||||
"Graph history is not available for long tests",
|
||||
);
|
||||
target.attr("data-baloon-pos", "up");
|
||||
target.addClass("disabled");
|
||||
|
||||
Notifications.add("Graph history is not available for long tests", 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
target.attr("aria-label", "View graph");
|
||||
MiniResultChartModal.show(chartData);
|
||||
});
|
||||
|
||||
$(".pageAccount .group.topFilters, .pageAccount .filterButtons").on(
|
||||
qs(".pageAccount")?.onChild(
|
||||
"click",
|
||||
"button",
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
void update();
|
||||
}, 0);
|
||||
".miniResultChartButton",
|
||||
async (event) => {
|
||||
const target = new ElementWithUtils(event.childTarget as HTMLElement);
|
||||
const resultId: string = target
|
||||
.closestParent("tr")
|
||||
?.getAttribute("data-id") as string;
|
||||
if (target.hasClass("loading")) return;
|
||||
if (target.hasClass("disabled")) return;
|
||||
|
||||
const result = filteredResults.find((it) => it._id === resultId);
|
||||
if (result === undefined) return;
|
||||
|
||||
let chartData = result.chartData as ChartData;
|
||||
|
||||
if (chartData === undefined) {
|
||||
//need to load full result
|
||||
target?.addClass("loading");
|
||||
target?.removeAttribute("aria-label");
|
||||
target?.setHtml('<i class="fas fa-fw fa-spin fa-circle-notch"></i>');
|
||||
Loader.show();
|
||||
|
||||
const response = await Ape.results.getById({
|
||||
params: { resultId: result._id },
|
||||
});
|
||||
Loader.hide();
|
||||
|
||||
target?.setHtml('<i class="fas fa-fw fa-chart-line"></i>');
|
||||
target?.removeClass("loading");
|
||||
|
||||
if (response.status !== 200) {
|
||||
Notifications.add("Error fetching result", -1, { response });
|
||||
return;
|
||||
}
|
||||
|
||||
chartData = response.body.data.chartData as ChartData;
|
||||
|
||||
//update local cache
|
||||
result.chartData = chartData;
|
||||
const dbResult = DB.getSnapshot()?.results?.find(
|
||||
(it) => it._id === result._id,
|
||||
);
|
||||
if (dbResult !== undefined) {
|
||||
dbResult["chartData"] = result.chartData;
|
||||
}
|
||||
|
||||
if (response.body.data.chartData === "toolong") {
|
||||
target?.setAttribute(
|
||||
"aria-label",
|
||||
"Graph history is not available for long tests",
|
||||
);
|
||||
target?.setAttribute("data-balloon-pos", "up");
|
||||
target.addClass("disabled");
|
||||
|
||||
Notifications.add("Graph history is not available for long tests", 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
target?.setAttribute("aria-label", "View graph");
|
||||
MiniResultChartModal.show(chartData);
|
||||
},
|
||||
);
|
||||
|
||||
$(".pageAccount .group.presetFilterButtons").on(
|
||||
const filterButtons = qsa(
|
||||
".pageAccount .group.topFilters, .pageAccount .filterButtons",
|
||||
);
|
||||
|
||||
filterButtons.forEach((filterButton) => {
|
||||
filterButton.onChild("click", "button", () => {
|
||||
setTimeout(() => {
|
||||
void update();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
qs(".pageAccount .group.presetFilterButtons")?.onChild(
|
||||
"click",
|
||||
".filterBtns .filterPresets .select-filter-preset",
|
||||
async (e) => {
|
||||
await ResultFilters.setFilterPreset($(e.target).data("id") as string);
|
||||
const target = e.childTarget as HTMLElement;
|
||||
await ResultFilters.setFilterPreset(
|
||||
target.getAttribute("data-id") as string,
|
||||
);
|
||||
void update();
|
||||
},
|
||||
);
|
||||
|
||||
$(".pageAccount .content .group.aboveHistory .exportCSV").on("click", () => {
|
||||
qs(".pageAccount .content .group.aboveHistory .exportCSV")?.on("click", () => {
|
||||
void Misc.downloadResultsCSV(filteredResults);
|
||||
});
|
||||
|
||||
$(".pageAccount .profile").on("click", ".details .copyLink", () => {
|
||||
qs(".pageAccount .profile")?.onChild("click", ".details .copyLink", () => {
|
||||
const snapshot = DB.getSnapshot();
|
||||
if (!snapshot) return;
|
||||
const { name } = snapshot;
|
||||
|
|
@ -1177,7 +1194,7 @@ $(".pageAccount .profile").on("click", ".details .copyLink", () => {
|
|||
);
|
||||
});
|
||||
|
||||
$(".pageAccount button.loadMoreResults").on("click", async () => {
|
||||
qs(".pageAccount button.loadMoreResults")?.on("click", async () => {
|
||||
const offset = DB.getSnapshot()?.results?.length ?? 0;
|
||||
|
||||
Loader.show();
|
||||
|
|
@ -1256,9 +1273,9 @@ export const page = new Page<undefined>({
|
|||
|
||||
await update().then(() => {
|
||||
void updateChartColors();
|
||||
$(".pageAccount .content .accountVerificatinNotice").remove();
|
||||
qs(".pageAccount .content .accountVerificatinNotice")?.remove();
|
||||
if (getAuthenticatedUser()?.emailVerified === false) {
|
||||
$(".pageAccount .content").prepend(
|
||||
qs(".pageAccount .content")?.prependHtml(
|
||||
`<div class="accountVerificatinNotice"><i class="fas icon fa-exclamation-triangle"></i><p>Your email address is still not verified</p><button class="sendVerificationEmail">resend verification email</button></div>`,
|
||||
);
|
||||
}
|
||||
|
|
@ -1267,6 +1284,6 @@ export const page = new Page<undefined>({
|
|||
},
|
||||
});
|
||||
|
||||
$(() => {
|
||||
onWindowLoad(() => {
|
||||
Skeleton.save("pageAccount");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import { Friend, UserNameSchema } from "@monkeytype/schemas/users";
|
|||
import * as Loader from "../elements/loader";
|
||||
import { LocalStorageWithSchema } from "../utils/local-storage-with-schema";
|
||||
import { remoteValidation } from "../utils/remote-validation";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsr, onWindowLoad } from "../utils/dom";
|
||||
|
||||
let friendsTable: SortedTable<Friend> | undefined = undefined;
|
||||
|
||||
|
|
@ -155,12 +155,12 @@ async function fetchPendingConnections(): Promise<void> {
|
|||
}
|
||||
|
||||
function updatePendingConnections(): void {
|
||||
$(".pageFriends .pendingRequests").addClass("hidden");
|
||||
qs(".pageFriends .pendingRequests")?.hide();
|
||||
|
||||
if (pendingRequests === undefined || pendingRequests.length === 0) {
|
||||
$(".pageFriends .pendingRequests").addClass("hidden");
|
||||
qs(".pageFriends .pendingRequests")?.hide();
|
||||
} else {
|
||||
$(".pageFriends .pendingRequests").removeClass("hidden");
|
||||
qs(".pageFriends .pendingRequests")?.show();
|
||||
|
||||
const html = pendingRequests
|
||||
.map(
|
||||
|
|
@ -193,7 +193,7 @@ function updatePendingConnections(): void {
|
|||
)
|
||||
.join("\n");
|
||||
|
||||
$(".pageFriends .pendingRequests tbody").html(html);
|
||||
qs(".pageFriends .pendingRequests tbody")?.setHtml(html);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,17 +208,17 @@ async function fetchFriends(): Promise<void> {
|
|||
}
|
||||
|
||||
function updateFriends(): void {
|
||||
$(".pageFriends .friends .nodata").addClass("hidden");
|
||||
$(".pageFriends .friends table").addClass("hidden");
|
||||
qs(".pageFriends .friends .nodata")?.hide();
|
||||
qs(".pageFriends .friends table")?.hide();
|
||||
|
||||
$(".pageFriends .friends .error").addClass("hidden");
|
||||
qs(".pageFriends .friends .error")?.hide();
|
||||
|
||||
if (friendsList === undefined || friendsList.length === 0) {
|
||||
$(".pageFriends .friends table").addClass("hidden");
|
||||
$(".pageFriends .friends .nodata").removeClass("hidden");
|
||||
qs(".pageFriends .friends table")?.hide();
|
||||
qs(".pageFriends .friends .nodata")?.show();
|
||||
} else {
|
||||
$(".pageFriends .friends table").removeClass("hidden");
|
||||
$(".pageFriends .friends .nodata").addClass("hidden");
|
||||
qs(".pageFriends .friends table")?.show();
|
||||
qs(".pageFriends .friends .nodata")?.hide();
|
||||
|
||||
if (friendsTable === undefined) {
|
||||
friendsTable = new SortedTable<Friend>({
|
||||
|
|
@ -386,19 +386,20 @@ function formatStreak(length?: number, prefix?: string): string {
|
|||
: "-";
|
||||
}
|
||||
|
||||
$(".pageFriends button.friendAdd").on("click", () => {
|
||||
qs(".pageFriends button.friendAdd")?.on("click", () => {
|
||||
addFriendModal.show(undefined, {});
|
||||
});
|
||||
|
||||
// need to set the listener for action buttons on the table because the table content is getting replaced
|
||||
$(".pageFriends .pendingRequests table").on("click", async (e) => {
|
||||
const action = Array.from(e.target.classList).find((it) =>
|
||||
qs(".pageFriends .pendingRequests table")?.on("click", async (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const action = Array.from(target.classList).find((it) =>
|
||||
["accepted", "rejected", "blocked"].includes(it),
|
||||
) as "accepted" | "rejected" | "blocked";
|
||||
|
||||
if (action === undefined) return;
|
||||
|
||||
const row = e.target.closest("tr") as HTMLElement;
|
||||
const row = target.closest("tr") as HTMLElement;
|
||||
const id = row.dataset["id"];
|
||||
if (id === undefined) {
|
||||
throw new Error("Cannot find id of target.");
|
||||
|
|
@ -462,14 +463,15 @@ $(".pageFriends .pendingRequests table").on("click", async (e) => {
|
|||
}
|
||||
});
|
||||
// need to set the listener for action buttons on the table because the table content is getting replaced
|
||||
$(".pageFriends .friends table").on("click", async (e) => {
|
||||
const action = Array.from(e.target.classList).find((it) =>
|
||||
qs(".pageFriends .friends table")?.on("click", async (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const action = Array.from(target.classList).find((it) =>
|
||||
["remove"].includes(it),
|
||||
);
|
||||
|
||||
if (action === undefined) return;
|
||||
|
||||
const row = e.target.closest("tr") as HTMLElement;
|
||||
const row = target.closest("tr") as HTMLElement;
|
||||
const connectionId = row.dataset["connectionId"];
|
||||
if (connectionId === undefined) {
|
||||
throw new Error("Cannot find id of target.");
|
||||
|
|
@ -551,7 +553,7 @@ export const page = new Page<undefined>({
|
|||
},
|
||||
});
|
||||
|
||||
$(() => {
|
||||
onWindowLoad(() => {
|
||||
Skeleton.save("pageFriends");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ import { isSafeNumber } from "@monkeytype/util/numbers";
|
|||
import { Mode, Mode2, ModeSchema } from "@monkeytype/schemas/shared";
|
||||
import * as ServerConfiguration from "../ape/server-configuration";
|
||||
import { getAvatarElement } from "../utils/discord-avatar";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsa, qsr, onWindowLoad } from "../utils/dom";
|
||||
|
||||
const LeaderboardTypeSchema = z.enum(["allTime", "weekly", "daily"]);
|
||||
type LeaderboardType = z.infer<typeof LeaderboardTypeSchema>;
|
||||
|
|
@ -169,32 +169,30 @@ function updateTitle(): void {
|
|||
: "";
|
||||
|
||||
state.title = `${type} ${language} ${mode} ${friend}Leaderboard`;
|
||||
$(".page.pageLeaderboards .bigtitle >.text").text(state.title);
|
||||
qs(".page.pageLeaderboards .bigtitle >.text")?.setText(state.title);
|
||||
|
||||
$(".page.pageLeaderboards .bigtitle .subtext").addClass("hidden");
|
||||
$(".page.pageLeaderboards .bigtitle button").addClass("hidden");
|
||||
$(".page.pageLeaderboards .bigtitle .subtext .divider").addClass("hidden");
|
||||
qs(".page.pageLeaderboards .bigtitle .subtext")?.hide();
|
||||
qsa(".page.pageLeaderboards .bigtitle button")?.hide();
|
||||
qs(".page.pageLeaderboards .bigtitle .subtext .divider")?.hide();
|
||||
|
||||
if (state.type === "daily") {
|
||||
$(".page.pageLeaderboards .bigtitle .subtext").removeClass("hidden");
|
||||
$(
|
||||
qs(".page.pageLeaderboards .bigtitle .subtext")?.show();
|
||||
qs(
|
||||
".page.pageLeaderboards .bigtitle button[data-action='toggleYesterday']",
|
||||
).removeClass("hidden");
|
||||
$(".page.pageLeaderboards .bigtitle .subtext .divider").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
)?.show();
|
||||
qs(".page.pageLeaderboards .bigtitle .subtext .divider")?.show();
|
||||
|
||||
if (state.yesterday) {
|
||||
$(
|
||||
qs(
|
||||
".page.pageLeaderboards .bigtitle button[data-action='toggleYesterday']",
|
||||
).html(`
|
||||
)?.setHtml(`
|
||||
<i class="fas fa-forward"></i>
|
||||
show today
|
||||
`);
|
||||
} else {
|
||||
$(
|
||||
qs(
|
||||
".page.pageLeaderboards .bigtitle button[data-action='toggleYesterday']",
|
||||
).html(`
|
||||
)?.setHtml(`
|
||||
<i class="fas fa-backward"></i>
|
||||
show yesterday
|
||||
`);
|
||||
|
|
@ -211,23 +209,23 @@ function updateTitle(): void {
|
|||
utcToLocalDate(endOfDay(timestamp)),
|
||||
);
|
||||
} else if (state.type === "weekly") {
|
||||
$(".page.pageLeaderboards .bigtitle .subtext").removeClass("hidden");
|
||||
$(
|
||||
qs(".page.pageLeaderboards .bigtitle .subtext")?.show();
|
||||
qs(
|
||||
".page.pageLeaderboards .bigtitle button[data-action='toggleLastWeek']",
|
||||
).removeClass("hidden");
|
||||
$(".page.pageLeaderboards .bigtitle .subtext .divider").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
)?.show();
|
||||
qs(".page.pageLeaderboards .bigtitle .subtext .divider")?.show();
|
||||
|
||||
if (state.lastWeek) {
|
||||
$(".page.pageLeaderboards .bigtitle button[data-action='toggleLastWeek']")
|
||||
.html(`
|
||||
qs(
|
||||
".page.pageLeaderboards .bigtitle button[data-action='toggleLastWeek']",
|
||||
)?.setHtml(`
|
||||
<i class="fas fa-forward"></i>
|
||||
show this week
|
||||
`);
|
||||
} else {
|
||||
$(".page.pageLeaderboards .bigtitle button[data-action='toggleLastWeek']")
|
||||
.html(`
|
||||
qs(
|
||||
".page.pageLeaderboards .bigtitle button[data-action='toggleLastWeek']",
|
||||
)?.setHtml(`
|
||||
<i class="fas fa-backward"></i>
|
||||
show last week
|
||||
`);
|
||||
|
|
@ -391,43 +389,43 @@ async function requestData(update = false): Promise<void> {
|
|||
}
|
||||
|
||||
function updateJumpButtons(): void {
|
||||
const el = $(".page.pageLeaderboards .titleAndButtons .jumpButtons");
|
||||
el.find("button").removeClass("active");
|
||||
const el = qsa(".page.pageLeaderboards .titleAndButtons .jumpButtons");
|
||||
el?.qsa("button")?.removeClass("active");
|
||||
|
||||
const totalPages = Math.ceil(state.count / state.pageSize);
|
||||
|
||||
if (totalPages <= 1) {
|
||||
el.find("button").addClass("disabled");
|
||||
el?.qsa("button")?.disable();
|
||||
} else {
|
||||
el.find("button").removeClass("disabled");
|
||||
el?.qsa("button")?.enable();
|
||||
}
|
||||
|
||||
if (state.page === 0) {
|
||||
el.find("button[data-action='previousPage']").addClass("disabled");
|
||||
el.find("button[data-action='firstPage']").addClass("disabled");
|
||||
el?.qs("button[data-action='previousPage']")?.disable();
|
||||
el?.qs("button[data-action='firstPage']")?.disable();
|
||||
} else {
|
||||
el.find("button[data-action='previousPage']").removeClass("disabled");
|
||||
el.find("button[data-action='firstPage']").removeClass("disabled");
|
||||
el?.qs("button[data-action='previousPage']")?.enable();
|
||||
el?.qs("button[data-action='firstPage']")?.enable();
|
||||
}
|
||||
|
||||
if (isAuthenticated()) {
|
||||
const userButton = el.find("button[data-action='userPage']");
|
||||
const userButton = el?.qs("button[data-action='userPage']");
|
||||
if (!state.userData) {
|
||||
userButton.addClass("disabled");
|
||||
userButton?.disable();
|
||||
} else {
|
||||
const userPage = Math.floor((state.userData.rank - 1) / state.pageSize);
|
||||
if (state.page === userPage) {
|
||||
userButton.addClass("disabled");
|
||||
userButton?.disable();
|
||||
} else {
|
||||
userButton.removeClass("disabled");
|
||||
userButton?.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.page >= totalPages - 1) {
|
||||
el.find("button[data-action='nextPage']").addClass("disabled");
|
||||
el?.qs("button[data-action='nextPage']")?.disable();
|
||||
} else {
|
||||
el.find("button[data-action='nextPage']").removeClass("disabled");
|
||||
el?.qs("button[data-action='nextPage']")?.enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -554,43 +552,41 @@ function buildWeeklyTableRow(
|
|||
}
|
||||
|
||||
function fillTable(): void {
|
||||
const table = $(".page.pageLeaderboards table tbody");
|
||||
table.empty();
|
||||
const table = qs(".page.pageLeaderboards table tbody");
|
||||
table?.empty();
|
||||
|
||||
if (state.friendsOnly) {
|
||||
table.parent().addClass("friendsOnly");
|
||||
table?.getParent()?.addClass("friendsOnly");
|
||||
} else {
|
||||
table.parent().removeClass("friendsOnly");
|
||||
table?.getParent()?.removeClass("friendsOnly");
|
||||
}
|
||||
|
||||
$(".page.pageLeaderboards table thead").addClass("hidden");
|
||||
qsa(".page.pageLeaderboards table thead")?.hide();
|
||||
if (state.type === "allTime" || state.type === "daily") {
|
||||
$(".page.pageLeaderboards table thead.allTimeAndDaily").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
qs(".page.pageLeaderboards table thead.allTimeAndDaily")?.show();
|
||||
} else if (state.type === "weekly") {
|
||||
$(".page.pageLeaderboards table thead.weekly").removeClass("hidden");
|
||||
qs(".page.pageLeaderboards table thead.weekly")?.show();
|
||||
}
|
||||
|
||||
if (state.data === null || state.data.length === 0) {
|
||||
table.append(`<tr><td colspan="7" class="empty">No data</td></tr>`);
|
||||
$(".page.pageLeaderboards table").removeClass("hidden");
|
||||
table?.appendHtml(`<tr><td colspan="7" class="empty">No data</td></tr>`);
|
||||
qs(".page.pageLeaderboards table")?.show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.type === "allTime" || state.type === "daily") {
|
||||
for (const entry of state.data) {
|
||||
const me = getAuthenticatedUser()?.uid === entry.uid;
|
||||
table.append(buildTableRow(entry, me));
|
||||
table?.append(buildTableRow(entry, me));
|
||||
}
|
||||
} else if (state.type === "weekly") {
|
||||
for (const entry of state.data) {
|
||||
const me = getAuthenticatedUser()?.uid === entry.uid;
|
||||
table.append(buildWeeklyTableRow(entry, me));
|
||||
table?.append(buildWeeklyTableRow(entry, me));
|
||||
}
|
||||
}
|
||||
|
||||
$(".page.pageLeaderboards table").removeClass("hidden");
|
||||
qs(".page.pageLeaderboards table")?.show();
|
||||
}
|
||||
|
||||
function getLbMemoryDifference(): number | null {
|
||||
|
|
@ -612,14 +608,14 @@ function getLbMemoryDifference(): number | null {
|
|||
|
||||
function fillUser(): void {
|
||||
if (isAuthenticated() && DB.getSnapshot()?.lbOptOut === true) {
|
||||
$(".page.pageLeaderboards .bigUser").html(
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(
|
||||
'<div class="warning">You have opted out of the leaderboards.</div>',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAuthenticated() && DB.getSnapshot()?.banned === true) {
|
||||
$(".page.pageLeaderboards .bigUser").html(
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(
|
||||
'<div class="warning">Your account is banned</div>',
|
||||
);
|
||||
return;
|
||||
|
|
@ -633,7 +629,7 @@ function fillUser(): void {
|
|||
!isDevEnvironment() &&
|
||||
(DB.getSnapshot()?.typingStats?.timeTyping ?? 0) < minTimeTyping
|
||||
) {
|
||||
$(".page.pageLeaderboards .bigUser").html(
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(
|
||||
`<div class="warning">Your account must have ${formatDuration(
|
||||
intervalToDuration({ start: 0, end: minTimeTyping * 1000 }),
|
||||
)} typed to be placed on the leaderboard.</div>`,
|
||||
|
|
@ -651,14 +647,14 @@ function fillUser(): void {
|
|||
})})`;
|
||||
}
|
||||
|
||||
$(".page.pageLeaderboards .bigUser").html(
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(
|
||||
`<div class="warning">${str}</div>`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAuthenticated() && state.userData === null) {
|
||||
$(".page.pageLeaderboards .bigUser").html(
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(
|
||||
`<div class="warning">Not qualified</div>`,
|
||||
);
|
||||
return;
|
||||
|
|
@ -670,10 +666,8 @@ function fillUser(): void {
|
|||
|
||||
if (state.type === "allTime" || state.type === "daily") {
|
||||
if (!state.userData || !state.count) {
|
||||
$(".page.pageLeaderboards .bigUser").addClass("hidden");
|
||||
$(".page.pageLeaderboards .tableAndUser > .divider").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
qs(".page.pageLeaderboards .bigUser")?.hide();
|
||||
qs(".page.pageLeaderboards .tableAndUser > .divider")?.show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -759,10 +753,10 @@ function fillUser(): void {
|
|||
</div>
|
||||
`;
|
||||
|
||||
$(".page.pageLeaderboards .bigUser").html(html);
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(html);
|
||||
} else if (state.type === "weekly") {
|
||||
if (!state.userData || !state.count) {
|
||||
$(".page.pageLeaderboards .bigUser").addClass("hidden");
|
||||
qs(".page.pageLeaderboards .bigUser")?.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -843,43 +837,43 @@ function fillUser(): void {
|
|||
</div>
|
||||
`;
|
||||
|
||||
$(".page.pageLeaderboards .bigUser").html(html);
|
||||
qs(".page.pageLeaderboards .bigUser")?.setHtml(html);
|
||||
}
|
||||
$(".page.pageLeaderboards .bigUser").removeClass("hidden");
|
||||
$(".page.pageLeaderboards .tableAndUser > .divider").addClass("hidden");
|
||||
qs(".page.pageLeaderboards .bigUser")?.show();
|
||||
qs(".page.pageLeaderboards .tableAndUser > .divider")?.hide();
|
||||
}
|
||||
|
||||
function updateContent(): void {
|
||||
$(".page.pageLeaderboards .loading").addClass("hidden");
|
||||
$(".page.pageLeaderboards .updating").addClass("invisible");
|
||||
$(".page.pageLeaderboards .error").addClass("hidden");
|
||||
qsa(".page.pageLeaderboards .loading").hide();
|
||||
qsa(".page.pageLeaderboards .updating").addClass("invisible");
|
||||
qs(".page.pageLeaderboards .error")?.hide();
|
||||
|
||||
if (state.error !== undefined) {
|
||||
$(".page.pageLeaderboards .error").removeClass("hidden");
|
||||
$(".page.pageLeaderboards .error p").text(state.error);
|
||||
qs(".page.pageLeaderboards .error")?.show();
|
||||
qs(".page.pageLeaderboards .error p")?.setText(state.error);
|
||||
enableButtons();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.updating) {
|
||||
disableButtons();
|
||||
$(".page.pageLeaderboards .updating").removeClass("invisible");
|
||||
qsa(".page.pageLeaderboards .updating").removeClass("invisible");
|
||||
return;
|
||||
} else if (state.loading) {
|
||||
disableButtons();
|
||||
$(".page.pageLeaderboards .bigUser").addClass("hidden");
|
||||
$(".page.pageLeaderboards .titleAndButtons").addClass("hidden");
|
||||
$(".page.pageLeaderboards .loading").removeClass("hidden");
|
||||
$(".page.pageLeaderboards table").addClass("hidden");
|
||||
qs(".page.pageLeaderboards .bigUser")?.hide();
|
||||
qsa(".page.pageLeaderboards .titleAndButtons")?.hide();
|
||||
qsa(".page.pageLeaderboards .loading").show();
|
||||
qs(".page.pageLeaderboards table")?.hide();
|
||||
return;
|
||||
} else {
|
||||
enableButtons();
|
||||
}
|
||||
|
||||
if (isAuthenticated()) {
|
||||
$(".page.pageLeaderboards .needAuth").removeClass("hidden");
|
||||
qsa(".page.pageLeaderboards .needAuth")?.show();
|
||||
} else {
|
||||
$(".page.pageLeaderboards .needAuth").addClass("hidden");
|
||||
qsa(".page.pageLeaderboards .needAuth")?.hide();
|
||||
}
|
||||
|
||||
if (state.data === null) {
|
||||
|
|
@ -887,7 +881,7 @@ function updateContent(): void {
|
|||
return;
|
||||
}
|
||||
|
||||
$(".page.pageLeaderboards .titleAndButtons").removeClass("hidden");
|
||||
qsa(".page.pageLeaderboards .titleAndButtons")?.show();
|
||||
updateJumpButtons();
|
||||
updateTimerVisibility();
|
||||
fillTable();
|
||||
|
|
@ -914,58 +908,56 @@ function updateSideButtons(): void {
|
|||
}
|
||||
|
||||
function updateTypeButtons(): void {
|
||||
const el = $(".page.pageLeaderboards .buttonGroup.typeButtons");
|
||||
el.find("button").removeClass("active");
|
||||
el.find(`button[data-type=${state.type}]`).addClass("active");
|
||||
const el = qs(".page.pageLeaderboards .buttonGroup.typeButtons");
|
||||
el?.qsa("button")?.removeClass("active");
|
||||
el?.qs(`button[data-type=${state.type}]`)?.addClass("active");
|
||||
}
|
||||
|
||||
function updateFriendsButtons(): void {
|
||||
const friendsOnlyGroup = $(
|
||||
const friendsOnlyGroup = qs(
|
||||
".page.pageLeaderboards .buttonGroup.friendsOnlyButtons",
|
||||
);
|
||||
if (
|
||||
isAuthenticated() &&
|
||||
(ServerConfiguration.get()?.connections.enabled ?? false)
|
||||
) {
|
||||
friendsOnlyGroup.removeClass("hidden");
|
||||
friendsOnlyGroup?.show();
|
||||
} else {
|
||||
friendsOnlyGroup.addClass("hidden");
|
||||
friendsOnlyGroup?.hide();
|
||||
state.friendsOnly = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const everyoneButton = $(
|
||||
const everyoneButton = qs(
|
||||
".page.pageLeaderboards .buttonGroup.friendsOnlyButtons .everyone",
|
||||
);
|
||||
const friendsOnlyButton = $(
|
||||
const friendsOnlyButton = qs(
|
||||
".page.pageLeaderboards .buttonGroup.friendsOnlyButtons .friendsOnly",
|
||||
);
|
||||
if (state.friendsOnly) {
|
||||
friendsOnlyButton.addClass("active");
|
||||
everyoneButton.removeClass("active");
|
||||
friendsOnlyButton?.addClass("active");
|
||||
everyoneButton?.removeClass("active");
|
||||
} else {
|
||||
friendsOnlyButton.removeClass("active");
|
||||
everyoneButton.addClass("active");
|
||||
friendsOnlyButton?.removeClass("active");
|
||||
everyoneButton?.addClass("active");
|
||||
}
|
||||
}
|
||||
|
||||
function updateModeButtons(): void {
|
||||
if (state.type !== "allTime" && state.type !== "daily") {
|
||||
$(".page.pageLeaderboards .buttonGroup.modeButtons").addClass("hidden");
|
||||
qs(".page.pageLeaderboards .buttonGroup.modeButtons")?.hide();
|
||||
return;
|
||||
}
|
||||
$(".page.pageLeaderboards .buttonGroup.modeButtons").removeClass("hidden");
|
||||
qs(".page.pageLeaderboards .buttonGroup.modeButtons")?.show();
|
||||
|
||||
const el = $(".page.pageLeaderboards .buttonGroup.modeButtons");
|
||||
el.find("button").removeClass("active");
|
||||
el.find(
|
||||
`button[data-mode=${state.mode}][data-mode2=${state.mode2}]`,
|
||||
).addClass("active");
|
||||
const el = qs(".page.pageLeaderboards .buttonGroup.modeButtons");
|
||||
el?.qsa("button")?.removeClass("active");
|
||||
el?.qs(
|
||||
`button[data-mode="${state.mode}"][data-mode2="${state.mode2}"]`,
|
||||
)?.addClass("active");
|
||||
|
||||
//hide all mode buttons
|
||||
$(`.page.pageLeaderboards .buttonGroup.modeButtons button`).addClass(
|
||||
"hidden",
|
||||
);
|
||||
qsa(`.page.pageLeaderboards .buttonGroup.modeButtons button`)?.hide();
|
||||
|
||||
//show all valid ones
|
||||
for (const mode of Object.keys(validLeaderboards[state.type]) as Mode[]) {
|
||||
|
|
@ -973,37 +965,33 @@ function updateModeButtons(): void {
|
|||
// oxlint-disable-next-line no-non-null-assertion
|
||||
validLeaderboards[state.type][mode]!,
|
||||
)) {
|
||||
$(
|
||||
qs(
|
||||
`.page.pageLeaderboards .buttonGroup.modeButtons button[data-mode="${mode}"][data-mode2="${mode2}"]`,
|
||||
).removeClass("hidden");
|
||||
)?.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateLanguageButtons(): void {
|
||||
if (state.type !== "daily") {
|
||||
$(".page.pageLeaderboards .buttonGroup.languageButtons").addClass("hidden");
|
||||
qs(".page.pageLeaderboards .buttonGroup.languageButtons")?.hide();
|
||||
return;
|
||||
}
|
||||
$(".page.pageLeaderboards .buttonGroup.languageButtons").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
qs(".page.pageLeaderboards .buttonGroup.languageButtons")?.show();
|
||||
|
||||
const el = $(".page.pageLeaderboards .buttonGroup.languageButtons");
|
||||
el.find("button").removeClass("active");
|
||||
el.find(`button[data-language=${state.language}]`).addClass("active");
|
||||
const el = qs(".page.pageLeaderboards .buttonGroup.languageButtons");
|
||||
el?.qsa("button")?.removeClass("active");
|
||||
el?.qs(`button[data-language=${state.language}]`)?.addClass("active");
|
||||
|
||||
//hide all languages
|
||||
$(`.page.pageLeaderboards .buttonGroup.languageButtons button`).addClass(
|
||||
"hidden",
|
||||
);
|
||||
qsa(`.page.pageLeaderboards .buttonGroup.languageButtons button`)?.hide();
|
||||
|
||||
//show all valid ones
|
||||
for (const lang of validLeaderboards[state.type][state.mode]?.[state.mode2] ??
|
||||
[]) {
|
||||
$(
|
||||
qs(
|
||||
`.page.pageLeaderboards .buttonGroup.languageButtons button[data-language="${lang}"]`,
|
||||
).removeClass("hidden");
|
||||
)?.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1013,7 +1001,7 @@ function updateTimerElement(): void {
|
|||
if (state.type === "daily") {
|
||||
const diff = differenceInSeconds(new Date(), endOfDay(new UTCDateMini()));
|
||||
|
||||
$(".page.pageLeaderboards .titleAndButtons .timer").text(
|
||||
qs(".page.pageLeaderboards .titleAndButtons .timer")?.setText(
|
||||
"Next reset in: " + DateTime.secondsToString(diff, true),
|
||||
);
|
||||
} else if (state.type === "allTime") {
|
||||
|
|
@ -1021,13 +1009,13 @@ function updateTimerElement(): void {
|
|||
const minutesToNextUpdate = 14 - (date.getMinutes() % 15);
|
||||
const secondsToNextUpdate = 60 - date.getSeconds();
|
||||
const totalSeconds = minutesToNextUpdate * 60 + secondsToNextUpdate;
|
||||
$(".page.pageLeaderboards .titleAndButtons .timer").text(
|
||||
qs(".page.pageLeaderboards .titleAndButtons .timer")?.setText(
|
||||
"Next update in: " + DateTime.secondsToString(totalSeconds, true),
|
||||
);
|
||||
} else if (state.type === "weekly") {
|
||||
const nextWeekTimestamp = endOfWeek(new UTCDateMini(), { weekStartsOn: 1 });
|
||||
const totalSeconds = differenceInSeconds(new Date(), nextWeekTimestamp);
|
||||
$(".page.pageLeaderboards .titleAndButtons .timer").text(
|
||||
qs(".page.pageLeaderboards .titleAndButtons .timer")?.setText(
|
||||
"Next reset in: " +
|
||||
DateTime.secondsToString(totalSeconds, true, true, ":", true, true),
|
||||
);
|
||||
|
|
@ -1045,11 +1033,11 @@ function updateTimerVisibility(): void {
|
|||
}
|
||||
|
||||
if (visible) {
|
||||
$(".page.pageLeaderboards .titleAndButtons .timer").removeClass(
|
||||
qs(".page.pageLeaderboards .titleAndButtons .timer")?.removeClass(
|
||||
"invisible",
|
||||
);
|
||||
} else {
|
||||
$(".page.pageLeaderboards .titleAndButtons .timer").addClass("invisible");
|
||||
qs(".page.pageLeaderboards .titleAndButtons .timer")?.addClass("invisible");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1063,7 +1051,7 @@ function startTimer(): void {
|
|||
function stopTimer(): void {
|
||||
clearInterval(updateTimer);
|
||||
updateTimer = undefined;
|
||||
$(".page.pageLeaderboards .titleAndButtons .timer").text("-");
|
||||
qs(".page.pageLeaderboards .titleAndButtons .timer")?.setText("-");
|
||||
}
|
||||
|
||||
function convertRuleOption(rule: string): string[] {
|
||||
|
|
@ -1183,7 +1171,7 @@ async function appendModeAndLanguageButtons(): Promise<void> {
|
|||
</button>`,
|
||||
);
|
||||
});
|
||||
$(".modeButtons").html(
|
||||
qs(".modeButtons")?.setHtml(
|
||||
`<div class="divider"></div>` + mode2Buttons.join("\n"),
|
||||
);
|
||||
|
||||
|
|
@ -1203,17 +1191,17 @@ async function appendModeAndLanguageButtons(): Promise<void> {
|
|||
${lang}
|
||||
</button>`,
|
||||
);
|
||||
$(".languageButtons").html(
|
||||
qs(".languageButtons")?.setHtml(
|
||||
`<div class="divider"></div>` + languageButtons.join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
function disableButtons(): void {
|
||||
$(".page.pageLeaderboards button").prop("disabled", true);
|
||||
qsa(".page.pageLeaderboards button")?.disable();
|
||||
}
|
||||
|
||||
function enableButtons(): void {
|
||||
$(".page.pageLeaderboards button").prop("disabled", false);
|
||||
qsa(".page.pageLeaderboards button")?.enable();
|
||||
}
|
||||
|
||||
export function goToPage(pageId: number): void {
|
||||
|
|
@ -1373,9 +1361,9 @@ function updateTimeText(
|
|||
" - \n" +
|
||||
format(localEnd, localDateFormat);
|
||||
|
||||
const text = $(".page.pageLeaderboards .bigtitle .subtext > .text");
|
||||
text.text(`${dateString}`);
|
||||
text.attr("aria-label", localDateString);
|
||||
const text = qs(".page.pageLeaderboards .bigtitle .subtext > .text");
|
||||
text?.setText(`${dateString}`);
|
||||
text?.setAttribute("aria-label", localDateString);
|
||||
}
|
||||
|
||||
function formatRank(rank: number | undefined): string {
|
||||
|
|
@ -1385,23 +1373,26 @@ function formatRank(rank: number | undefined): string {
|
|||
return rank.toString();
|
||||
}
|
||||
|
||||
$(".page.pageLeaderboards .jumpButtons button").on("click", function () {
|
||||
const action = $(this).data("action") as Action;
|
||||
qsa(".page.pageLeaderboards .jumpButtons button")?.on("click", function () {
|
||||
const action = this.getAttribute("data-action") as Action;
|
||||
if (action !== "goToPage") {
|
||||
handleJumpButton(action);
|
||||
}
|
||||
});
|
||||
|
||||
$(".page.pageLeaderboards .bigtitle button").on("click", function () {
|
||||
const action = $(this).data("action") as string;
|
||||
qsa(".page.pageLeaderboards .bigtitle button")?.on("click", function () {
|
||||
const action = this.getAttribute("data-action") as string;
|
||||
handleYesterdayLastWeekButton(action);
|
||||
});
|
||||
|
||||
$(".page.pageLeaderboards .buttonGroup.typeButtons").on(
|
||||
qs(".page.pageLeaderboards .buttonGroup.typeButtons")?.onChild(
|
||||
"click",
|
||||
"button",
|
||||
function () {
|
||||
const type = $(this).data("type") as "allTime" | "weekly" | "daily";
|
||||
const type = this.getAttribute("data-type") as
|
||||
| "allTime"
|
||||
| "weekly"
|
||||
| "daily";
|
||||
if (state.type === type) return;
|
||||
state.type = type;
|
||||
if (state.type === "daily") {
|
||||
|
|
@ -1422,16 +1413,17 @@ $(".page.pageLeaderboards .buttonGroup.typeButtons").on(
|
|||
},
|
||||
);
|
||||
|
||||
$(".page.pageLeaderboards .buttonGroup.modeButtons").on(
|
||||
qs(".page.pageLeaderboards .buttonGroup.modeButtons")?.onChild(
|
||||
"click",
|
||||
"button",
|
||||
function () {
|
||||
const mode = $(this).attr("data-mode") as Mode;
|
||||
const mode2 = $(this).attr("data-mode2");
|
||||
const mode = this.getAttribute("data-mode") as Mode;
|
||||
const mode2 = this.getAttribute("data-mode2");
|
||||
|
||||
if (
|
||||
mode !== undefined &&
|
||||
mode2 !== undefined &&
|
||||
mode2 !== null &&
|
||||
(state.type === "allTime" || state.type === "daily")
|
||||
) {
|
||||
if (state.mode === mode && state.mode2 === mode2) return;
|
||||
|
|
@ -1451,11 +1443,11 @@ $(".page.pageLeaderboards .buttonGroup.modeButtons").on(
|
|||
},
|
||||
);
|
||||
|
||||
$(".page.pageLeaderboards .buttonGroup.languageButtons").on(
|
||||
qs(".page.pageLeaderboards .buttonGroup.languageButtons")?.onChild(
|
||||
"click",
|
||||
"button",
|
||||
function () {
|
||||
const language = $(this).attr("data-language") as Language;
|
||||
const language = this.getAttribute("data-language") as Language;
|
||||
|
||||
if (language !== undefined && state.type === "daily") {
|
||||
if (state.language === language) return;
|
||||
|
|
@ -1474,7 +1466,7 @@ $(".page.pageLeaderboards .buttonGroup.languageButtons").on(
|
|||
},
|
||||
);
|
||||
|
||||
$(".page.pageLeaderboards .buttonGroup.friendsOnlyButtons").on(
|
||||
qs(".page.pageLeaderboards .buttonGroup.friendsOnlyButtons")?.onChild(
|
||||
"click",
|
||||
"button",
|
||||
() => {
|
||||
|
|
@ -1517,7 +1509,7 @@ export const page = new PageWithUrlParams({
|
|||
},
|
||||
});
|
||||
|
||||
$(async () => {
|
||||
onWindowLoad(async () => {
|
||||
Skeleton.save("pageLeaderboards");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,47 +1,46 @@
|
|||
import Page from "./page";
|
||||
import * as Skeleton from "../utils/skeleton";
|
||||
import { promiseAnimate } from "../utils/misc";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsr } from "../utils/dom";
|
||||
|
||||
const pageEl = $(".page.pageLoading");
|
||||
const barEl = pageEl.find(".bar");
|
||||
const errorEl = pageEl.find(".error");
|
||||
const spinnerEl = pageEl.find(".spinner");
|
||||
const textEl = pageEl.find(".text");
|
||||
const pageEl = qs(".page.pageLoading");
|
||||
const barEl = pageEl?.qs(".bar");
|
||||
const errorEl = pageEl?.qs(".error");
|
||||
const spinnerEl = pageEl?.qs(".spinner");
|
||||
const textEl = pageEl?.qs(".text");
|
||||
|
||||
export async function updateBar(
|
||||
percentage: number,
|
||||
duration: number,
|
||||
): Promise<void> {
|
||||
await promiseAnimate(barEl[0]?.querySelector(".fill") as HTMLElement, {
|
||||
await barEl?.qs(".fill")?.promiseAnimate({
|
||||
width: percentage + "%",
|
||||
duration,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateText(text: string): void {
|
||||
textEl.removeClass("hidden").html(text);
|
||||
textEl?.show()?.setHtml(text);
|
||||
}
|
||||
|
||||
export function showSpinner(): void {
|
||||
barEl.addClass("hidden");
|
||||
errorEl.addClass("hidden");
|
||||
spinnerEl.removeClass("hidden");
|
||||
textEl.addClass("hidden");
|
||||
barEl?.hide();
|
||||
errorEl?.hide();
|
||||
spinnerEl?.show();
|
||||
textEl?.hide();
|
||||
}
|
||||
|
||||
export function showError(): void {
|
||||
barEl.addClass("hidden");
|
||||
spinnerEl.addClass("hidden");
|
||||
errorEl.removeClass("hidden");
|
||||
textEl.addClass("hidden");
|
||||
barEl?.hide();
|
||||
spinnerEl?.hide();
|
||||
errorEl?.show();
|
||||
textEl?.hide();
|
||||
}
|
||||
|
||||
export async function showBar(): Promise<void> {
|
||||
barEl.removeClass("hidden");
|
||||
errorEl.addClass("hidden");
|
||||
spinnerEl.addClass("hidden");
|
||||
textEl.addClass("hidden");
|
||||
barEl?.show();
|
||||
errorEl?.hide();
|
||||
spinnerEl?.hide();
|
||||
textEl?.hide();
|
||||
}
|
||||
|
||||
export const page = new Page({
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { ValidatedHtmlInputElement } from "../elements/input-validation";
|
|||
import { isDevEnvironment } from "../utils/misc";
|
||||
import { z } from "zod";
|
||||
import { remoteValidation } from "../utils/remote-validation";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsa, qsr, onWindowLoad } from "../utils/dom";
|
||||
|
||||
let registerForm: {
|
||||
name?: string;
|
||||
|
|
@ -20,29 +20,29 @@ let registerForm: {
|
|||
} = {};
|
||||
|
||||
export function enableSignUpButton(): void {
|
||||
$(".page.pageLogin .register.side button").prop("disabled", false);
|
||||
qs(".page.pageLogin .register.side button")?.enable();
|
||||
}
|
||||
|
||||
export function disableSignUpButton(): void {
|
||||
$(".page.pageLogin .register.side button").prop("disabled", true);
|
||||
qs(".page.pageLogin .register.side button")?.disable();
|
||||
}
|
||||
|
||||
export function enableInputs(): void {
|
||||
$(".pageLogin input").prop("disabled", false);
|
||||
$(".pageLogin button").prop("disabled", false);
|
||||
qsa(".pageLogin input")?.enable();
|
||||
qsa(".pageLogin button")?.enable();
|
||||
}
|
||||
|
||||
export function disableInputs(): void {
|
||||
$(".pageLogin input").prop("disabled", true);
|
||||
$(".pageLogin button").prop("disabled", true);
|
||||
qsa(".pageLogin input")?.disable();
|
||||
qsa(".pageLogin button")?.disable();
|
||||
}
|
||||
|
||||
export function showPreloader(): void {
|
||||
$(".pageLogin .preloader").removeClass("hidden");
|
||||
qs(".pageLogin .preloader")?.show();
|
||||
}
|
||||
|
||||
export function hidePreloader(): void {
|
||||
$(".pageLogin .preloader").addClass("hidden");
|
||||
qs(".pageLogin .preloader")?.hide();
|
||||
}
|
||||
|
||||
function isFormComplete(): boolean {
|
||||
|
|
@ -217,13 +217,16 @@ export const page = new Page({
|
|||
beforeShow: async (): Promise<void> => {
|
||||
Skeleton.append("pageLogin", "main");
|
||||
registerForm = {};
|
||||
$(".pageLogin input").val("");
|
||||
$(".pageLogin .register .indicator").addClass("hidden");
|
||||
const inputs = qsa<HTMLInputElement>(".pageLogin input");
|
||||
inputs.forEach((input) => {
|
||||
input.setValue("");
|
||||
});
|
||||
qsa(".pageLogin .register .indicator")?.hide();
|
||||
enableInputs();
|
||||
disableSignUpButton();
|
||||
},
|
||||
});
|
||||
|
||||
$(() => {
|
||||
onWindowLoad(() => {
|
||||
Skeleton.save("pageLogin");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,17 +5,17 @@ import { ValidatedHtmlInputElement } from "../elements/input-validation";
|
|||
import { UserNameSchema, UserProfile } from "@monkeytype/schemas/users";
|
||||
import { remoteValidation } from "../utils/remote-validation";
|
||||
import * as NavigationEvent from "../observables/navigation-event";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsr, onWindowLoad } from "../utils/dom";
|
||||
|
||||
let nameInputEl: ValidatedHtmlInputElement | null = null;
|
||||
let lastProfile: UserProfile | null = null;
|
||||
|
||||
function enableButton(): void {
|
||||
$('.page.pageProfileSearch button[type="submit"]').prop("disabled", false);
|
||||
qs('.page.pageProfileSearch button[type="submit"]')?.enable();
|
||||
}
|
||||
|
||||
function disableButton(): void {
|
||||
$('.page.pageProfileSearch button[type="submit"]').prop("disabled", true);
|
||||
qs('.page.pageProfileSearch button[type="submit"]')?.disable();
|
||||
}
|
||||
|
||||
export const page = new Page({
|
||||
|
|
@ -57,11 +57,11 @@ export const page = new Page({
|
|||
disableButton();
|
||||
},
|
||||
afterShow: async (): Promise<void> => {
|
||||
$(".page.pageProfileSearch input").trigger("focus");
|
||||
qs(".page.pageProfileSearch input")?.dispatch("focus");
|
||||
},
|
||||
});
|
||||
|
||||
$(".page.pageProfileSearch form").on("submit", (e) => {
|
||||
qs(".page.pageProfileSearch form")?.on("submit", (e) => {
|
||||
e.preventDefault();
|
||||
if (lastProfile === null) return;
|
||||
NavigationEvent.dispatch(`/profile/${lastProfile.name}`, {
|
||||
|
|
@ -69,6 +69,6 @@ $(".page.pageProfileSearch form").on("submit", (e) => {
|
|||
});
|
||||
});
|
||||
|
||||
$(() => {
|
||||
onWindowLoad(() => {
|
||||
Skeleton.save("pageProfileSearch");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ import * as TestActivity from "../elements/test-activity";
|
|||
import { TestActivityCalendar } from "../elements/test-activity-calendar";
|
||||
import { getFirstDayOfTheWeek } from "../utils/date-and-time";
|
||||
import { addFriend } from "./friends";
|
||||
import { qsr } from "../utils/dom";
|
||||
import { qs, qsr } from "../utils/dom";
|
||||
|
||||
const firstDayOfTheWeek = getFirstDayOfTheWeek();
|
||||
|
||||
function reset(): void {
|
||||
$(".page.pageProfile .error").addClass("hidden");
|
||||
$(".page.pageProfile .preloader").removeClass("hidden");
|
||||
$(".page.pageProfile .profile").html(`
|
||||
qs(".page.pageProfile .error")?.hide();
|
||||
qs(".page.pageProfile .preloader")?.show();
|
||||
qs(".page.pageProfile .profile")?.setHtml(`
|
||||
<div class="details none">
|
||||
<div class="avatarAndName">
|
||||
<div class="avatar"></div>
|
||||
|
|
@ -182,7 +182,7 @@ type UpdateOptions = {
|
|||
async function update(options: UpdateOptions): Promise<void> {
|
||||
const getParamExists = checkIfGetParameterExists("isUid");
|
||||
if (options.data) {
|
||||
$(".page.pageProfile .preloader").addClass("hidden");
|
||||
qs(".page.pageProfile .preloader")?.hide();
|
||||
await Profile.update("profile", options.data);
|
||||
PbTables.update(
|
||||
// this cast is fine because pb tables can handle the partial data inside user profiles
|
||||
|
|
@ -195,15 +195,15 @@ async function update(options: UpdateOptions): Promise<void> {
|
|||
query: { isUid: getParamExists },
|
||||
});
|
||||
|
||||
$(".page.pageProfile .preloader").addClass("hidden");
|
||||
qs(".page.pageProfile .preloader")?.hide();
|
||||
|
||||
if (response.status === 404) {
|
||||
const message = getParamExists
|
||||
? "User not found"
|
||||
: `User ${options.uidOrName} not found`;
|
||||
$(".page.pageProfile .preloader").addClass("hidden");
|
||||
$(".page.pageProfile .error").removeClass("hidden");
|
||||
$(".page.pageProfile .error .message").text(message);
|
||||
qs(".page.pageProfile .preloader")?.hide();
|
||||
qs(".page.pageProfile .error")?.show();
|
||||
qs(".page.pageProfile .error .message")?.setText(message);
|
||||
} else if (response.status === 200) {
|
||||
const profile = response.body.data;
|
||||
window.history.replaceState(null, "", `/profile/${profile.name}`);
|
||||
|
|
@ -228,7 +228,7 @@ async function update(options: UpdateOptions): Promise<void> {
|
|||
TestActivity.clear(testActivity);
|
||||
}
|
||||
} else {
|
||||
// $(".page.pageProfile .failedToLoad").removeClass("hidden");
|
||||
// qs(".page.pageProfile .failedToLoad")?.show();
|
||||
Notifications.add("Failed to load profile: " + response.body.message, -1);
|
||||
return;
|
||||
}
|
||||
|
|
@ -237,27 +237,33 @@ async function update(options: UpdateOptions): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
$(".page.pageProfile").on("click", ".profile .userReportButton", () => {
|
||||
const uid = $(".page.pageProfile .profile").attr("uid") ?? "";
|
||||
const name = $(".page.pageProfile .profile").attr("name") ?? "";
|
||||
qs(".page.pageProfile")?.onChild("click", ".profile .userReportButton", () => {
|
||||
const uid = qs(".page.pageProfile .profile")?.getAttribute("uid") ?? "";
|
||||
const name = qs(".page.pageProfile .profile")?.getAttribute("name") ?? "";
|
||||
const lbOptOut =
|
||||
($(".page.pageProfile .profile").attr("lbOptOut") ?? "false") === "true";
|
||||
(qs(".page.pageProfile .profile")?.getAttribute("lbOptOut") ?? "false") ===
|
||||
"true";
|
||||
|
||||
void UserReportModal.show({ uid, name, lbOptOut });
|
||||
});
|
||||
|
||||
$(".page.pageProfile").on("click", ".profile .addFriendButton", async () => {
|
||||
const friendName = $(".page.pageProfile .profile").attr("name") ?? "";
|
||||
qs(".page.pageProfile")?.onChild(
|
||||
"click",
|
||||
".profile .addFriendButton",
|
||||
async () => {
|
||||
const friendName =
|
||||
qs(".page.pageProfile .profile")?.getAttribute("name") ?? "";
|
||||
|
||||
const result = await addFriend(friendName);
|
||||
const result = await addFriend(friendName);
|
||||
|
||||
if (result === true) {
|
||||
Notifications.add(`Request sent to ${friendName}`);
|
||||
$(".profile .details .addFriendButton").addClass("disabled");
|
||||
} else {
|
||||
Notifications.add(result, -1);
|
||||
}
|
||||
});
|
||||
if (result === true) {
|
||||
Notifications.add(`Request sent to ${friendName}`);
|
||||
qs(".profile .details .addFriendButton")?.disable();
|
||||
} else {
|
||||
Notifications.add(result, -1);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export const page = new Page<undefined | UserProfile>({
|
||||
id: "profile",
|
||||
|
|
@ -271,18 +277,18 @@ export const page = new Page<undefined | UserProfile>({
|
|||
Skeleton.append("pageProfile", "main");
|
||||
const uidOrName = options?.params?.["uidOrName"] ?? "";
|
||||
if (uidOrName) {
|
||||
$(".page.pageProfile .preloader").removeClass("hidden");
|
||||
$(".page.pageProfile .search").addClass("hidden");
|
||||
$(".page.pageProfile .content").removeClass("hidden");
|
||||
qs(".page.pageProfile .preloader")?.show();
|
||||
qs(".page.pageProfile .search")?.hide();
|
||||
qs(".page.pageProfile .content")?.show();
|
||||
reset();
|
||||
void update({
|
||||
uidOrName,
|
||||
data: options?.data,
|
||||
});
|
||||
} else {
|
||||
$(".page.pageProfile .preloader").addClass("hidden");
|
||||
$(".page.pageProfile .search").removeClass("hidden");
|
||||
$(".page.pageProfile .content").addClass("hidden");
|
||||
qs(".page.pageProfile .preloader")?.hide();
|
||||
qs(".page.pageProfile .search")?.show();
|
||||
qs(".page.pageProfile .content")?.hide();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import * as CustomBackgroundPicker from "../elements/settings/custom-background-
|
|||
import * as CustomFontPicker from "../elements/settings/custom-font-picker";
|
||||
import * as AuthEvent from "../observables/auth-event";
|
||||
import * as FpsLimitSection from "../elements/settings/fps-limit-section";
|
||||
import { qs, qsr } from "../utils/dom";
|
||||
import { qs, qsa, qsr, onWindowLoad } from "../utils/dom";
|
||||
|
||||
let settingsInitialized = false;
|
||||
|
||||
|
|
@ -83,37 +83,25 @@ async function initGroups(): Promise<void> {
|
|||
groups["keymapMode"] = new SettingsGroup("keymapMode", "button", {
|
||||
updateCallback: () => {
|
||||
if (Config.keymapMode === "off") {
|
||||
$(".pageSettings .section[data-config-name='keymapStyle']").addClass(
|
||||
"hidden",
|
||||
);
|
||||
$(".pageSettings .section[data-config-name='keymapLayout']").addClass(
|
||||
"hidden",
|
||||
);
|
||||
$(
|
||||
qs(".pageSettings .section[data-config-name='keymapStyle']")?.hide();
|
||||
qs(".pageSettings .section[data-config-name='keymapLayout']")?.hide();
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapLegendStyle']",
|
||||
).addClass("hidden");
|
||||
$(
|
||||
)?.hide();
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapShowTopRow']",
|
||||
).addClass("hidden");
|
||||
$(".pageSettings .section[data-config-name='keymapSize']").addClass(
|
||||
"hidden",
|
||||
);
|
||||
)?.hide();
|
||||
qs(".pageSettings .section[data-config-name='keymapSize']")?.hide();
|
||||
} else {
|
||||
$(".pageSettings .section[data-config-name='keymapStyle']").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
$(
|
||||
".pageSettings .section[data-config-name='keymapLayout']",
|
||||
).removeClass("hidden");
|
||||
$(
|
||||
qs(".pageSettings .section[data-config-name='keymapStyle']")?.show();
|
||||
qs(".pageSettings .section[data-config-name='keymapLayout']")?.show();
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapLegendStyle']",
|
||||
).removeClass("hidden");
|
||||
$(
|
||||
)?.show();
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapShowTopRow']",
|
||||
).removeClass("hidden");
|
||||
$(".pageSettings .section[data-config-name='keymapSize']").removeClass(
|
||||
"hidden",
|
||||
);
|
||||
)?.show();
|
||||
qs(".pageSettings .section[data-config-name='keymapSize']")?.show();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -226,19 +214,21 @@ async function initGroups(): Promise<void> {
|
|||
groups["timerColor"] = new SettingsGroup("timerColor", "button");
|
||||
groups["fontFamily"] = new SettingsGroup("fontFamily", "button", {
|
||||
updateCallback: () => {
|
||||
const customButton = $(
|
||||
const customButton = qs(
|
||||
".pageSettings .section[data-config-name='fontFamily'] .buttons button[data-config-value='custom']",
|
||||
);
|
||||
|
||||
if (
|
||||
$(
|
||||
qsa(
|
||||
".pageSettings .section[data-config-name='fontFamily'] .buttons .active",
|
||||
).length === 0
|
||||
) {
|
||||
customButton.addClass("active");
|
||||
customButton.text(`Custom (${Config.fontFamily.replace(/_/g, " ")})`);
|
||||
customButton?.addClass("active");
|
||||
customButton?.setText(
|
||||
`Custom (${Config.fontFamily.replace(/_/g, " ")})`,
|
||||
);
|
||||
} else {
|
||||
customButton.text("Custom");
|
||||
customButton?.setText("Custom");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -482,11 +472,11 @@ async function fillSettingsPage(): Promise<void> {
|
|||
// export let settingsFillPromise = fillSettingsPage();
|
||||
|
||||
export function hideAccountSection(): void {
|
||||
$(`.pageSettings .section.needsAccount`).addClass("hidden");
|
||||
qsa(`.pageSettings .section.needsAccount`)?.hide();
|
||||
}
|
||||
|
||||
function showAccountSection(): void {
|
||||
$(`.pageSettings .section.needsAccount`).removeClass("hidden");
|
||||
qsa(`.pageSettings .section.needsAccount`)?.show();
|
||||
refreshTagsSettingsSection();
|
||||
refreshPresetsSettingsSection();
|
||||
}
|
||||
|
|
@ -519,13 +509,13 @@ function setActiveFunboxButton(): void {
|
|||
|
||||
function refreshTagsSettingsSection(): void {
|
||||
if (isAuthenticated() && DB.getSnapshot()) {
|
||||
const tagsEl = $(".pageSettings .section.tags .tagsList").empty();
|
||||
const tagsEl = qs(".pageSettings .section.tags .tagsList")?.empty();
|
||||
DB.getSnapshot()?.tags?.forEach((tag) => {
|
||||
// let tagPbString = "No PB found";
|
||||
// if (tag.pb !== undefined && tag.pb > 0) {
|
||||
// tagPbString = `PB: ${tag.pb}`;
|
||||
// }
|
||||
tagsEl.append(`
|
||||
tagsEl?.appendHtml(`
|
||||
|
||||
<div class="buttons tag" data-id="${tag._id}" data-name="${
|
||||
tag.name
|
||||
|
|
@ -548,17 +538,19 @@ function refreshTagsSettingsSection(): void {
|
|||
|
||||
`);
|
||||
});
|
||||
$(".pageSettings .section.tags").removeClass("hidden");
|
||||
qs(".pageSettings .section.tags")?.show();
|
||||
} else {
|
||||
$(".pageSettings .section.tags").addClass("hidden");
|
||||
qs(".pageSettings .section.tags")?.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function refreshPresetsSettingsSection(): void {
|
||||
if (isAuthenticated() && DB.getSnapshot()) {
|
||||
const presetsEl = $(".pageSettings .section.presets .presetsList").empty();
|
||||
const presetsEl = qs(
|
||||
".pageSettings .section.presets .presetsList",
|
||||
)?.empty();
|
||||
DB.getSnapshot()?.presets?.forEach((preset: SnapshotPreset) => {
|
||||
presetsEl.append(`
|
||||
presetsEl?.appendHtml(`
|
||||
<div class="buttons preset" data-id="${preset._id}" data-name="${preset.name}" data-display="${preset.display}">
|
||||
<button class="presetButton">${preset.display}</button>
|
||||
<button class="editButton">
|
||||
|
|
@ -571,9 +563,9 @@ function refreshPresetsSettingsSection(): void {
|
|||
|
||||
`);
|
||||
});
|
||||
$(".pageSettings .section.presets").removeClass("hidden");
|
||||
qs(".pageSettings .section.presets")?.show();
|
||||
} else {
|
||||
$(".pageSettings .section.presets").addClass("hidden");
|
||||
qs(".pageSettings .section.presets")?.hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -581,16 +573,16 @@ export async function updateFilterSectionVisibility(): Promise<void> {
|
|||
const hasBackgroundUrl =
|
||||
Config.customBackground !== "" ||
|
||||
(await FileStorage.hasFile("LocalBackgroundFile"));
|
||||
const isImageVisible = $(".customBackground img").is(":visible");
|
||||
const isImageVisible = qs(".customBackground img")?.isVisible();
|
||||
|
||||
if (hasBackgroundUrl && isImageVisible) {
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='customBackgroundFilter']",
|
||||
).removeClass("hidden");
|
||||
)?.show();
|
||||
} else {
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='customBackgroundFilter']",
|
||||
).addClass("hidden");
|
||||
)?.hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -604,9 +596,9 @@ export async function update(
|
|||
}
|
||||
|
||||
if (Config.showKeyTips) {
|
||||
$(".pageSettings .tip").removeClass("hidden");
|
||||
qs(".pageSettings .tip")?.show();
|
||||
} else {
|
||||
$(".pageSettings .tip").addClass("hidden");
|
||||
qs(".pageSettings .tip")?.hide();
|
||||
}
|
||||
|
||||
for (const group of Object.values(groups)) {
|
||||
|
|
@ -674,13 +666,13 @@ export async function update(
|
|||
);
|
||||
|
||||
if (Config.autoSwitchTheme) {
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='autoSwitchThemeInputs']",
|
||||
).removeClass("hidden");
|
||||
)?.show();
|
||||
} else {
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='autoSwitchThemeInputs']",
|
||||
).addClass("hidden");
|
||||
)?.hide();
|
||||
}
|
||||
|
||||
setInputValue(
|
||||
|
|
@ -728,7 +720,7 @@ export async function update(
|
|||
: "ctrl";
|
||||
|
||||
const commandKey = Config.quickRestart === "esc" ? "tab" : "esc";
|
||||
$(".pageSettings .tip").html(`
|
||||
qs(".pageSettings .tip")?.setHtml(`
|
||||
tip: You can also change all these settings quickly using the
|
||||
command line (<key>${commandKey}</key> or <key>${modifierKey}</key> + <key>shift</key> + <key>p</key>)`);
|
||||
|
||||
|
|
@ -788,44 +780,45 @@ function toggleSettingsGroup(groupName: string): void {
|
|||
}
|
||||
|
||||
//funbox
|
||||
$(".pageSettings .section[data-config-name='funbox'] .buttons").on(
|
||||
qs(".pageSettings .section[data-config-name='funbox'] .buttons")?.onChild(
|
||||
"click",
|
||||
"button",
|
||||
(e) => {
|
||||
const funbox = $(e.currentTarget).attr("data-config-value") as FunboxName;
|
||||
const target = e.childTarget as HTMLElement;
|
||||
const funbox = target?.getAttribute("data-config-value") as FunboxName;
|
||||
Funbox.toggleFunbox(funbox);
|
||||
setActiveFunboxButton();
|
||||
},
|
||||
);
|
||||
|
||||
//tags
|
||||
$(".pageSettings .section.tags").on(
|
||||
qs(".pageSettings .section.tags")?.onChild(
|
||||
"click",
|
||||
".tagsList .tag .tagButton",
|
||||
(e) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
const tagid = $(target).parent(".tag").attr("data-id") as string;
|
||||
const target = e.childTarget as HTMLElement;
|
||||
const tagid = target.parentElement?.getAttribute("data-id") as string;
|
||||
TagController.toggle(tagid);
|
||||
$(target).toggleClass("active");
|
||||
target.classList.toggle("active");
|
||||
},
|
||||
);
|
||||
|
||||
$(".pageSettings .section.presets").on(
|
||||
qs(".pageSettings .section.presets")?.onChild(
|
||||
"click",
|
||||
".presetsList .preset .presetButton",
|
||||
async (e) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
const presetid = $(target).parent(".preset").attr("data-id") as string;
|
||||
const target = e.childTarget as HTMLElement;
|
||||
const presetid = target.parentElement?.getAttribute("data-id") as string;
|
||||
await PresetController.apply(presetid);
|
||||
void update();
|
||||
},
|
||||
);
|
||||
|
||||
$("#importSettingsButton").on("click", () => {
|
||||
qs("#importSettingsButton")?.on("click", () => {
|
||||
ImportExportSettingsModal.show("import");
|
||||
});
|
||||
|
||||
$("#exportSettingsButton").on("click", () => {
|
||||
qs("#exportSettingsButton")?.on("click", () => {
|
||||
const configJSON = JSON.stringify(Config);
|
||||
navigator.clipboard.writeText(configJSON).then(
|
||||
function () {
|
||||
|
|
@ -837,19 +830,20 @@ $("#exportSettingsButton").on("click", () => {
|
|||
);
|
||||
});
|
||||
|
||||
$(".pageSettings .sectionGroupTitle").on("click", (e) => {
|
||||
toggleSettingsGroup($(e.currentTarget).attr("group") as string);
|
||||
qsa(".pageSettings .sectionGroupTitle")?.on("click", (e) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
toggleSettingsGroup(target.getAttribute("group") as string);
|
||||
});
|
||||
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapSize'] .inputAndButton button.save",
|
||||
).on("click", () => {
|
||||
)?.on("click", () => {
|
||||
const didConfigSave = setConfig(
|
||||
"keymapSize",
|
||||
parseFloat(
|
||||
$(
|
||||
qs<HTMLInputElement>(
|
||||
".pageSettings .section[data-config-name='keymapSize'] .inputAndButton input",
|
||||
).val() as string,
|
||||
)?.getValue() as string,
|
||||
),
|
||||
);
|
||||
if (didConfigSave) {
|
||||
|
|
@ -859,15 +853,15 @@ $(
|
|||
}
|
||||
});
|
||||
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapSize'] .inputAndButton input",
|
||||
).on("focusout", () => {
|
||||
)?.on("focusout", () => {
|
||||
const didConfigSave = setConfig(
|
||||
"keymapSize",
|
||||
parseFloat(
|
||||
$(
|
||||
qs<HTMLInputElement>(
|
||||
".pageSettings .section[data-config-name='keymapSize'] .inputAndButton input",
|
||||
).val() as string,
|
||||
)?.getValue() as string,
|
||||
),
|
||||
);
|
||||
if (didConfigSave) {
|
||||
|
|
@ -877,16 +871,16 @@ $(
|
|||
}
|
||||
});
|
||||
|
||||
$(
|
||||
qs(
|
||||
".pageSettings .section[data-config-name='keymapSize'] .inputAndButton input",
|
||||
).on("keypress", (e) => {
|
||||
)?.on("keypress", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
const didConfigSave = setConfig(
|
||||
"keymapSize",
|
||||
parseFloat(
|
||||
$(
|
||||
qs<HTMLInputElement>(
|
||||
".pageSettings .section[data-config-name='keymapSize'] .inputAndButton input",
|
||||
).val() as string,
|
||||
)?.getValue() as string,
|
||||
),
|
||||
);
|
||||
if (didConfigSave) {
|
||||
|
|
@ -897,11 +891,12 @@ $(
|
|||
}
|
||||
});
|
||||
|
||||
$(".pageSettings .quickNav .links a").on("click", (e) => {
|
||||
const settingsGroup = e.target.innerText;
|
||||
const isClosed = $(`.pageSettings .settingsGroup.${settingsGroup}`).hasClass(
|
||||
"slideup",
|
||||
);
|
||||
qsa(".pageSettings .quickNav .links a")?.on("click", (e) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
const settingsGroup = target.innerText;
|
||||
const isClosed = qs(
|
||||
`.pageSettings .settingsGroup.${settingsGroup}`,
|
||||
)?.hasClass("slideup");
|
||||
if (isClosed) {
|
||||
toggleSettingsGroup(settingsGroup);
|
||||
}
|
||||
|
|
@ -972,8 +967,9 @@ function handleHighlightSection(highlight: Highlight | undefined): void {
|
|||
}
|
||||
}
|
||||
|
||||
$(".pageSettings .section .groupTitle button").on("click", (e) => {
|
||||
const section = e.target.parentElement?.parentElement;
|
||||
qsa(".pageSettings .section .groupTitle button")?.on("click", (e) => {
|
||||
const target = e.currentTarget as HTMLElement;
|
||||
const section = target.parentElement?.parentElement;
|
||||
const configName = (section?.dataset?.["configName"] ??
|
||||
section?.dataset?.["sectionId"]) as Highlight | undefined;
|
||||
if (configName === undefined) {
|
||||
|
|
@ -997,13 +993,13 @@ ConfigEvent.subscribe(({ key, newValue }) => {
|
|||
if (key === "fullConfigChange") setEventDisabled(true);
|
||||
if (key === "fullConfigChangeFinished") setEventDisabled(false);
|
||||
if (key === "themeLight") {
|
||||
$(
|
||||
qs(
|
||||
`.pageSettings .section[data-config-name='autoSwitchThemeInputs'] select.light option[value="${newValue}"]`,
|
||||
).attr("selected", "true");
|
||||
)?.setAttribute("selected", "true");
|
||||
} else if (key === "themeDark") {
|
||||
$(
|
||||
qs(
|
||||
`.pageSettings .section[data-config-name='autoSwitchThemeInputs'] select.dark option[value="${newValue}"]`,
|
||||
).attr("selected", "true");
|
||||
)?.setAttribute("selected", "true");
|
||||
}
|
||||
//make sure the page doesnt update a billion times when applying a preset/config at once
|
||||
if (configEventDisabled) return;
|
||||
|
|
@ -1044,6 +1040,6 @@ export const page = new PageWithUrlParams({
|
|||
},
|
||||
});
|
||||
|
||||
$(async () => {
|
||||
onWindowLoad(async () => {
|
||||
Skeleton.save("pageSettings");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -207,6 +207,20 @@ export class ElementWithUtils<T extends HTMLElement = HTMLElement> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if element is visible
|
||||
*/
|
||||
|
||||
isVisible(): boolean {
|
||||
return this.native.offsetWidth > 0 || this.native.offsetHeight > 0;
|
||||
}
|
||||
|
||||
scrollIntoView(options: ScrollIntoViewOptions): this {
|
||||
this.native.scrollIntoView(options);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the element
|
||||
*/
|
||||
|
|
@ -538,6 +552,25 @@ export class ElementWithUtils<T extends HTMLElement = HTMLElement> {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first parent that matches a selector
|
||||
*/
|
||||
|
||||
closestParent(selector: string): ElementWithUtils | null {
|
||||
const closestParent = this.native.parentElement?.closest(
|
||||
selector,
|
||||
) as HTMLElement;
|
||||
return closestParent !== null ? new ElementWithUtils(closestParent) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if element matches a selector
|
||||
*/
|
||||
|
||||
matches(selector: string): boolean {
|
||||
return this.native.matches(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace this element with another element
|
||||
*/
|
||||
|
|
@ -710,6 +743,38 @@ export class ElementsWithUtils<
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query all elements in the array for a child element matching the selector
|
||||
*/
|
||||
qs<U extends HTMLElement>(selector: string): ElementsWithUtils<U> {
|
||||
const allElements: ElementWithUtils<U>[] = [];
|
||||
|
||||
for (const item of this) {
|
||||
const found = item.native.querySelector<U>(selector);
|
||||
if (found) allElements.push(new ElementWithUtils<U>(found));
|
||||
}
|
||||
|
||||
return new ElementsWithUtils<U>(...allElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query all elements in the array for all child elements matching the selector
|
||||
*/
|
||||
qsa<U extends HTMLElement = HTMLElement>(
|
||||
selector: string,
|
||||
): ElementsWithUtils<U> {
|
||||
const allElements: ElementWithUtils<U>[] = [];
|
||||
|
||||
for (const item of this) {
|
||||
const elements = Array.from(item.native.querySelectorAll<U>(selector));
|
||||
for (const el of elements) {
|
||||
if (el !== null) allElements.push(new ElementWithUtils<U>(el));
|
||||
}
|
||||
}
|
||||
|
||||
return new ElementsWithUtils<U>(...allElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach an event listener to all elements in the array
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue