mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-09-07 15:15:49 +08:00
refactor: reduce indentation by extracting code to a function
This commit is contained in:
parent
33857d400a
commit
3207a20829
3 changed files with 419 additions and 380 deletions
|
@ -33,170 +33,176 @@ export function clearActive(): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function verify(result: CompletedEvent): string | null {
|
||||
try {
|
||||
if (TestState.activeChallenge) {
|
||||
const afk = (result.afkDuration / result.testDuration) * 100;
|
||||
function verifyRequirement(
|
||||
result: CompletedEvent,
|
||||
requirements: Record<string, Record<string, string | number | boolean>>,
|
||||
requirementType: string
|
||||
): [boolean, string[]] {
|
||||
let requirementsMet = true;
|
||||
let failReasons: string[] = [];
|
||||
|
||||
if (afk > 10) {
|
||||
Notifications.add(`Challenge failed: AFK time is greater than 10%`, 0);
|
||||
return null;
|
||||
const afk = (result.afkDuration / result.testDuration) * 100;
|
||||
|
||||
const requirementValue = requirements[requirementType];
|
||||
|
||||
if (requirementValue === undefined) {
|
||||
throw new Error("Requirement value is undefined");
|
||||
}
|
||||
|
||||
if (requirementType === "wpm") {
|
||||
const wpmMode = Object.keys(requirementValue)[0];
|
||||
if (wpmMode === "exact") {
|
||||
if (Math.round(result.wpm) !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`WPM not ${requirementValue["exact"]}`);
|
||||
}
|
||||
} else if (wpmMode === "min") {
|
||||
if (result.wpm < Number(requirementValue["min"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`WPM below ${requirementValue["min"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "acc") {
|
||||
const accMode = Object.keys(requirementValue)[0];
|
||||
if (accMode === "exact") {
|
||||
if (result.acc !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Accuracy not ${requirementValue["exact"]}`);
|
||||
}
|
||||
} else if (accMode === "min") {
|
||||
if (result.acc < Number(requirementValue["min"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Accuracy below ${requirementValue["min"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "afk") {
|
||||
const afkMode = Object.keys(requirementValue)[0];
|
||||
if (afkMode === "max") {
|
||||
if (Math.round(afk) > Number(requirementValue["max"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`AFK percentage above ${requirementValue["max"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "time") {
|
||||
const timeMode = Object.keys(requirementValue)[0];
|
||||
if (timeMode === "min") {
|
||||
if (Math.round(result.testDuration) < Number(requirementValue["min"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Test time below ${requirementValue["min"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "funbox") {
|
||||
const funboxMode = requirementValue["exact"]
|
||||
?.toString()
|
||||
.split("#")
|
||||
.sort()
|
||||
.join("#");
|
||||
|
||||
if (TestState.activeChallenge.requirements === undefined) {
|
||||
if (funboxMode === undefined) {
|
||||
throw new Error("Funbox mode is undefined");
|
||||
}
|
||||
|
||||
if (funboxMode !== result.funbox) {
|
||||
requirementsMet = false;
|
||||
for (const f of funboxMode.split("#")) {
|
||||
if (
|
||||
result.funbox?.split("#").find((rf: string) => rf === f) === undefined
|
||||
) {
|
||||
failReasons.push(`${f} funbox not active`);
|
||||
}
|
||||
}
|
||||
const funboxSplit = result.funbox?.split("#");
|
||||
if (funboxSplit !== undefined && funboxSplit.length > 0) {
|
||||
for (const f of funboxSplit) {
|
||||
if (funboxMode.split("#").find((rf) => rf === f) === undefined) {
|
||||
failReasons.push(`${f} funbox active`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "raw") {
|
||||
const rawMode = Object.keys(requirementValue)[0];
|
||||
if (rawMode === "exact") {
|
||||
if (Math.round(result.rawWpm) !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Raw WPM not ${requirementValue["exact"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "con") {
|
||||
const conMode = Object.keys(requirementValue)[0];
|
||||
if (conMode === "exact") {
|
||||
if (Math.round(result.consistency) !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Consistency not ${requirementValue["exact"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "config") {
|
||||
for (const configKey in requirementValue) {
|
||||
const configValue = requirementValue[configKey];
|
||||
if (Config[configKey as keyof ConfigType] !== configValue) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`${configKey} not set to ${configValue}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [requirementsMet, failReasons];
|
||||
}
|
||||
|
||||
export function verify(result: CompletedEvent): string | null {
|
||||
if (!TestState.activeChallenge) return null;
|
||||
|
||||
try {
|
||||
const afk = (result.afkDuration / result.testDuration) * 100;
|
||||
|
||||
if (afk > 10) {
|
||||
Notifications.add(`Challenge failed: AFK time is greater than 10%`, 0);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (TestState.activeChallenge.requirements === undefined) {
|
||||
Notifications.add(
|
||||
`${TestState.activeChallenge.display} challenge passed!`,
|
||||
1
|
||||
);
|
||||
return TestState.activeChallenge.name;
|
||||
} else {
|
||||
let requirementsMet = true;
|
||||
const failReasons: string[] = [];
|
||||
for (const requirementType in TestState.activeChallenge.requirements) {
|
||||
const [passed, requirementFailReasons] = verifyRequirement(
|
||||
result,
|
||||
TestState.activeChallenge.requirements,
|
||||
requirementType
|
||||
);
|
||||
if (!passed) {
|
||||
requirementsMet = false;
|
||||
}
|
||||
failReasons.push(...requirementFailReasons);
|
||||
}
|
||||
if (requirementsMet) {
|
||||
if (TestState.activeChallenge.autoRole) {
|
||||
Notifications.add(
|
||||
"You will receive a role shortly. Please don't post a screenshot in challenge submissions.",
|
||||
1,
|
||||
{
|
||||
duration: 5,
|
||||
}
|
||||
);
|
||||
}
|
||||
Notifications.add(
|
||||
`${TestState.activeChallenge.display} challenge passed!`,
|
||||
1
|
||||
);
|
||||
return TestState.activeChallenge.name;
|
||||
} else {
|
||||
let requirementsMet = true;
|
||||
const failReasons = [];
|
||||
for (const requirementType in TestState.activeChallenge.requirements) {
|
||||
if (!requirementsMet) return null;
|
||||
const requirementValue =
|
||||
TestState.activeChallenge.requirements[requirementType];
|
||||
|
||||
if (requirementValue === undefined) {
|
||||
throw new Error("Requirement value is undefined");
|
||||
}
|
||||
|
||||
if (requirementType === "wpm") {
|
||||
const wpmMode = Object.keys(requirementValue)[0];
|
||||
if (wpmMode === "exact") {
|
||||
if (Math.round(result.wpm) !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`WPM not ${requirementValue["exact"]}`);
|
||||
}
|
||||
} else if (wpmMode === "min") {
|
||||
if (result.wpm < Number(requirementValue["min"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`WPM below ${requirementValue["min"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "acc") {
|
||||
const accMode = Object.keys(requirementValue)[0];
|
||||
if (accMode === "exact") {
|
||||
if (result.acc !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Accuracy not ${requirementValue["exact"]}`);
|
||||
}
|
||||
} else if (accMode === "min") {
|
||||
if (result.acc < Number(requirementValue["min"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Accuracy below ${requirementValue["min"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "afk") {
|
||||
const afkMode = Object.keys(requirementValue)[0];
|
||||
if (afkMode === "max") {
|
||||
if (Math.round(afk) > Number(requirementValue["max"])) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(
|
||||
`AFK percentage above ${requirementValue["max"]}`
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "time") {
|
||||
const timeMode = Object.keys(requirementValue)[0];
|
||||
if (timeMode === "min") {
|
||||
if (
|
||||
Math.round(result.testDuration) <
|
||||
Number(requirementValue["min"])
|
||||
) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Test time below ${requirementValue["min"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "funbox") {
|
||||
const funboxMode = requirementValue["exact"]
|
||||
?.toString()
|
||||
.split("#")
|
||||
.sort()
|
||||
.join("#");
|
||||
|
||||
if (funboxMode === undefined) {
|
||||
throw new Error("Funbox mode is undefined");
|
||||
}
|
||||
|
||||
if (funboxMode !== result.funbox) {
|
||||
requirementsMet = false;
|
||||
for (const f of funboxMode.split("#")) {
|
||||
if (
|
||||
result.funbox?.split("#").find((rf: string) => rf === f) ===
|
||||
undefined
|
||||
) {
|
||||
failReasons.push(`${f} funbox not active`);
|
||||
}
|
||||
}
|
||||
const funboxSplit = result.funbox?.split("#");
|
||||
if (funboxSplit !== undefined && funboxSplit.length > 0) {
|
||||
for (const f of funboxSplit) {
|
||||
if (
|
||||
funboxMode.split("#").find((rf) => rf === f) === undefined
|
||||
) {
|
||||
failReasons.push(`${f} funbox active`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "raw") {
|
||||
const rawMode = Object.keys(requirementValue)[0];
|
||||
if (rawMode === "exact") {
|
||||
if (Math.round(result.rawWpm) !== requirementValue["exact"]) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`Raw WPM not ${requirementValue["exact"]}`);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "con") {
|
||||
const conMode = Object.keys(requirementValue)[0];
|
||||
if (conMode === "exact") {
|
||||
if (
|
||||
Math.round(result.consistency) !== requirementValue["exact"]
|
||||
) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(
|
||||
`Consistency not ${requirementValue["exact"]}`
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (requirementType === "config") {
|
||||
for (const configKey in requirementValue) {
|
||||
const configValue = requirementValue[configKey];
|
||||
if (Config[configKey as keyof ConfigType] !== configValue) {
|
||||
requirementsMet = false;
|
||||
failReasons.push(`${configKey} not set to ${configValue}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requirementsMet) {
|
||||
if (TestState.activeChallenge.autoRole) {
|
||||
Notifications.add(
|
||||
"You will receive a role shortly. Please don't post a screenshot in challenge submissions.",
|
||||
1,
|
||||
{
|
||||
duration: 5,
|
||||
}
|
||||
);
|
||||
}
|
||||
Notifications.add(
|
||||
`${TestState.activeChallenge.display} challenge passed!`,
|
||||
1
|
||||
);
|
||||
return TestState.activeChallenge.name;
|
||||
} else {
|
||||
Notifications.add(
|
||||
`${
|
||||
TestState.activeChallenge.display
|
||||
} challenge failed: ${failReasons.join(", ")}`,
|
||||
0
|
||||
);
|
||||
return null;
|
||||
}
|
||||
Notifications.add(
|
||||
`${
|
||||
TestState.activeChallenge.display
|
||||
} challenge failed: ${failReasons.join(", ")}`,
|
||||
0
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
|
|
@ -111,29 +111,262 @@ export function show(): void {
|
|||
$("#keymap").removeClass("hidden");
|
||||
}
|
||||
|
||||
function buildRow(options: {
|
||||
layoutData: JSONData.Layout;
|
||||
rowId: string;
|
||||
rowKeys: string[];
|
||||
layoutNameDisplayString: string;
|
||||
showTopRow: boolean;
|
||||
isMatrix: boolean;
|
||||
isSteno: boolean;
|
||||
isISO: boolean;
|
||||
isAlice: boolean;
|
||||
}): string {
|
||||
const {
|
||||
layoutData,
|
||||
rowId,
|
||||
isMatrix,
|
||||
showTopRow,
|
||||
isSteno,
|
||||
isISO,
|
||||
layoutNameDisplayString,
|
||||
isAlice,
|
||||
} = options;
|
||||
let { rowKeys } = options;
|
||||
|
||||
let hasAlphas = false;
|
||||
let r5Grid = "";
|
||||
let rowHtml = "";
|
||||
let keysHtml = "";
|
||||
|
||||
if (rowId === "row1" && (isMatrix || Config.keymapStyle === "staggered")) {
|
||||
rowKeys = rowKeys.slice(1);
|
||||
}
|
||||
if (rowId === "row1" && (!showTopRow || isSteno)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (
|
||||
(rowId === "row2" || rowId === "row3" || rowId === "row4") &&
|
||||
!isMatrix &&
|
||||
!isSteno
|
||||
) {
|
||||
keysHtml += "<div></div>";
|
||||
}
|
||||
|
||||
if (rowId === "row4" && !isISO && !isMatrix && !isSteno) {
|
||||
keysHtml += "<div></div>";
|
||||
}
|
||||
|
||||
if (isMatrix) {
|
||||
if (rowId !== "row5" && layoutData.matrixShowRightColumn) {
|
||||
keysHtml += `<div class="keymapKey"></div>`;
|
||||
} else {
|
||||
keysHtml += `<div></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowId === "row5") {
|
||||
if (isSteno) return "";
|
||||
let layoutDisplay = layoutNameDisplayString.replace(/_/g, " ");
|
||||
let letterStyle = "";
|
||||
if (Config.keymapLegendStyle === "blank") {
|
||||
letterStyle = `style="display: none;"`;
|
||||
}
|
||||
/* ROW 5 in alternate keymaps allow for alphas in thumb keys.
|
||||
* These keymaps MUST include two keys in row 5,
|
||||
* an alpha and a space, or a space and an alpha.
|
||||
* Alpha key is rendered with the regular alpha size.
|
||||
* Layout name is automatically added in the space key.
|
||||
* Visual keymap will be:
|
||||
* 1-3 for 1 alpha and 1 space
|
||||
* 3-1 for 1 space and 1 alpha
|
||||
* Together with the data-row5-has-alpha="true",
|
||||
* these two will be used to edit the CSS grid layout.
|
||||
* 3-3 for two spaces of size 3. This will not be used to edit CSS,
|
||||
* since it means a traditional layout, can keep current CSS grid.
|
||||
* It is just created for simplicity in the for loop below.
|
||||
* */
|
||||
// If only one space, add another
|
||||
if (rowKeys.length === 1 && rowKeys[0] === " ") {
|
||||
rowKeys[1] = rowKeys[0];
|
||||
}
|
||||
// If only one alpha, add one space and place it on the left
|
||||
if (rowKeys.length === 1 && rowKeys[0] !== " ") {
|
||||
rowKeys[1] = " ";
|
||||
rowKeys.reverse();
|
||||
}
|
||||
// If two alphas equal, replace one with a space on the left
|
||||
if (rowKeys.length > 1 && rowKeys[0] !== " " && rowKeys[0] === rowKeys[1]) {
|
||||
rowKeys[0] = " ";
|
||||
}
|
||||
const alphas = (v: string): boolean => v !== " ";
|
||||
hasAlphas = rowKeys.some(alphas);
|
||||
|
||||
keysHtml += "<div></div>";
|
||||
|
||||
for (let keyId = 0; keyId < rowKeys.length; keyId++) {
|
||||
const key = rowKeys[keyId] as string;
|
||||
let keyDisplay = key[0] as string;
|
||||
if (Config.keymapLegendStyle === "uppercase") {
|
||||
keyDisplay = keyDisplay.toUpperCase();
|
||||
}
|
||||
const keyVisualValue = key.replace('"', """);
|
||||
// these are used to keep grid layout but magically hide keys using opacity:
|
||||
let side = keyId < 1 ? "left" : "right";
|
||||
// we won't use this trick for alternate layouts, unless Alice (for rotation):
|
||||
if (hasAlphas && !isAlice) side = "";
|
||||
if (keyId === 1) {
|
||||
keysHtml += `<div class="keymapSplitSpacer"></div>`;
|
||||
r5Grid += "-";
|
||||
}
|
||||
if (keyVisualValue === " ") {
|
||||
keysHtml += `<div class="keymapKey keySpace layoutIndicator ${side}">
|
||||
<div class="letter" ${letterStyle}>${layoutDisplay}</div>
|
||||
</div>`;
|
||||
r5Grid += "3";
|
||||
// potential second space in next loop iterations will be empty:
|
||||
layoutDisplay = "";
|
||||
} else {
|
||||
keysHtml += `<div class="keymapKey ${side}">
|
||||
<div class="letter">${keyDisplay}</div>
|
||||
</div>`;
|
||||
r5Grid += "1";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let keyId = 0; keyId < rowKeys.length; keyId++) {
|
||||
if (rowId === "row2" && keyId === 12) continue;
|
||||
if (rowId === "row4" && isMatrix && isISO && keyId === 0) continue;
|
||||
|
||||
let colLimit = 10;
|
||||
if (layoutData.matrixShowRightColumn) {
|
||||
colLimit = 11;
|
||||
}
|
||||
if (rowId === "row4" && isMatrix && isISO) {
|
||||
colLimit += 1;
|
||||
}
|
||||
|
||||
if (
|
||||
(Config.keymapStyle === "matrix" ||
|
||||
Config.keymapStyle === "split_matrix") &&
|
||||
keyId >= colLimit
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = rowKeys[keyId] as string;
|
||||
const bump = rowId === "row3" && (keyId === 3 || keyId === 6);
|
||||
let keyDisplay = key[0] as string;
|
||||
let letterStyle = "";
|
||||
|
||||
if (Config.keymapLegendStyle === "blank") {
|
||||
letterStyle = `style="display: none;"`;
|
||||
} else if (Config.keymapLegendStyle === "uppercase") {
|
||||
keyDisplay = keyDisplay.toUpperCase();
|
||||
}
|
||||
|
||||
let hide = "";
|
||||
if (
|
||||
rowId === "row1" &&
|
||||
keyId === 0 &&
|
||||
!isMatrix &&
|
||||
Config.keymapStyle !== "staggered"
|
||||
) {
|
||||
hide = ` invisible`;
|
||||
}
|
||||
|
||||
const keyElement = `<div class="keymapKey${hide}" data-key="${key.replace(
|
||||
'"',
|
||||
"""
|
||||
)}"><span class="letter" ${letterStyle}>${keyDisplay}</span>${
|
||||
bump ? "<div class='bump'></div>" : ""
|
||||
}</div>`;
|
||||
|
||||
let splitSpacer = "";
|
||||
if (
|
||||
Config.keymapStyle === "split" ||
|
||||
Config.keymapStyle === "split_matrix" ||
|
||||
Config.keymapStyle === "alice" ||
|
||||
isSteno
|
||||
) {
|
||||
if (
|
||||
rowId === "row4" &&
|
||||
isSteno &&
|
||||
(keyId === 0 || keyId === 2 || keyId === 4)
|
||||
) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
} else if (
|
||||
rowId === "row4" &&
|
||||
(Config.keymapStyle === "split" || Config.keymapStyle === "alice") &&
|
||||
isISO
|
||||
) {
|
||||
if (keyId === 6) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
} else if (
|
||||
rowId === "row1" &&
|
||||
(Config.keymapStyle === "split" || Config.keymapStyle === "alice")
|
||||
) {
|
||||
if (keyId === 7) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
} else if (rowId === "row4" && isMatrix && isISO) {
|
||||
if (keyId === 6) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
} else {
|
||||
if (keyId === 5) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.keymapStyle === "alice" && rowId === "row4") {
|
||||
if ((isISO && keyId === 6) || (!isISO && keyId === 5)) {
|
||||
splitSpacer += `<div class="extraKey"><span class="letter"></span></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
keysHtml += splitSpacer + keyElement;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowId === "row5") {
|
||||
rowHtml += `<div
|
||||
class="row r5"
|
||||
data-row5-grid="${r5Grid}"
|
||||
data-row5-has-alpha="${hasAlphas}"
|
||||
>${keysHtml}</div>`;
|
||||
} else {
|
||||
const rowIndex = parseInt(rowId.replace("row", ""));
|
||||
rowHtml += `<div class="row r${rowIndex}">${keysHtml}</div>`;
|
||||
}
|
||||
|
||||
return rowHtml;
|
||||
}
|
||||
|
||||
export async function refresh(
|
||||
layoutName: string = Config.layout
|
||||
): Promise<void> {
|
||||
if (Config.keymapMode === "off") return;
|
||||
if (ActivePage.get() !== "test") return;
|
||||
if (!layoutName) return;
|
||||
let r5_grid = "";
|
||||
let hasAlphas = false;
|
||||
try {
|
||||
let layoutString = layoutName;
|
||||
let lts;
|
||||
let layoutNameDisplayString = layoutName;
|
||||
let layoutData: JSONData.Layout;
|
||||
try {
|
||||
if (Config.keymapLayout === "overrideSync") {
|
||||
if (Config.layout === "default") {
|
||||
lts = await JSONData.getLayout("qwerty");
|
||||
layoutString = "default";
|
||||
layoutData = await JSONData.getLayout("qwerty");
|
||||
layoutNameDisplayString = "default";
|
||||
} else {
|
||||
lts = await JSONData.getLayout(Config.layout);
|
||||
layoutString = Config.layout;
|
||||
layoutData = await JSONData.getLayout(Config.layout);
|
||||
layoutNameDisplayString = Config.layout;
|
||||
}
|
||||
} else {
|
||||
lts = await JSONData.getLayout(Config.keymapLayout);
|
||||
layoutString = Config.keymapLayout;
|
||||
layoutData = await JSONData.getLayout(Config.keymapLayout);
|
||||
layoutNameDisplayString = Config.keymapLayout;
|
||||
}
|
||||
} catch (e) {
|
||||
Notifications.add(
|
||||
|
@ -146,7 +379,7 @@ export async function refresh(
|
|||
const showTopRow =
|
||||
(TestWords.hasNumbers && Config.keymapMode === "next") ||
|
||||
Config.keymapShowTopRow === "always" ||
|
||||
(lts.keymapShowTopRow && Config.keymapShowTopRow !== "never");
|
||||
(layoutData.keymapShowTopRow && Config.keymapShowTopRow !== "never");
|
||||
|
||||
const isMatrix =
|
||||
Config.keymapStyle === "matrix" || Config.keymapStyle === "split_matrix";
|
||||
|
@ -157,225 +390,25 @@ export async function refresh(
|
|||
const isAlice = Config.keymapStyle === "alice";
|
||||
|
||||
if (isSteno) {
|
||||
lts = stenoKeys;
|
||||
layoutData = stenoKeys;
|
||||
}
|
||||
|
||||
const isISO = lts.type === "iso";
|
||||
const isISO = layoutData.type === "iso";
|
||||
|
||||
let keymapElement = "";
|
||||
|
||||
// ( as (keyof MonkeyTypes.Keys)[]).forEach(
|
||||
// (row, index) => {
|
||||
|
||||
const rowIds = Object.keys(lts.keys);
|
||||
|
||||
for (let index = 0; index < rowIds.length; index++) {
|
||||
const row = rowIds[index] as keyof JSONData.Keys;
|
||||
let rowKeys = lts.keys[row];
|
||||
if (row === "row1" && (isMatrix || Config.keymapStyle === "staggered")) {
|
||||
rowKeys = rowKeys.slice(1);
|
||||
}
|
||||
let rowElement = "";
|
||||
if (row === "row1" && (!showTopRow || isSteno)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
(row === "row2" || row === "row3" || row === "row4") &&
|
||||
!isMatrix &&
|
||||
!isSteno
|
||||
) {
|
||||
rowElement += "<div></div>";
|
||||
}
|
||||
|
||||
if (row === "row4" && !isISO && !isMatrix && !isSteno) {
|
||||
rowElement += "<div></div>";
|
||||
}
|
||||
|
||||
if (isMatrix) {
|
||||
if (row !== "row5" && lts.matrixShowRightColumn) {
|
||||
rowElement += `<div class="keymapKey"></div>`;
|
||||
} else {
|
||||
rowElement += `<div></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (row === "row5") {
|
||||
if (isSteno) continue;
|
||||
let layoutDisplay = layoutString.replace(/_/g, " ");
|
||||
let letterStyle = "";
|
||||
if (Config.keymapLegendStyle === "blank") {
|
||||
letterStyle = `style="display: none;"`;
|
||||
}
|
||||
/* ROW 5 in alternate keymaps allow for alphas in thumb keys.
|
||||
* These keymaps MUST include two keys in row 5,
|
||||
* an alpha and a space, or a space and an alpha.
|
||||
* Alpha key is rendered with the regular alpha size.
|
||||
* Layout name is automatically added in the space key.
|
||||
* Visual keymap will be:
|
||||
* 1-3 for 1 alpha and 1 space
|
||||
* 3-1 for 1 space and 1 alpha
|
||||
* Together with the data-row5-has-alpha="true",
|
||||
* these two will be used to edit the CSS grid layout.
|
||||
* 3-3 for two spaces of size 3. This will not be used to edit CSS,
|
||||
* since it means a traditional layout, can keep current CSS grid.
|
||||
* It is just created for simplicity in the for loop below.
|
||||
* */
|
||||
// If only one space, add another
|
||||
if (rowKeys.length === 1 && rowKeys[0] === " ") {
|
||||
rowKeys[1] = rowKeys[0];
|
||||
}
|
||||
// If only one alpha, add one space and place it on the left
|
||||
if (rowKeys.length === 1 && rowKeys[0] !== " ") {
|
||||
rowKeys[1] = " ";
|
||||
rowKeys.reverse();
|
||||
}
|
||||
// If two alphas equal, replace one with a space on the left
|
||||
if (
|
||||
rowKeys.length > 1 &&
|
||||
rowKeys[0] !== " " &&
|
||||
rowKeys[0] === rowKeys[1]
|
||||
) {
|
||||
rowKeys[0] = " ";
|
||||
}
|
||||
const alphas = (v: string): boolean => v !== " ";
|
||||
hasAlphas = rowKeys.some(alphas);
|
||||
|
||||
rowElement += "<div></div>";
|
||||
|
||||
for (let i = 0; i < rowKeys.length; i++) {
|
||||
const key = rowKeys[i] as string;
|
||||
let keyDisplay = key[0] as string;
|
||||
if (Config.keymapLegendStyle === "uppercase") {
|
||||
keyDisplay = keyDisplay.toUpperCase();
|
||||
}
|
||||
const keyVisualValue = key.replace('"', """);
|
||||
// these are used to keep grid layout but magically hide keys using opacity:
|
||||
let side = i < 1 ? "left" : "right";
|
||||
// we won't use this trick for alternate layouts, unless Alice (for rotation):
|
||||
if (hasAlphas && !isAlice) side = "";
|
||||
if (i === 1) {
|
||||
rowElement += `<div class="keymapSplitSpacer"></div>`;
|
||||
r5_grid += "-";
|
||||
}
|
||||
if (keyVisualValue === " ") {
|
||||
rowElement += `<div class="keymapKey keySpace layoutIndicator ${side}">
|
||||
<div class="letter" ${letterStyle}>${layoutDisplay}</div>
|
||||
</div>`;
|
||||
r5_grid += "3";
|
||||
// potential second space in next loop iterations will be empty:
|
||||
layoutDisplay = "";
|
||||
} else {
|
||||
rowElement += `<div class="keymapKey ${side}">
|
||||
<div class="letter">${keyDisplay}</div>
|
||||
</div>`;
|
||||
r5_grid += "1";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < rowKeys.length; i++) {
|
||||
if (row === "row2" && i === 12) continue;
|
||||
if (row === "row4" && isMatrix && isISO && i === 0) continue;
|
||||
|
||||
let colLimit = 10;
|
||||
if (lts.matrixShowRightColumn) {
|
||||
colLimit = 11;
|
||||
}
|
||||
if (row === "row4" && isMatrix && isISO) {
|
||||
colLimit += 1;
|
||||
}
|
||||
|
||||
if (
|
||||
(Config.keymapStyle === "matrix" ||
|
||||
Config.keymapStyle === "split_matrix") &&
|
||||
i >= colLimit
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const key = rowKeys[i] as string;
|
||||
const bump = row === "row3" && (i === 3 || i === 6);
|
||||
let keyDisplay = key[0] as string;
|
||||
let letterStyle = "";
|
||||
if (Config.keymapLegendStyle === "blank") {
|
||||
letterStyle = `style="display: none;"`;
|
||||
} else if (Config.keymapLegendStyle === "uppercase") {
|
||||
keyDisplay = keyDisplay.toUpperCase();
|
||||
}
|
||||
let hide = "";
|
||||
if (
|
||||
row === "row1" &&
|
||||
i === 0 &&
|
||||
!isMatrix &&
|
||||
Config.keymapStyle !== "staggered"
|
||||
) {
|
||||
hide = ` invisible`;
|
||||
}
|
||||
|
||||
const keyElement = `<div class="keymapKey${hide}" data-key="${key.replace(
|
||||
'"',
|
||||
"""
|
||||
)}">
|
||||
<span class="letter" ${letterStyle}>${keyDisplay}</span>
|
||||
${bump ? "<div class='bump'></div>" : ""}
|
||||
</div>`;
|
||||
|
||||
let splitSpacer = "";
|
||||
if (
|
||||
Config.keymapStyle === "split" ||
|
||||
Config.keymapStyle === "split_matrix" ||
|
||||
Config.keymapStyle === "alice" ||
|
||||
isSteno
|
||||
) {
|
||||
if (row === "row4" && isSteno && (i === 0 || i === 2 || i === 4)) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
} else if (
|
||||
row === "row4" &&
|
||||
(Config.keymapStyle === "split" ||
|
||||
Config.keymapStyle === "alice") &&
|
||||
isISO
|
||||
) {
|
||||
if (i === 6) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
} else if (
|
||||
row === "row1" &&
|
||||
(Config.keymapStyle === "split" || Config.keymapStyle === "alice")
|
||||
) {
|
||||
if (i === 7) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
} else if (row === "row4" && isMatrix && isISO) {
|
||||
if (i === 6) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
} else {
|
||||
if (i === 5) {
|
||||
splitSpacer += `<div class="keymapSplitSpacer"></div>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.keymapStyle === "alice" && row === "row4") {
|
||||
if ((isISO && i === 6) || (!isISO && i === 5)) {
|
||||
splitSpacer += `<div class="extraKey"><span class="letter"></span></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
rowElement += splitSpacer + keyElement;
|
||||
}
|
||||
}
|
||||
|
||||
if (row === "row5") {
|
||||
keymapElement += `<div
|
||||
class="row r${index + 1}"
|
||||
data-row5-grid="${r5_grid}"
|
||||
data-row5-has-alpha="${hasAlphas}"
|
||||
>${rowElement}</div>`;
|
||||
} else {
|
||||
keymapElement += `<div class="row r${index + 1}">${rowElement}</div>`;
|
||||
}
|
||||
for (const [rowId, rowKeys] of Object.entries(layoutData.keys)) {
|
||||
keymapElement += buildRow({
|
||||
layoutData,
|
||||
rowId,
|
||||
rowKeys,
|
||||
isMatrix,
|
||||
showTopRow,
|
||||
isSteno,
|
||||
isISO,
|
||||
layoutNameDisplayString,
|
||||
isAlice,
|
||||
});
|
||||
}
|
||||
// );
|
||||
|
||||
$("#keymap").html(keymapElement);
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
"max-depth": [
|
||||
"error",
|
||||
{
|
||||
"max": 9
|
||||
"max": 6
|
||||
}
|
||||
],
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue