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
54 changes: 27 additions & 27 deletions frontend/__tests__/utils/strings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ describe("string utils", () => {
] as const)(
"should return %s for word '%s' (%s)",
(expected: boolean, word: string, _description: string) => {
expect(Strings.__testing.hasRTLCharacters(word)).toBe(expected);
expect(Strings.__testing.hasRTLCharacters(word)[0]).toBe(expected);
},
);
});
Expand Down Expand Up @@ -321,27 +321,27 @@ describe("string utils", () => {
languageRTL: boolean,
_description: string,
) => {
expect(Strings.isWordRightToLeft(word, languageRTL)).toBe(expected);
expect(Strings.isWordRightToLeft(word, languageRTL)[0]).toBe(expected);
},
);

it("should return languageRTL for undefined word", () => {
expect(Strings.isWordRightToLeft(undefined, false)).toBe(false);
expect(Strings.isWordRightToLeft(undefined, true)).toBe(true);
expect(Strings.isWordRightToLeft(undefined, false)[0]).toBe(false);
expect(Strings.isWordRightToLeft(undefined, true)[0]).toBe(true);
});

// testing reverseDirection
it("should return true for LTR word with reversed direction", () => {
expect(Strings.isWordRightToLeft("hello", false, true)).toBe(true);
expect(Strings.isWordRightToLeft("hello", true, true)).toBe(true);
expect(Strings.isWordRightToLeft("hello", false, true)[0]).toBe(true);
expect(Strings.isWordRightToLeft("hello", true, true)[0]).toBe(true);
});
it("should return false for RTL word with reversed direction", () => {
expect(Strings.isWordRightToLeft("مرحبا", true, true)).toBe(false);
expect(Strings.isWordRightToLeft("مرحبا", false, true)).toBe(false);
expect(Strings.isWordRightToLeft("مرحبا", true, true)[0]).toBe(false);
expect(Strings.isWordRightToLeft("مرحبا", false, true)[0]).toBe(false);
});
it("should return reverse of languageRTL for undefined word with reversed direction", () => {
expect(Strings.isWordRightToLeft(undefined, false, true)).toBe(true);
expect(Strings.isWordRightToLeft(undefined, true, true)).toBe(false);
expect(Strings.isWordRightToLeft(undefined, false, true)[0]).toBe(true);
expect(Strings.isWordRightToLeft(undefined, true, true)[0]).toBe(false);
});

