mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-11-01 03:39:15 +08:00
fix: use selected typing speed unit on personal best popup (fehmer) (#5070)
* fix: Use selected typing speed unit on personal best popup * refactor * refactor * test coverage * use Format in more places * Make config mockable * dependency injection * wip * fix * test * touch
This commit is contained in:
parent
4d5085d351
commit
bac837d823
14 changed files with 416 additions and 302 deletions
201
frontend/__tests__/utils/format.spec.ts
Normal file
201
frontend/__tests__/utils/format.spec.ts
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
import { Formatting } from "../../src/ts/utils/format";
|
||||
import * as MockConfig from "../../src/ts/config";
|
||||
import DefaultConfig from "../../src/ts/constants/default-config";
|
||||
|
||||
describe("format.ts", () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
describe("typingsSpeed", () => {
|
||||
it("should format with typing speed and decimalPlaces from configuration", () => {
|
||||
//wpm, no decimals
|
||||
const wpmNoDecimals = getInstance({
|
||||
typingSpeedUnit: "wpm",
|
||||
alwaysShowDecimalPlaces: false,
|
||||
});
|
||||
expect(wpmNoDecimals.typingSpeed(12.5)).toEqual("13");
|
||||
expect(wpmNoDecimals.typingSpeed(0)).toEqual("0");
|
||||
|
||||
//cpm, no decimals
|
||||
const cpmNoDecimals = getInstance({
|
||||
typingSpeedUnit: "cpm",
|
||||
alwaysShowDecimalPlaces: false,
|
||||
});
|
||||
expect(cpmNoDecimals.typingSpeed(12.5)).toEqual("63");
|
||||
expect(cpmNoDecimals.typingSpeed(0)).toEqual("0");
|
||||
|
||||
//wpm, with decimals
|
||||
const wpmWithDecimals = getInstance({
|
||||
typingSpeedUnit: "wpm",
|
||||
alwaysShowDecimalPlaces: true,
|
||||
});
|
||||
expect(wpmWithDecimals.typingSpeed(12.5)).toEqual("12.50");
|
||||
expect(wpmWithDecimals.typingSpeed(0)).toEqual("0.00");
|
||||
|
||||
//cpm, with decimals
|
||||
const cpmWithDecimals = getInstance({
|
||||
typingSpeedUnit: "cpm",
|
||||
alwaysShowDecimalPlaces: true,
|
||||
});
|
||||
expect(cpmWithDecimals.typingSpeed(12.5)).toEqual("62.50");
|
||||
expect(cpmWithDecimals.typingSpeed(0)).toEqual("0.00");
|
||||
});
|
||||
|
||||
it("should format with fallback", () => {
|
||||
//default fallback
|
||||
const format = getInstance();
|
||||
expect(format.typingSpeed(null)).toEqual("-");
|
||||
expect(format.typingSpeed(undefined)).toEqual("-");
|
||||
|
||||
//provided fallback
|
||||
expect(format.typingSpeed(null, { fallback: "none" })).toEqual("none");
|
||||
expect(format.typingSpeed(null, { fallback: "" })).toEqual("");
|
||||
expect(format.typingSpeed(undefined, { fallback: "none" })).toEqual(
|
||||
"none"
|
||||
);
|
||||
|
||||
expect(format.typingSpeed(undefined, { fallback: "" })).toEqual("");
|
||||
expect(format.typingSpeed(undefined, { fallback: undefined })).toEqual(
|
||||
""
|
||||
);
|
||||
});
|
||||
|
||||
it("should format with decimals", () => {
|
||||
//force with decimals
|
||||
const wpmNoDecimals = getInstance({
|
||||
typingSpeedUnit: "wpm",
|
||||
alwaysShowDecimalPlaces: false,
|
||||
});
|
||||
expect(
|
||||
wpmNoDecimals.typingSpeed(100, { showDecimalPlaces: true })
|
||||
).toEqual("100.00");
|
||||
//force without decimals
|
||||
const wpmWithDecimals = getInstance({
|
||||
typingSpeedUnit: "wpm",
|
||||
alwaysShowDecimalPlaces: true,
|
||||
});
|
||||
expect(
|
||||
wpmWithDecimals.typingSpeed(100, { showDecimalPlaces: false })
|
||||
).toEqual("100");
|
||||
});
|
||||
|
||||
it("should format with suffix", () => {
|
||||
const format = getInstance({
|
||||
typingSpeedUnit: "wpm",
|
||||
alwaysShowDecimalPlaces: false,
|
||||
});
|
||||
expect(format.typingSpeed(100, { suffix: " raw" })).toEqual("100 raw");
|
||||
expect(format.typingSpeed(100, { suffix: undefined })).toEqual("100");
|
||||
expect(format.typingSpeed(0, { suffix: " raw" })).toEqual("0 raw");
|
||||
expect(format.typingSpeed(null, { suffix: " raw" })).toEqual("-");
|
||||
expect(format.typingSpeed(undefined, { suffix: " raw" })).toEqual("-");
|
||||
});
|
||||
});
|
||||
describe("percentage", () => {
|
||||
it("should format with decimalPlaces from configuration", () => {
|
||||
//no decimals
|
||||
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
|
||||
expect(noDecimals.percentage(12.5)).toEqual("13%");
|
||||
expect(noDecimals.percentage(0)).toEqual("0%");
|
||||
|
||||
//with decimals
|
||||
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
|
||||
expect(withDecimals.percentage(12.5)).toEqual("12.50%");
|
||||
expect(withDecimals.percentage(0)).toEqual("0.00%");
|
||||
});
|
||||
|
||||
it("should format with fallback", () => {
|
||||
//default fallback
|
||||
const format = getInstance();
|
||||
expect(format.percentage(null)).toEqual("-");
|
||||
expect(format.percentage(undefined)).toEqual("-");
|
||||
|
||||
//provided fallback
|
||||
expect(format.percentage(null, { fallback: "none" })).toEqual("none");
|
||||
expect(format.percentage(null, { fallback: "" })).toEqual("");
|
||||
expect(format.percentage(undefined, { fallback: "none" })).toEqual(
|
||||
"none"
|
||||
);
|
||||
|
||||
expect(format.percentage(undefined, { fallback: "" })).toEqual("");
|
||||
expect(format.percentage(undefined, { fallback: undefined })).toEqual("");
|
||||
});
|
||||
|
||||
it("should format with decimals", () => {
|
||||
//force with decimals
|
||||
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
|
||||
expect(noDecimals.percentage(100, { showDecimalPlaces: true })).toEqual(
|
||||
"100.00%"
|
||||
);
|
||||
//force without decimals
|
||||
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
|
||||
expect(
|
||||
withDecimals.percentage(100, { showDecimalPlaces: false })
|
||||
).toEqual("100%");
|
||||
});
|
||||
|
||||
it("should format with suffix", () => {
|
||||
const format = getInstance({ alwaysShowDecimalPlaces: false });
|
||||
expect(format.percentage(100, { suffix: " raw" })).toEqual("100% raw");
|
||||
expect(format.percentage(100, { suffix: undefined })).toEqual("100%");
|
||||
expect(format.percentage(0, { suffix: " raw" })).toEqual("0% raw");
|
||||
expect(format.percentage(null, { suffix: " raw" })).toEqual("-");
|
||||
expect(format.percentage(undefined, { suffix: " raw" })).toEqual("-");
|
||||
});
|
||||
});
|
||||
describe("decimals", () => {
|
||||
it("should format with decimalPlaces from configuration", () => {
|
||||
//no decimals
|
||||
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
|
||||
expect(noDecimals.decimals(12.5)).toEqual("13");
|
||||
expect(noDecimals.decimals(0)).toEqual("0");
|
||||
|
||||
//with decimals
|
||||
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
|
||||
expect(withDecimals.decimals(12.5)).toEqual("12.50");
|
||||
expect(withDecimals.decimals(0)).toEqual("0.00");
|
||||
});
|
||||
|
||||
it("should format with fallback", () => {
|
||||
//default fallback
|
||||
const format = getInstance();
|
||||
expect(format.decimals(null)).toEqual("-");
|
||||
expect(format.decimals(undefined)).toEqual("-");
|
||||
|
||||
//provided fallback
|
||||
expect(format.decimals(null, { fallback: "none" })).toEqual("none");
|
||||
expect(format.decimals(null, { fallback: "" })).toEqual("");
|
||||
expect(format.decimals(undefined, { fallback: "none" })).toEqual("none");
|
||||
|
||||
expect(format.decimals(undefined, { fallback: "" })).toEqual("");
|
||||
expect(format.decimals(undefined, { fallback: undefined })).toEqual("");
|
||||
});
|
||||
|
||||
it("should format with decimals", () => {
|
||||
//force with decimals
|
||||
const noDecimals = getInstance({ alwaysShowDecimalPlaces: false });
|
||||
expect(noDecimals.decimals(100, { showDecimalPlaces: true })).toEqual(
|
||||
"100.00"
|
||||
);
|
||||
//force without decimals
|
||||
const withDecimals = getInstance({ alwaysShowDecimalPlaces: true });
|
||||
expect(withDecimals.decimals(100, { showDecimalPlaces: false })).toEqual(
|
||||
"100"
|
||||
);
|
||||
});
|
||||
|
||||
it("should format with suffix", () => {
|
||||
const format = getInstance({ alwaysShowDecimalPlaces: false });
|
||||
expect(format.decimals(100, { suffix: " raw" })).toEqual("100 raw");
|
||||
expect(format.decimals(100, { suffix: undefined })).toEqual("100");
|
||||
expect(format.decimals(0, { suffix: " raw" })).toEqual("0 raw");
|
||||
expect(format.decimals(null, { suffix: " raw" })).toEqual("-");
|
||||
expect(format.decimals(undefined, { suffix: " raw" })).toEqual("-");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getInstance(config?: Partial<SharedTypes.Config>): Formatting {
|
||||
const target: SharedTypes.Config = { ...DefaultConfig, ...config };
|
||||
return new Formatting(target);
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import Config from "../config";
|
||||
import format from "date-fns/format";
|
||||
import * as Misc from "../utils/misc";
|
||||
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
|
||||
import dateFormat from "date-fns/format";
|
||||
import Format from "../utils/format";
|
||||
|
||||
function clearTables(isProfile: boolean): void {
|
||||
const source = isProfile ? "Profile" : "Account";
|
||||
|
|
@ -140,7 +139,6 @@ function buildPbHtml(
|
|||
let dateText = "";
|
||||
const modeString = `${mode2} ${mode === "time" ? "seconds" : "words"}`;
|
||||
const speedUnit = Config.typingSpeedUnit;
|
||||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
try {
|
||||
const pbData = (pbs[mode][mode2] ?? []).sort((a, b) => b.wpm - a.wpm)[0];
|
||||
|
||||
|
|
@ -148,62 +146,28 @@ function buildPbHtml(
|
|||
|
||||
const date = new Date(pbData.timestamp);
|
||||
if (pbData.timestamp) {
|
||||
dateText = format(date, "dd MMM yyyy");
|
||||
dateText = dateFormat(date, "dd MMM yyyy");
|
||||
}
|
||||
|
||||
let speedString: number | string = typingSpeedUnit.fromWpm(pbData.wpm);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
speedString = Misc.roundTo2(speedString).toFixed(2);
|
||||
} else {
|
||||
speedString = Math.round(speedString);
|
||||
}
|
||||
speedString += ` ${speedUnit}`;
|
||||
|
||||
let rawString: number | string = typingSpeedUnit.fromWpm(pbData.raw);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
rawString = Misc.roundTo2(rawString).toFixed(2);
|
||||
} else {
|
||||
rawString = Math.round(rawString);
|
||||
}
|
||||
rawString += ` raw`;
|
||||
|
||||
let accString: number | string = pbData.acc;
|
||||
if (accString === undefined) {
|
||||
accString = "-";
|
||||
} else {
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
accString = Misc.roundTo2(accString).toFixed(2);
|
||||
} else {
|
||||
accString = Math.floor(accString);
|
||||
}
|
||||
}
|
||||
accString += ` acc`;
|
||||
|
||||
let conString: number | string = pbData.consistency;
|
||||
if (conString === undefined) {
|
||||
conString = "-";
|
||||
} else {
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
conString = Misc.roundTo2(conString).toFixed(2);
|
||||
} else {
|
||||
conString = Math.round(conString);
|
||||
}
|
||||
}
|
||||
conString += ` con`;
|
||||
|
||||
retval = `<div class="quick">
|
||||
<div class="test">${modeString}</div>
|
||||
<div class="wpm">${Math.round(typingSpeedUnit.fromWpm(pbData.wpm))}</div>
|
||||
<div class="acc">${
|
||||
pbData.acc === undefined ? "-" : Math.floor(pbData.acc) + "%"
|
||||
}</div>
|
||||
<div class="wpm">${Format.typingSpeed(pbData.wpm, {
|
||||
showDecimalPlaces: false,
|
||||
})}</div>
|
||||
<div class="acc">${Format.percentage(pbData.acc, {
|
||||
showDecimalPlaces: false,
|
||||
})}</div>
|
||||
</div>
|
||||
<div class="fullTest">
|
||||
<div>${modeString}</div>
|
||||
<div>${speedString}</div>
|
||||
<div>${rawString}</div>
|
||||
<div>${accString}</div>
|
||||
<div>${conString}</div>
|
||||
<div>${Format.typingSpeed(pbData.wpm, {
|
||||
suffix: ` ${speedUnit}`,
|
||||
})}</div>
|
||||
<div>${Format.typingSpeed(pbData.raw, { suffix: " raw" })}</div>
|
||||
<div>${Format.percentage(pbData.acc, { suffix: " acc" })}</div>
|
||||
<div>${Format.percentage(pbData.consistency, {
|
||||
suffix: " con",
|
||||
})}</div>
|
||||
<div>${dateText}</div>
|
||||
</div>`;
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Ape from "../ape";
|
|||
import * as DB from "../db";
|
||||
import Config from "../config";
|
||||
import * as Misc from "../utils/misc";
|
||||
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
|
||||
import * as Notifications from "./notifications";
|
||||
import format from "date-fns/format";
|
||||
import { isAuthenticated } from "../firebase";
|
||||
|
|
@ -11,6 +10,7 @@ import { getHTMLById as getBadgeHTMLbyId } from "../controllers/badge-controller
|
|||
import * as ConnectionState from "../states/connection";
|
||||
import * as Skeleton from "../popups/skeleton";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import Format from "../utils/format";
|
||||
import SlimSelect from "slim-select";
|
||||
|
||||
const wrapperId = "leaderboardsWrapper";
|
||||
|
|
@ -165,7 +165,6 @@ function updateFooter(lb: LbKey): void {
|
|||
return;
|
||||
}
|
||||
|
||||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
if (DB.getSnapshot()?.lbOptOut === true) {
|
||||
$(`#leaderboardsWrapper table.${side} tfoot`).html(`
|
||||
<tr>
|
||||
|
|
@ -211,12 +210,18 @@ function updateFooter(lb: LbKey): void {
|
|||
<tr>
|
||||
<td>${lbRank.rank}</td>
|
||||
<td><span class="top">You</span>${toppercent ? toppercent : ""}</td>
|
||||
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.wpm).toFixed(2)}<br>
|
||||
<div class="sub">${entry.acc.toFixed(2)}%</div></td>
|
||||
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.raw).toFixed(2)}<br>
|
||||
<div class="sub">${
|
||||
entry.consistency === undefined ? "-" : entry.consistency.toFixed(2) + "%"
|
||||
}</div></td>
|
||||
<td class="alignRight">${Format.typingSpeed(entry.wpm, {
|
||||
showDecimalPlaces: true,
|
||||
})}<br>
|
||||
<div class="sub">${Format.percentage(entry.acc, {
|
||||
showDecimalPlaces: true,
|
||||
})}%</div></td>
|
||||
<td class="alignRight">${Format.typingSpeed(entry.raw, {
|
||||
showDecimalPlaces: true,
|
||||
})}<br>
|
||||
<div class="sub">${Format.percentage(entry.consistency, {
|
||||
showDecimalPlaces: true,
|
||||
})}</div></td>
|
||||
<td class="alignRight">${format(date, "dd MMM yyyy")}<br>
|
||||
<div class='sub'>${format(date, "HH:mm")}</div></td>
|
||||
</tr>
|
||||
|
|
@ -296,8 +301,6 @@ async function fillTable(lb: LbKey): Promise<void> {
|
|||
"<tr><td colspan='7'>No results found</td></tr>"
|
||||
);
|
||||
}
|
||||
|
||||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
const loggedInUserName = DB.getSnapshot()?.name;
|
||||
|
||||
let html = "";
|
||||
|
|
@ -336,12 +339,18 @@ async function fillTable(lb: LbKey): Promise<void> {
|
|||
${entry.badgeId ? getBadgeHTMLbyId(entry.badgeId) : ""}
|
||||
</div>
|
||||
</td>
|
||||
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.wpm).toFixed(2)}<br>
|
||||
<div class="sub">${entry.acc.toFixed(2)}%</div></td>
|
||||
<td class="alignRight">${typingSpeedUnit.fromWpm(entry.raw).toFixed(2)}<br>
|
||||
<div class="sub">${
|
||||
entry.consistency === undefined ? "-" : entry.consistency.toFixed(2) + "%"
|
||||
}</div></td>
|
||||
<td class="alignRight">${Format.typingSpeed(entry.wpm, {
|
||||
showDecimalPlaces: true,
|
||||
})}<br>
|
||||
<div class="sub">${Format.percentage(entry.acc, {
|
||||
showDecimalPlaces: true,
|
||||
})}</div></td>
|
||||
<td class="alignRight">${Format.typingSpeed(entry.raw, {
|
||||
showDecimalPlaces: true,
|
||||
})}<br>
|
||||
<div class="sub">${Format.percentage(entry.consistency, {
|
||||
showDecimalPlaces: true,
|
||||
})}</div></td>
|
||||
<td class="alignRight">${format(date, "dd MMM yyyy")}<br>
|
||||
<div class='sub'>${format(date, "HH:mm")}</div></td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import * as TestWords from "../test/test-words";
|
|||
import * as ConfigEvent from "../observables/config-event";
|
||||
import { isAuthenticated } from "../firebase";
|
||||
import * as CustomTextState from "../states/custom-text-name";
|
||||
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
|
||||
import { getLanguageDisplayString, roundTo2 } from "../utils/misc";
|
||||
import { getLanguageDisplayString } from "../utils/misc";
|
||||
import Format from "../utils/format";
|
||||
|
||||
ConfigEvent.subscribe((eventKey) => {
|
||||
if (
|
||||
|
|
@ -123,14 +123,11 @@ export async function update(): Promise<void> {
|
|||
Config.paceCaret !== "off" ||
|
||||
(Config.repeatedPace && TestState.isPaceRepeat)
|
||||
) {
|
||||
let speed = "";
|
||||
try {
|
||||
speed = ` (${roundTo2(
|
||||
getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(
|
||||
PaceCaret.settings?.wpm ?? 0
|
||||
)
|
||||
)} ${Config.typingSpeedUnit})`;
|
||||
} catch {}
|
||||
const speed = Format.typingSpeed(PaceCaret.settings?.wpm ?? 0, {
|
||||
showDecimalPlaces: true,
|
||||
suffix: ` ${Config.typingSpeedUnit}`,
|
||||
});
|
||||
|
||||
$(".pageTest #testModesNotice").append(
|
||||
`<div class="textButton" commands="paceCaretMode"><i class="fas fa-tachometer-alt"></i>${
|
||||
Config.paceCaret === "average"
|
||||
|
|
@ -142,7 +139,7 @@ export async function update(): Promise<void> {
|
|||
: Config.paceCaret === "daily"
|
||||
? "daily"
|
||||
: "custom"
|
||||
} pace${speed}</div>`
|
||||
} pace ${speed}</div>`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -157,14 +154,11 @@ export async function update(): Promise<void> {
|
|||
|
||||
if (isAuthenticated() && avgWPM > 0) {
|
||||
const avgWPMText = ["speed", "both"].includes(Config.showAverage)
|
||||
? getTypingSpeedUnit(Config.typingSpeedUnit).convertWithUnitSuffix(
|
||||
avgWPM,
|
||||
Config.alwaysShowDecimalPlaces
|
||||
)
|
||||
? Format.typingSpeed(avgWPM, { suffix: ` ${Config.typingSpeedUnit}` })
|
||||
: "";
|
||||
|
||||
const avgAccText = ["acc", "both"].includes(Config.showAverage)
|
||||
? `${avgAcc}% acc`
|
||||
? Format.percentage(avgAcc, { suffix: " acc" })
|
||||
: "";
|
||||
|
||||
const text = `${avgWPMText} ${avgAccText}`.trim();
|
||||
|
|
@ -177,11 +171,10 @@ export async function update(): Promise<void> {
|
|||
|
||||
if (Config.minWpm !== "off") {
|
||||
$(".pageTest #testModesNotice").append(
|
||||
`<div class="textButton" commands="minWpm"><i class="fas fa-bomb"></i>min ${roundTo2(
|
||||
getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(
|
||||
Config.minWpmCustomSpeed
|
||||
)
|
||||
)} ${Config.typingSpeedUnit}</div>`
|
||||
`<div class="textButton" commands="minWpm"><i class="fas fa-bomb"></i>min ${Format.typingSpeed(
|
||||
Config.minWpmCustomSpeed,
|
||||
{ showDecimalPlaces: true, suffix: ` ${Config.typingSpeedUnit}` }
|
||||
)}</div>`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -193,10 +186,9 @@ export async function update(): Promise<void> {
|
|||
|
||||
if (Config.minBurst !== "off") {
|
||||
$(".pageTest #testModesNotice").append(
|
||||
`<div class="textButton" commands="minBurst"><i class="fas fa-bomb"></i>min ${roundTo2(
|
||||
getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(
|
||||
Config.minBurstCustomSpeed
|
||||
)
|
||||
`<div class="textButton" commands="minBurst"><i class="fas fa-bomb"></i>min ${Format.typingSpeed(
|
||||
Config.minBurstCustomSpeed,
|
||||
{ showDecimalPlaces: true }
|
||||
)} ${Config.typingSpeedUnit} burst ${
|
||||
Config.minBurst === "flex" ? "(flex)" : ""
|
||||
}</div>`
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import * as ActivePage from "../states/active-page";
|
|||
import { Auth } from "../firebase";
|
||||
import * as Loader from "../elements/loader";
|
||||
import * as ResultBatches from "../elements/result-batches";
|
||||
import Format from "../utils/format";
|
||||
|
||||
let filterDebug = false;
|
||||
//toggle filterdebug
|
||||
|
|
@ -37,7 +38,6 @@ let filteredResults: SharedTypes.Result<SharedTypes.Config.Mode>[] = [];
|
|||
let visibleTableLines = 0;
|
||||
|
||||
function loadMoreLines(lineIndex?: number): void {
|
||||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
if (filteredResults === undefined || filteredResults.length === 0) return;
|
||||
let newVisibleLines;
|
||||
if (lineIndex && lineIndex > visibleTableLines) {
|
||||
|
|
@ -53,16 +53,6 @@ function loadMoreLines(lineIndex?: number): void {
|
|||
diff = "normal";
|
||||
}
|
||||
|
||||
let raw;
|
||||
try {
|
||||
raw = typingSpeedUnit.fromWpm(result.rawWpm).toFixed(2);
|
||||
if (raw === undefined) {
|
||||
raw = "-";
|
||||
}
|
||||
} catch (e) {
|
||||
raw = "-";
|
||||
}
|
||||
|
||||
let icons = `<span aria-label="${result.language?.replace(
|
||||
"_",
|
||||
" "
|
||||
|
|
@ -139,12 +129,6 @@ function loadMoreLines(lineIndex?: number): void {
|
|||
}
|
||||
}
|
||||
|
||||
let consistency = "-";
|
||||
|
||||
if (result.consistency) {
|
||||
consistency = result.consistency.toFixed(2) + "%";
|
||||
}
|
||||
|
||||
let pb = "";
|
||||
if (result.isPb) {
|
||||
pb = '<i class="fas fa-fw fa-crown"></i>';
|
||||
|
|
@ -158,10 +142,12 @@ function loadMoreLines(lineIndex?: number): void {
|
|||
$(".pageAccount .history table tbody").append(`
|
||||
<tr class="resultRow" id="result-${i}">
|
||||
<td>${pb}</td>
|
||||
<td>${typingSpeedUnit.fromWpm(result.wpm).toFixed(2)}</td>
|
||||
<td>${raw}</td>
|
||||
<td>${result.acc.toFixed(2)}%</td>
|
||||
<td>${consistency}</td>
|
||||
<td>${Format.typingSpeed(result.wpm, { showDecimalPlaces: true })}</td>
|
||||
<td>${Format.typingSpeed(result.rawWpm, { showDecimalPlaces: true })}</td>
|
||||
<td>${Format.percentage(result.acc, { showDecimalPlaces: true })}</td>
|
||||
<td>${Format.percentage(result.consistency, {
|
||||
showDecimalPlaces: true,
|
||||
})}</td>
|
||||
<td>${charStats}</td>
|
||||
<td>${result.mode} ${result.mode2}</td>
|
||||
<td class="infoIcons">${icons}</td>
|
||||
|
|
@ -860,144 +846,58 @@ async function fillContent(): Promise<void> {
|
|||
Misc.secondsToString(Math.round(totalSecondsFiltered), true, true)
|
||||
);
|
||||
|
||||
let highestSpeed: number | string = typingSpeedUnit.fromWpm(topWpm);
|
||||
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
highestSpeed = Misc.roundTo2(highestSpeed).toFixed(2);
|
||||
} else {
|
||||
highestSpeed = Math.round(highestSpeed);
|
||||
}
|
||||
|
||||
const speedUnit = Config.typingSpeedUnit;
|
||||
|
||||
$(".pageAccount .highestWpm .title").text(`highest ${speedUnit}`);
|
||||
$(".pageAccount .highestWpm .val").text(highestSpeed);
|
||||
|
||||
let averageSpeed: number | string = typingSpeedUnit.fromWpm(totalWpm);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageSpeed = Misc.roundTo2(averageSpeed / testCount).toFixed(2);
|
||||
} else {
|
||||
averageSpeed = Math.round(averageSpeed / testCount);
|
||||
}
|
||||
$(".pageAccount .highestWpm .val").text(Format.typingSpeed(topWpm));
|
||||
|
||||
$(".pageAccount .averageWpm .title").text(`average ${speedUnit}`);
|
||||
$(".pageAccount .averageWpm .val").text(averageSpeed);
|
||||
|
||||
let averageSpeedLast10: number | string =
|
||||
typingSpeedUnit.fromWpm(wpmLast10total);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageSpeedLast10 = Misc.roundTo2(averageSpeedLast10 / last10).toFixed(2);
|
||||
} else {
|
||||
averageSpeedLast10 = Math.round(averageSpeedLast10 / last10);
|
||||
}
|
||||
$(".pageAccount .averageWpm .val").text(
|
||||
Format.typingSpeed(totalWpm / testCount)
|
||||
);
|
||||
|
||||
$(".pageAccount .averageWpm10 .title").text(
|
||||
`average ${speedUnit} (last 10 tests)`
|
||||
);
|
||||
$(".pageAccount .averageWpm10 .val").text(averageSpeedLast10);
|
||||
|
||||
let highestRawSpeed: number | string = typingSpeedUnit.fromWpm(rawWpm.max);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
highestRawSpeed = Misc.roundTo2(highestRawSpeed).toFixed(2);
|
||||
} else {
|
||||
highestRawSpeed = Math.round(highestRawSpeed);
|
||||
}
|
||||
$(".pageAccount .averageWpm10 .val").text(
|
||||
Format.typingSpeed(wpmLast10total / last10)
|
||||
);
|
||||
|
||||
$(".pageAccount .highestRaw .title").text(`highest raw ${speedUnit}`);
|
||||
$(".pageAccount .highestRaw .val").text(highestRawSpeed);
|
||||
|
||||
let averageRawSpeed: number | string = typingSpeedUnit.fromWpm(rawWpm.total);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageRawSpeed = Misc.roundTo2(averageRawSpeed / rawWpm.count).toFixed(2);
|
||||
} else {
|
||||
averageRawSpeed = Math.round(averageRawSpeed / rawWpm.count);
|
||||
}
|
||||
$(".pageAccount .highestRaw .val").text(Format.typingSpeed(rawWpm.max));
|
||||
|
||||
$(".pageAccount .averageRaw .title").text(`average raw ${speedUnit}`);
|
||||
$(".pageAccount .averageRaw .val").text(averageRawSpeed);
|
||||
|
||||
let averageRawSpeedLast10: number | string = typingSpeedUnit.fromWpm(
|
||||
rawWpm.last10Total
|
||||
$(".pageAccount .averageRaw .val").text(
|
||||
Format.typingSpeed(rawWpm.total / rawWpm.count)
|
||||
);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageRawSpeedLast10 = Misc.roundTo2(
|
||||
averageRawSpeedLast10 / rawWpm.last10Count
|
||||
).toFixed(2);
|
||||
} else {
|
||||
averageRawSpeedLast10 = Math.round(
|
||||
averageRawSpeedLast10 / rawWpm.last10Count
|
||||
);
|
||||
}
|
||||
|
||||
$(".pageAccount .averageRaw10 .title").text(
|
||||
`average raw ${speedUnit} (last 10 tests)`
|
||||
);
|
||||
$(".pageAccount .averageRaw10 .val").text(averageRawSpeedLast10);
|
||||
$(".pageAccount .averageRaw10 .val").text(
|
||||
Format.typingSpeed(rawWpm.last10Total / rawWpm.last10Count)
|
||||
);
|
||||
|
||||
$(".pageAccount .highestWpm .mode").html(topMode);
|
||||
$(".pageAccount .testsTaken .val").text(testCount);
|
||||
|
||||
let highestAcc: string | number = topAcc;
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
highestAcc = Misc.roundTo2(highestAcc).toFixed(2);
|
||||
} else {
|
||||
highestAcc = Math.floor(highestAcc);
|
||||
}
|
||||
|
||||
$(".pageAccount .highestAcc .val").text(highestAcc + "%");
|
||||
|
||||
let averageAcc: number | string = totalAcc;
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageAcc = Misc.roundTo2(averageAcc / testCount);
|
||||
} else {
|
||||
averageAcc = Math.floor(averageAcc / testCount);
|
||||
}
|
||||
|
||||
$(".pageAccount .avgAcc .val").text(averageAcc + "%");
|
||||
|
||||
let averageAccLast10: number | string = totalAcc10;
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageAccLast10 = Misc.roundTo2(averageAccLast10 / last10);
|
||||
} else {
|
||||
averageAccLast10 = Math.floor(averageAccLast10 / last10);
|
||||
}
|
||||
|
||||
$(".pageAccount .avgAcc10 .val").text(averageAccLast10 + "%");
|
||||
$(".pageAccount .highestAcc .val").text(Format.percentage(topAcc));
|
||||
$(".pageAccount .avgAcc .val").text(Format.percentage(totalAcc / testCount));
|
||||
$(".pageAccount .avgAcc10 .val").text(Format.percentage(totalAcc10 / last10));
|
||||
|
||||
if (totalCons === 0 || totalCons === undefined) {
|
||||
$(".pageAccount .avgCons .val").text("-");
|
||||
$(".pageAccount .avgCons10 .val").text("-");
|
||||
} else {
|
||||
let highestCons: number | string = topCons;
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
highestCons = Misc.roundTo2(highestCons).toFixed(2);
|
||||
} else {
|
||||
highestCons = Math.round(highestCons);
|
||||
}
|
||||
$(".pageAccount .highestCons .val").text(Format.percentage(topCons));
|
||||
|
||||
$(".pageAccount .highestCons .val").text(highestCons + "%");
|
||||
$(".pageAccount .avgCons .val").text(
|
||||
Format.percentage(totalCons / consCount)
|
||||
);
|
||||
|
||||
let averageCons: number | string = totalCons;
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageCons = Misc.roundTo2(averageCons / consCount).toFixed(2);
|
||||
} else {
|
||||
averageCons = Math.round(averageCons / consCount);
|
||||
}
|
||||
|
||||
$(".pageAccount .avgCons .val").text(averageCons + "%");
|
||||
|
||||
let averageConsLast10: number | string = totalCons10;
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
averageConsLast10 = Misc.roundTo2(
|
||||
averageConsLast10 / Math.min(last10, consCount)
|
||||
).toFixed(2);
|
||||
} else {
|
||||
averageConsLast10 = Math.round(
|
||||
averageConsLast10 / Math.min(last10, consCount)
|
||||
);
|
||||
}
|
||||
|
||||
$(".pageAccount .avgCons10 .val").text(averageConsLast10 + "%");
|
||||
$(".pageAccount .avgCons10 .val").text(
|
||||
Format.percentage(totalCons10 / Math.min(last10, consCount))
|
||||
);
|
||||
}
|
||||
|
||||
$(".pageAccount .testsStarted .val").text(`${testCount + testRestarts}`);
|
||||
|
|
@ -1020,7 +920,7 @@ async function fillContent(): Promise<void> {
|
|||
const plus = wpmChangePerHour > 0 ? "+" : "";
|
||||
$(".pageAccount .group.chart .below .text").text(
|
||||
`Speed change per hour spent typing: ${
|
||||
plus + Misc.roundTo2(typingSpeedUnit.fromWpm(wpmChangePerHour))
|
||||
plus + Format.typingSpeed(wpmChangePerHour, { showDecimalPlaces: true })
|
||||
} ${Config.typingSpeedUnit}`
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import * as DB from "../db";
|
|||
import format from "date-fns/format";
|
||||
import * as Skeleton from "./skeleton";
|
||||
import { getLanguageDisplayString, isPopupVisible } from "../utils/misc";
|
||||
import Config from "../config";
|
||||
import Format from "../utils/format";
|
||||
|
||||
type PersonalBest = {
|
||||
mode2: SharedTypes.Config.Mode2<SharedTypes.Config.Mode>;
|
||||
|
|
@ -12,6 +14,9 @@ const wrapperId = "pbTablesPopupWrapper";
|
|||
function update(mode: SharedTypes.Config.Mode): void {
|
||||
$("#pbTablesPopup table tbody").empty();
|
||||
$($("#pbTablesPopup table thead tr td")[0] as HTMLElement).text(mode);
|
||||
$($("#pbTablesPopup table thead tr td span.unit")[0] as HTMLElement).text(
|
||||
Config.typingSpeedUnit
|
||||
);
|
||||
|
||||
const snapshot = DB.getSnapshot();
|
||||
if (!snapshot) return;
|
||||
|
|
@ -56,16 +61,14 @@ function update(mode: SharedTypes.Config.Mode): void {
|
|||
<tr>
|
||||
<td>${mode2memory === pb.mode2 ? "" : pb.mode2}</td>
|
||||
<td>
|
||||
${pb.wpm.toFixed(2)}
|
||||
${Format.typingSpeed(pb.wpm)}
|
||||
<br />
|
||||
<span class="sub">${pb.acc ? pb.acc + "%" : "-"}</span>
|
||||
<span class="sub">${Format.percentage(pb.acc)}</span>
|
||||
</td>
|
||||
<td>
|
||||
${pb.raw ? pb.raw : "-"}
|
||||
${Format.typingSpeed(pb.raw)}
|
||||
<br />
|
||||
<span class="sub">${
|
||||
pb.consistency ? pb.consistency + "%" : "-"
|
||||
}</span>
|
||||
<span class="sub">${Format.percentage(pb.consistency)}</span>
|
||||
</td>
|
||||
<td>${pb.difficulty}</td>
|
||||
<td>${pb.language ? getLanguageDisplayString(pb.language) : "-"}</td>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import Config from "../config";
|
||||
import * as TestState from "../test/test-state";
|
||||
import * as ConfigEvent from "../observables/config-event";
|
||||
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
|
||||
import Format from "../utils/format";
|
||||
|
||||
export async function update(burst: number): Promise<void> {
|
||||
if (!Config.showLiveBurst) return;
|
||||
burst = Math.round(getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(burst));
|
||||
const burstText = Format.typingSpeed(burst, { showDecimalPlaces: false });
|
||||
(document.querySelector("#miniTimerAndLiveWpm .burst") as Element).innerHTML =
|
||||
burst.toString();
|
||||
(document.querySelector("#liveBurst") as Element).innerHTML =
|
||||
burst.toString();
|
||||
burstText;
|
||||
(document.querySelector("#liveBurst") as Element).innerHTML = burstText;
|
||||
}
|
||||
|
||||
let state = false;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Config from "../config";
|
||||
import * as TestState from "../test/test-state";
|
||||
import * as ConfigEvent from "../observables/config-event";
|
||||
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
|
||||
import Format from "../utils/format";
|
||||
|
||||
const liveWpmElement = document.querySelector("#liveWpm") as Element;
|
||||
const miniLiveWpmElement = document.querySelector(
|
||||
|
|
@ -13,11 +13,9 @@ export function update(wpm: number, raw: number): void {
|
|||
if (Config.blindMode) {
|
||||
number = raw;
|
||||
}
|
||||
number = Math.round(
|
||||
getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(number)
|
||||
);
|
||||
miniLiveWpmElement.innerHTML = number.toString();
|
||||
liveWpmElement.innerHTML = number.toString();
|
||||
const numberText = Format.typingSpeed(number, { showDecimalPlaces: false });
|
||||
miniLiveWpmElement.innerHTML = numberText;
|
||||
liveWpmElement.innerHTML = numberText;
|
||||
}
|
||||
|
||||
let state = false;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//TODO: use Format
|
||||
import { Chart, type PluginChartOptions } from "chart.js";
|
||||
import Config from "../config";
|
||||
import * as AdController from "../controllers/ad-controller";
|
||||
|
|
@ -25,6 +26,7 @@ import * as Focus from "./focus";
|
|||
import * as CustomText from "./custom-text";
|
||||
import * as CustomTextState from "./../states/custom-text-name";
|
||||
import * as Funbox from "./funbox/funbox";
|
||||
import Format from "../utils/format";
|
||||
|
||||
import confetti from "canvas-confetti";
|
||||
import type { AnnotationOptions } from "chartjs-plugin-annotation";
|
||||
|
|
@ -213,24 +215,23 @@ export async function updateGraphPBLine(): Promise<void> {
|
|||
|
||||
function updateWpmAndAcc(): void {
|
||||
let inf = false;
|
||||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
if (result.wpm >= 1000) {
|
||||
inf = true;
|
||||
}
|
||||
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
$("#result .stats .wpm .top .text").text(Config.typingSpeedUnit);
|
||||
if (inf) {
|
||||
$("#result .stats .wpm .bottom").text("Infinite");
|
||||
} else {
|
||||
$("#result .stats .wpm .bottom").text(
|
||||
Misc.roundTo2(typingSpeedUnit.fromWpm(result.wpm)).toFixed(2)
|
||||
);
|
||||
}
|
||||
$("#result .stats .raw .bottom").text(
|
||||
Misc.roundTo2(typingSpeedUnit.fromWpm(result.rawWpm)).toFixed(2)
|
||||
);
|
||||
$("#result .stats .wpm .top .text").text(Config.typingSpeedUnit);
|
||||
|
||||
if (inf) {
|
||||
$("#result .stats .wpm .bottom").text("Infinite");
|
||||
} else {
|
||||
$("#result .stats .wpm .bottom").text(Format.typingSpeed(result.wpm));
|
||||
}
|
||||
$("#result .stats .raw .bottom").text(Format.typingSpeed(result.rawWpm));
|
||||
$("#result .stats .acc .bottom").text(
|
||||
result.acc === 100 ? "100%" : Format.percentage(result.acc)
|
||||
);
|
||||
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
if (Config.typingSpeedUnit != "wpm") {
|
||||
$("#result .stats .wpm .bottom").attr(
|
||||
"aria-label",
|
||||
|
|
@ -245,9 +246,6 @@ function updateWpmAndAcc(): void {
|
|||
$("#result .stats .raw .bottom").removeAttr("aria-label");
|
||||
}
|
||||
|
||||
$("#result .stats .acc .bottom").text(
|
||||
result.acc === 100 ? "100%" : Misc.roundTo2(result.acc).toFixed(2) + "%"
|
||||
);
|
||||
let time = Misc.roundTo2(result.testDuration).toFixed(2) + "s";
|
||||
if (result.testDuration > 61) {
|
||||
time = Misc.secondsToString(Misc.roundTo2(result.testDuration));
|
||||
|
|
@ -261,53 +259,47 @@ function updateWpmAndAcc(): void {
|
|||
);
|
||||
} else {
|
||||
//not showing decimal places
|
||||
let wpmHover = typingSpeedUnit.convertWithUnitSuffix(result.wpm, true);
|
||||
let rawWpmHover = typingSpeedUnit.convertWithUnitSuffix(
|
||||
result.rawWpm,
|
||||
true
|
||||
);
|
||||
const decimalsAndSuffix = {
|
||||
showDecimalPlaces: true,
|
||||
suffix: ` ${Config.typingSpeedUnit}`,
|
||||
};
|
||||
let wpmHover = Format.typingSpeed(result.wpm, decimalsAndSuffix);
|
||||
let rawWpmHover = Format.typingSpeed(result.rawWpm, decimalsAndSuffix);
|
||||
|
||||
if (Config.typingSpeedUnit != "wpm") {
|
||||
wpmHover += " (" + result.wpm.toFixed(2) + " wpm)";
|
||||
rawWpmHover += " (" + result.rawWpm.toFixed(2) + " wpm)";
|
||||
}
|
||||
|
||||
$("#result .stats .wpm .top .text").text(Config.typingSpeedUnit);
|
||||
$("#result .stats .wpm .bottom").attr("aria-label", wpmHover);
|
||||
if (inf) {
|
||||
$("#result .stats .wpm .bottom").text("Infinite");
|
||||
} else {
|
||||
$("#result .stats .wpm .bottom").text(
|
||||
Math.round(typingSpeedUnit.fromWpm(result.wpm))
|
||||
);
|
||||
}
|
||||
$("#result .stats .raw .bottom").text(
|
||||
Math.round(typingSpeedUnit.fromWpm(result.rawWpm))
|
||||
);
|
||||
$("#result .stats .raw .bottom").attr("aria-label", rawWpmHover);
|
||||
|
||||
$("#result .stats .acc .bottom").text(Math.floor(result.acc) + "%");
|
||||
$("#result .stats .acc .bottom").attr(
|
||||
"aria-label",
|
||||
`${result.acc === 100 ? "100" : Misc.roundTo2(result.acc).toFixed(2)}% (${
|
||||
TestInput.accuracy.correct
|
||||
} correct / ${TestInput.accuracy.incorrect} incorrect)`
|
||||
`${
|
||||
result.acc === 100
|
||||
? "100"
|
||||
: Format.percentage(result.acc, { showDecimalPlaces: true })
|
||||
} (${TestInput.accuracy.correct} correct / ${
|
||||
TestInput.accuracy.incorrect
|
||||
} incorrect)`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function updateConsistency(): void {
|
||||
$("#result .stats .consistency .bottom").text(
|
||||
Format.percentage(result.consistency)
|
||||
);
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
$("#result .stats .consistency .bottom").text(
|
||||
Misc.roundTo2(result.consistency).toFixed(2) + "%"
|
||||
);
|
||||
$("#result .stats .consistency .bottom").attr(
|
||||
"aria-label",
|
||||
`${result.keyConsistency.toFixed(2)}% key`
|
||||
Format.percentage(result.keyConsistency, {
|
||||
showDecimalPlaces: true,
|
||||
suffix: " key",
|
||||
})
|
||||
);
|
||||
} else {
|
||||
$("#result .stats .consistency .bottom").text(
|
||||
Math.round(result.consistency) + "%"
|
||||
);
|
||||
$("#result .stats .consistency .bottom").attr(
|
||||
"aria-label",
|
||||
`${result.consistency}% (${result.keyConsistency}% key)`
|
||||
|
|
@ -327,6 +319,7 @@ function updateTime(): void {
|
|||
"aria-label",
|
||||
`${result.afkDuration}s afk ${afkSecondsPercent}%`
|
||||
);
|
||||
|
||||
if (Config.alwaysShowDecimalPlaces) {
|
||||
let time = Misc.roundTo2(result.testDuration).toFixed(2) + "s";
|
||||
if (result.testDuration > 61) {
|
||||
|
|
@ -416,11 +409,10 @@ export async function updateCrown(): Promise<void> {
|
|||
Config.lazyMode,
|
||||
Config.funbox
|
||||
);
|
||||
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
|
||||
pbDiff = Math.abs(result.wpm - lpb);
|
||||
$("#result .stats .wpm .crown").attr(
|
||||
"aria-label",
|
||||
"+" + Misc.roundTo2(typingSpeedUnit.fromWpm(pbDiff))
|
||||
"+" + Format.typingSpeed(pbDiff, { showDecimalPlaces: true })
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { debounce } from "throttle-debounce";
|
|||
import * as ResultWordHighlight from "../elements/result-word-highlight";
|
||||
import * as ActivePage from "../states/active-page";
|
||||
import html2canvas from "html2canvas";
|
||||
import Format from "../utils/format";
|
||||
|
||||
const debouncedZipfCheck = debounce(250, async () => {
|
||||
const supports = await Misc.checkIfLanguageSupportsZipf(Config.language);
|
||||
|
|
@ -1299,9 +1300,8 @@ $(".pageTest #resultWordsHistory").on("mouseenter", ".words .word", (e) => {
|
|||
.replace(/>/g, ">")}
|
||||
</div>
|
||||
<div class="speed">
|
||||
${Math.round(
|
||||
getTypingSpeedUnit(Config.typingSpeedUnit).fromWpm(burst)
|
||||
)}${Config.typingSpeedUnit}
|
||||
${Format.typingSpeed(burst, { showDecimalPlaces: false })}
|
||||
${Config.typingSpeedUnit}
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
|
|
|
|||
1
frontend/src/ts/types/types.d.ts
vendored
1
frontend/src/ts/types/types.d.ts
vendored
|
|
@ -474,7 +474,6 @@ declare namespace MonkeyTypes {
|
|||
type TypingSpeedUnitSettings = {
|
||||
fromWpm: (number: number) => number;
|
||||
toWpm: (number: number) => number;
|
||||
convertWithUnitSuffix: (number: number, withDecimals: boolean) => string;
|
||||
fullUnitString: string;
|
||||
histogramDataBucketSize: number;
|
||||
historyStepSize: number;
|
||||
|
|
|
|||
67
frontend/src/ts/utils/format.ts
Normal file
67
frontend/src/ts/utils/format.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import * as Misc from "./misc";
|
||||
import Config from "../config";
|
||||
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
|
||||
|
||||
export type FormatOptions = {
|
||||
showDecimalPlaces?: boolean;
|
||||
suffix?: string;
|
||||
fallback?: string;
|
||||
};
|
||||
|
||||
const FORMAT_DEFAULT_OPTIONS: FormatOptions = {
|
||||
suffix: "",
|
||||
fallback: "-",
|
||||
showDecimalPlaces: undefined,
|
||||
};
|
||||
|
||||
export class Formatting {
|
||||
constructor(private config: SharedTypes.Config) {}
|
||||
|
||||
typingSpeed(
|
||||
wpm: number | null | undefined,
|
||||
formatOptions: FormatOptions = FORMAT_DEFAULT_OPTIONS
|
||||
): string {
|
||||
const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions };
|
||||
if (wpm === undefined || wpm === null) return options.fallback ?? "";
|
||||
|
||||
const result = getTypingSpeedUnit(this.config.typingSpeedUnit).fromWpm(wpm);
|
||||
|
||||
return this.number(result, options);
|
||||
}
|
||||
percentage(
|
||||
percentage: number | null | undefined,
|
||||
formatOptions: FormatOptions = {}
|
||||
): string {
|
||||
const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions };
|
||||
options.suffix = "%" + (options.suffix ?? "");
|
||||
|
||||
return this.number(percentage, options);
|
||||
}
|
||||
|
||||
decimals(
|
||||
value: number | null | undefined,
|
||||
formatOptions: FormatOptions = {}
|
||||
): string {
|
||||
const options = { ...FORMAT_DEFAULT_OPTIONS, ...formatOptions };
|
||||
return this.number(value, options);
|
||||
}
|
||||
private number(
|
||||
value: number | null | undefined,
|
||||
formatOptions: FormatOptions
|
||||
): string {
|
||||
if (value === undefined || value === null)
|
||||
return formatOptions.fallback ?? "";
|
||||
const suffix = formatOptions.suffix ?? "";
|
||||
|
||||
if (
|
||||
formatOptions.showDecimalPlaces !== undefined
|
||||
? formatOptions.showDecimalPlaces
|
||||
: this.config.alwaysShowDecimalPlaces
|
||||
) {
|
||||
return Misc.roundTo2(value).toFixed(2) + suffix;
|
||||
}
|
||||
return Math.round(value).toString() + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Formatting(Config);
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
import { roundTo2 } from "../utils/misc";
|
||||
|
||||
class Unit implements MonkeyTypes.TypingSpeedUnitSettings {
|
||||
unit: SharedTypes.Config.TypingSpeedUnit;
|
||||
convertFactor: number;
|
||||
|
|
@ -28,14 +26,6 @@ class Unit implements MonkeyTypes.TypingSpeedUnitSettings {
|
|||
toWpm(val: number): number {
|
||||
return val / this.convertFactor;
|
||||
}
|
||||
|
||||
convertWithUnitSuffix(wpm: number, withDecimals: boolean): string {
|
||||
if (withDecimals) {
|
||||
return roundTo2(this.fromWpm(wpm)).toFixed(2) + " " + this.unit;
|
||||
} else {
|
||||
return Math.round(this.fromWpm(wpm)) + " " + this.unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const typingSpeedUnits: Record<SharedTypes.Config.TypingSpeedUnit, Unit> = {
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@
|
|||
<tr>
|
||||
<td width="1%">words</td>
|
||||
<td>
|
||||
wpm
|
||||
<span class="unit">wpm</span>
|
||||
<br />
|
||||
<span class="sub">accuracy</span>
|
||||
</td>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue