Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions frontend/src/html/pages/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,7 @@
list="autocompleteOff"
spellcheck="false"
></textarea>
<div class="outOfFocusWarning hidden">
<div>
<i class="fas fa-fw fa-mouse-pointer"></i>
</div>
<div class="text">Click here or press any key to focus</div>
</div>
<mount data-component="outoffocuswarning" class="contents"></mount>
<div id="paceCaret" class="full-width default hidden"></div>
<div id="caret" class="full-width default"></div>
<div id="words" class="full-width"></div>
Expand Down
15 changes: 0 additions & 15 deletions frontend/src/styles/test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1342,21 +1342,6 @@
pointer-events: none;
opacity: 0;
}
.outOfFocusWarning {
display: flex;
place-content: center;
align-items: center;
gap: 0.5em;
text-align: center;
height: 100%;
align-content: center;
font-size: 1rem;
z-index: 999;
position: absolute;
width: 100%;
user-select: none;
pointer-events: none;
}

#liveStatsMini {
width: 0;
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/ts/commandline/commandline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as ThemeController from "../controllers/theme-controller";
import { clearFontPreview } from "../ui";
import AnimatedModal, { ShowOptions } from "../utils/animated-modal";
import { showNoticeNotification } from "../states/notifications";
import * as OutOfFocus from "../test/out-of-focus";
import {
getActivePage,
getCommandlineSubgroup,
Expand Down Expand Up @@ -34,6 +33,7 @@ import {
isModalOpen,
} from "../states/modals";
import { ValidationResult } from "../types/validation";
import { setTestFocusState } from "../states/test";

type CommandlineMode = "search" | "input";
type InputModeParams = {
Expand Down Expand Up @@ -74,14 +74,14 @@ let lastState:
function removeCommandlineBackground(): void {
qs("#commandLine")?.addClass("noBackground");
if (Config.showOutOfFocusWarning) {
OutOfFocus.hide();
setTestFocusState("focused");
}
}

function addCommandlineBackground(): void {
qs("#commandLine")?.removeClass("noBackground");
if (!isInputElementFocused()) {
OutOfFocus.show();
setTestFocusState("unfocused");
}
}

Expand Down
2 changes: 2 additions & 0 deletions frontend/src/ts/components/mount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { CompositionDisplay } from "./pages/test/CompositionDisplay";
import { Keymap } from "./pages/test/Keymap";
import { TestModesNotice } from "./pages/test/modes-notice/TestModesNotice";
import { Monkey } from "./pages/test/Monkey";
import { OutOfFocusWarning } from "./pages/test/OutOfFocusWarning";
import { TestConfig } from "./pages/test/TestConfig";
import { Popups } from "./popups/Popups";

Expand Down Expand Up @@ -56,6 +57,7 @@ const components: Record<string, () => JSXElement> = {
accountsettingspage: () => <AccountSettingsPage />,
keymap: () => <Keymap />,
monkey: () => <Monkey />,
outoffocuswarning: () => <OutOfFocusWarning />,
};

function mountToMountpoint(name: string, component: () => JSXElement): void {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/components/pages/test/CompositionDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Show } from "solid-js";

import { getConfig } from "../../../config/store";
import { getCompositionText, isOutOfFocus } from "../../../states/test";
import { getCompositionText, testFocusState } from "../../../states/test";
import { cn } from "../../../utils/cn";

export function CompositionDisplay() {
const isOutOfFocus = () => testFocusState() !== "focused";
return (
<Show when={getConfig.compositionDisplay === "below"}>
<div
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/ts/components/pages/test/OutOfFocusWarning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Show } from "solid-js";

import {
outOfFocusMaxHeight,
showOutOfFocusWarning,
testFocusState,
} from "../../../states/test";
import { Fa } from "../../common/Fa";

export function OutOfFocusWarning() {
const message = () =>
testFocusState() === "unfocusedWindow"
? "Click anywhere to focus the window"
: "Click here or press any key to focus";

return (
<Show when={showOutOfFocusWarning()}>
<div
class="pointer-events-none absolute z-999 flex h-full w-full place-content-center items-center gap-2 text-center text-base select-none"
style={{
"max-height":
outOfFocusMaxHeight() !== undefined
? `${outOfFocusMaxHeight()}px`
: undefined,
}}
>
<div>
<Fa icon="fa-mouse-pointer" fixedWidth />
</div>
<div>{message()}</div>
</div>
</Show>
);
}
33 changes: 30 additions & 3 deletions frontend/src/ts/states/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { canQuickRestart } from "../utils/quick-restart";
import { replaceUnderscoresWithSpaces } from "../utils/strings";
import { getActivePage, getCustomTextIndicator } from "./core";
import { useResourceWithPromise } from "../hooks/useResourceWithPromise";
import { clearTimeouts } from "../utils/misc";

export const [wordsHaveNewline, setWordsHaveNewline] = createSignal(false);
export const [wordsHaveTab, setWordsHaveTab] = createSignal(false);
Expand All @@ -24,9 +25,35 @@ export const [getLoadedChallenge, setLoadedChallenge] =
createSignal<Challenge | null>(null);
export const [getResultVisible, setResultVisible] = createSignal(false);
export const [getFocus, setFocus] = createSignal(false);
// #words is still vanilla so it's blurred imperatively (see test/out-of-focus);
// the Solid-owned composition display reads this signal instead.
export const [isOutOfFocus, setOutOfFocus] = createSignal(false);
// #words is still vanilla so it's blurred imperatively (see test/test-ui);
// the Solid-owned composition display + OutOfFocusWarning read this signal.
const outOfFocusTimeouts: (number | NodeJS.Timeout)[] = [];
export type TestFocusState = "focused" | "unfocused" | "unfocusedWindow";
export const [testFocusState, { setTestFocusState }] =
createSignalWithSetters<TestFocusState>("focused")({
setTestFocusState: (set, val: TestFocusState) => {
if (val === "focused") {
clearTimeouts(outOfFocusTimeouts);
set(val);
} else {
outOfFocusTimeouts.push(
setTimeout(() => {
set(val);
}, 1000),
);
}
},
});

export const showOutOfFocusWarning = createMemo(
() => getConfig.showOutOfFocusWarning && testFocusState() !== "focused",
);

// max-height of the warning, kept in sync with the words wrapper by test-ui.
export const [outOfFocusMaxHeight, setOutOfFocusMaxHeight] = createSignal<
number | undefined
>(undefined);

// live IME composition text, pushed from the compositionupdate/end events.
export const [getCompositionText, setCompositionText] = createSignal("");
export const [isTestInvalid, setIsTestInvalid] = createSignal(false);
Expand Down
30 changes: 0 additions & 30 deletions frontend/src/ts/test/out-of-focus.ts

This file was deleted.

36 changes: 23 additions & 13 deletions frontend/src/ts/test/test-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { getCurrentInput } from "./events/data";
import { getLiveCachedAccuracy } from "./events/live-cache";
import * as CustomText from "./custom-text";
import * as Caret from "./caret";
import * as OutOfFocus from "./out-of-focus";
import * as Misc from "../utils/misc";
import * as Strings from "../utils/strings";
import { blendTwoHexColors } from "../utils/colors";
Expand Down Expand Up @@ -65,8 +64,12 @@ import {
isTestActive,
resetCurrentLiveStats,
setCompositionText,
setOutOfFocusMaxHeight,
wordsHaveNewline,
setTestFocusState,
showOutOfFocusWarning,
} from "../states/test";
import { createEffect } from "solid-js";
import {
getCorrectedWordsHistory,
getInputHistory,
Expand All @@ -87,6 +90,16 @@ export let activeWordTop = 0;
export let activeWordHeight = 0;
let wordTopBeforeLineJump = 0;
let lineTransition = false;

// #words is still vanilla; the warning itself is Solid (OutOfFocusWarning.tsx).
// show/hideOutOfFocus live in states/test so commandline needn't import test-ui.
createEffect(() => {
if (showOutOfFocusWarning()) {
wordsEl.setStyle({ transition: "0.25s" })?.addClass("blurred");
} else {
wordsEl.setStyle({ transition: "none" })?.removeClass("blurred");
}
});
let currentTestLine = 0;

export function focusWords(force = false): void {
Expand Down Expand Up @@ -404,7 +417,7 @@ function buildWordHTML(word: string, wordIndex: number): string {

function updateWordWrapperClasses(): void {
// outoffocus applies transition, need to remove it
OutOfFocus.hide();
setTestFocusState("focused");

if (Config.tapeMode !== "off") {
wordsEl.addClass("tape");
Expand Down Expand Up @@ -492,7 +505,7 @@ function updateWordWrapperClasses(): void {
Caret.updatePosition();

if (!isInputElementFocused()) {
OutOfFocus.show();
setTestFocusState("unfocused");
}
}

Expand Down Expand Up @@ -607,9 +620,6 @@ export async function centerActiveLine(): Promise<void> {
export function updateWordsWrapperHeight(force = false): void {
if (getActivePage() !== "test" || TestState.resultVisible) return;
if (!force && Config.mode !== "custom") return;
const outOfFocusEl = document.querySelector(
".outOfFocusWarning",
) as HTMLElement;
const activeWordEl = getActiveWordElement();
if (!activeWordEl) return;

Expand Down Expand Up @@ -669,7 +679,7 @@ export function updateWordsWrapperHeight(force = false): void {
}
}

outOfFocusEl.style.maxHeight = `${wordHeight * 3}px`;
setOutOfFocusMaxHeight(wordHeight * 3);
}

function updateWordsMargin(): void {
Expand Down Expand Up @@ -1918,7 +1928,7 @@ export function onTestFinish(): void {
LiveAcc.hide();
LiveBurst.hide();
TimerProgress.hide();
OutOfFocus.hide();
setTestFocusState("focused");
if (Config.playSoundOnClick === "16") {
void SoundController.playFartReverb();
}
Expand Down Expand Up @@ -1982,14 +1992,14 @@ addEventListener("resize", () => {
qs("#wordsInput")?.on("focus", (e) => {
if (!isInputElementFocused()) return;
if (!TestState.resultVisible && Config.showOutOfFocusWarning) {
OutOfFocus.hide();
setTestFocusState("focused");
}
Caret.show(true);
});

qs("#wordsInput")?.on("focusout", () => {
if (!isInputElementFocused()) {
OutOfFocus.show();
setTestFocusState("unfocused");
}
Caret.hide();
});
Expand All @@ -2003,13 +2013,13 @@ qs("#wordsWrapper")?.on("click", () => {
});

window.addEventListener("blur", () => {
OutOfFocus.show("window");
setTestFocusState("unfocusedWindow");
});

// little roadblock for basic cheating
document.addEventListener("visibilitychange", () => {
if (document.visibilityState !== "hidden") return;
OutOfFocus.show("window");
setTestFocusState("unfocusedWindow");
});

configEvent.subscribe(({ key, newValue }) => {
Expand All @@ -2023,7 +2033,7 @@ configEvent.subscribe(({ key, newValue }) => {
updateLiveStatsColor(newValue);
}
if (key === "showOutOfFocusWarning" && !newValue) {
OutOfFocus.hide();
setTestFocusState("focused");
}
if (key === "compositionDisplay" && newValue === "below") {
setCompositionText(" ");
Expand Down
Loading