describe("caching", () => {
Expand All @@ -364,16 +364,16 @@ describe("string utils", () => {
it("should use cache for repeated calls", () => {
// First call should cache the result (cache miss)
const result1 = Strings.isWordRightToLeft("hello", false);
expect(result1).toBe(false);
expect(mapSetSpy).toHaveBeenCalledWith("hello", false);
expect(result1[0]).toBe(false);
expect(mapSetSpy).toHaveBeenCalledWith("hello", [false, 0]);

// Reset spies to check second call
mapGetSpy.mockClear();
mapSetSpy.mockClear();

// Second call should use cache (cache hit)
const result2 = Strings.isWordRightToLeft("hello", false);
expect(result2).toBe(false);
expect(result2[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("hello");
expect(mapSetSpy).not.toHaveBeenCalled(); // Should not set again

Expand All @@ -382,47 +382,47 @@ describe("string utils", () => {
mapSetSpy.mockClear();

const result3 = Strings.isWordRightToLeft("hello", true);
expect(result3).toBe(false); // Still false because "hello" is LTR regardless of language
expect(result3[0]).toBe(false); // Still false because "hello" is LTR regardless of language
expect(mapGetSpy).toHaveBeenCalledWith("hello");
expect(mapSetSpy).not.toHaveBeenCalled(); // Should not set again
});

it("should cache based on core word without punctuation", () => {
// First call should cache the result for core "hello"
const result1 = Strings.isWordRightToLeft("hello", false);
expect(result1).toBe(false);
expect(mapSetSpy).toHaveBeenCalledWith("hello", false);
expect(result1[0]).toBe(false);
expect(mapSetSpy).toHaveBeenCalledWith("hello", [false, 0]);

mapGetSpy.mockClear();
mapSetSpy.mockClear();

// These should all use the same cache entry since they have the same core
const result2 = Strings.isWordRightToLeft("hello!", false);
expect(result2).toBe(false);
expect(result2[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("hello");
expect(mapSetSpy).not.toHaveBeenCalled();

mapGetSpy.mockClear();
mapSetSpy.mockClear();

const result3 = Strings.isWordRightToLeft("!hello", false);
expect(result3).toBe(false);
expect(result3[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("hello");
expect(mapSetSpy).not.toHaveBeenCalled();

mapGetSpy.mockClear();
mapSetSpy.mockClear();

const result4 = Strings.isWordRightToLeft("!hello!", false);
expect(result4).toBe(false);
expect(result4[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("hello");
expect(mapSetSpy).not.toHaveBeenCalled();
});

it("should handle cache clearing", () => {
// Cache a result
Strings.isWordRightToLeft("test", false);
expect(mapSetSpy).toHaveBeenCalledWith("test", false);
expect(mapSetSpy).toHaveBeenCalledWith("test", [false, 0]);

// Clear cache
Strings.clearWordDirectionCache();
Expand All @@ -434,23 +434,23 @@ describe("string utils", () => {

// Should work normally after cache clear (cache miss again)
const result = Strings.isWordRightToLeft("test", false);
expect(result).toBe(false);
expect(mapSetSpy).toHaveBeenCalledWith("test", false);
expect(result[0]).toBe(false);
expect(mapSetSpy).toHaveBeenCalledWith("test", [false, 0]);
});

it("should demonstrate cache miss vs cache hit behavior", () => {
// Test cache miss - first time seeing this word
const result1 = Strings.isWordRightToLeft("unique", false);
expect(result1).toBe(false);
expect(result1[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("unique");
expect(mapSetSpy).toHaveBeenCalledWith("unique", false);
expect(mapSetSpy).toHaveBeenCalledWith("unique", [false, 0]);

mapGetSpy.mockClear();
mapSetSpy.mockClear();

// Test cache hit - same word again
const result2 = Strings.isWordRightToLeft("unique", false);
expect(result2).toBe(false);
expect(result2[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("unique");
expect(mapSetSpy).not.toHaveBeenCalled(); // No cache set on hit

Expand All @@ -459,9 +459,9 @@ describe("string utils", () => {

// Test cache miss - different word
const result3 = Strings.isWordRightToLeft("different", false);
expect(result3).toBe(false);
expect(result3[0]).toBe(false);
expect(mapGetSpy).toHaveBeenCalledWith("different");
expect(mapSetSpy).toHaveBeenCalledWith("different", false);
expect(mapSetSpy).toHaveBeenCalledWith("different", [false, 0]);
});
});
});
Expand Down
1 change: 1 addition & 0 deletions frontend/src/html/pages/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@
<button data-config-value="13">wholetone</button>
<button data-config-value="14">fist fight</button>
<button data-config-value="15">rubber keys</button>
<button data-config-value="16">fart</button>
</div>
</div>
<div class="section fullWidth" data-config-name="playSoundOnError">
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/html/popups.html
Original file line number Diff line number Diff line change
Expand Up @@ -1060,9 +1060,17 @@
<br />
<span class="red">You can only do this once!</span>
</div>
<input type="number" min="-11" max="12" value="0" />
<div class="group">
<button class="decreaseOffset">
<i class="fas fa-fw fa-chevron-left"></i>
</button>
<input type="number" min="-11" max="12" value="0" step="0.5" />
<button class="increaseOffset">
<i class="fas fa-fw fa-chevron-right"></i>
</button>
</div>
<div class="preview"></div>
<button>set</button>
<button class="submit">set</button>
</div>
</dialog>
<dialog id="editResultTagsModal" class="modalWrapper hidden">
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/styles/popups.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,20 @@ body.darkMode {
.red {
color: var(--error-color);
}
.group {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 0.5rem;
justify-items: center;
align-items: center;
font-size: 2em;
button {
width: 100%;
}
input {
text-align: center;
}
}
.preview {
& > div:first-child {
margin-bottom: 1rem;
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/styles/test.scss
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@
&.rightToLeftTest {
//flex-direction: row-reverse; // no need for hacking 😉, CSS fully support right-to-left languages
direction: rtl;

.wordRtl {
unicode-bidi: bidi-override;
}
}
&.withLigatures {
.word {
Expand Down Expand Up @@ -789,6 +793,10 @@
&.rightToLeftTest {
//flex-direction: row-reverse; // no need for hacking 😉, CSS fully support right-to-left languages
direction: rtl;

.wordRtl {
unicode-bidi: bidi-override;
}
}
&.withLigatures {
.word {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/ts/commandline/commandline-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ export const commandlineConfigMetadata: CommandlineConfigMetadataObject = {
"13": "wholetone",
"14": "fist fight",
"15": "rubber keys",
"16": "fart",
};
return map[value];
},
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/ts/commandline/commandline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from "../elements/input-validation";
import { isInputElementFocused } from "../input/input-element";
import { qs } from "../utils/dom";
import { ConfigKey } from "@monkeytype/schemas/configs";

type CommandlineMode = "search" | "input";
type InputModeParams = {
Expand Down Expand Up @@ -70,7 +71,10 @@ function addCommandlineBackground(): void {
}

type ShowSettings = {
subgroupOverride?: CommandsSubgroup | string;
subgroupOverride?:
| CommandsSubgroup
| CommandlineLists.ListsObjectKeys
| ConfigKey;
commandOverride?: string;
singleListOverride?: boolean;
};
Expand Down Expand Up @@ -102,7 +106,7 @@ export function show(
if (exists) {
Loader.show();
subgroupOverride = await CommandlineLists.getList(
settings.subgroupOverride as CommandlineLists.ListsObjectKeys,
settings.subgroupOverride,
);
Loader.hide();
} else {
Expand Down
Loading
Loading