From 661c1388124c986adf6f86ae50ae559c576646f4 Mon Sep 17 00:00:00 2001 From: Nad Alaba <37968805+NadAlaba@users.noreply.github.com> Date: Mon, 2 Sep 2024 13:10:45 +0300 Subject: [PATCH] fix(zen mode): issues when changing tape mode and other caret issues (@NadAlaba) (#5824) * fix(zen mode): undefined word when changing tape mode during test (@NadAlaba) * fix(zen mode): shrinking full-width-caret when changing tape mode during test (@NadAlaba) * fix(zen mode): messed up caret in RTL languages (@NadAlaba) because of the letter '_' that is added to the beginning of a word in zen mode, the caret is getting positioned on the 2nd letter. Also, since lastWordLetter is always undefined (because wordLen is always 0) offsetHeight and offsetTop are getting the default values regardless of font characteristics. * fix caret staying in position in (blind + word tape + zen) mode * refactor: combine last 2 solutions * rename parameter --- frontend/src/ts/commandline/commandline.ts | 3 ++- frontend/src/ts/test/caret.ts | 24 +++++++++++++--------- frontend/src/ts/test/test-ui.ts | 10 ++++----- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/frontend/src/ts/commandline/commandline.ts b/frontend/src/ts/commandline/commandline.ts index 18efbf9e1..190f77c4a 100644 --- a/frontend/src/ts/commandline/commandline.ts +++ b/frontend/src/ts/commandline/commandline.ts @@ -126,7 +126,8 @@ function hide(clearModalChain = false): void { clearModalChain, afterAnimation: async () => { addCommandlineBackground(); - if (ActivePage.get() === "test") { + const isWordsFocused = $("#wordsInput").is(":focus"); + if (ActivePage.get() === "test" && !isWordsFocused) { focusWords(); } }, diff --git a/frontend/src/ts/test/caret.ts b/frontend/src/ts/test/caret.ts index 3be4dfb4f..286d79447 100644 --- a/frontend/src/ts/test/caret.ts +++ b/frontend/src/ts/test/caret.ts @@ -49,6 +49,7 @@ function getTargetPositionLeft( fullWidthCaret: boolean, isLanguageRightToLeft: boolean, activeWordElement: HTMLElement, + underscoreAdded: boolean, currentWordNodeList: NodeListOf, fullWidthCaretWidth: number, wordLen: number, @@ -98,6 +99,8 @@ function getTargetPositionLeft( } } result = activeWordElement.offsetLeft + positionOffsetToWord; + if (underscoreAdded && isLanguageRightToLeft) + result += activeWordElement.offsetWidth; } else { const wordsWrapperWidth = $(document.querySelector("#wordsWrapper") as HTMLElement).width() ?? 0; @@ -129,10 +132,9 @@ export async function updatePosition(noAnim = false): Promise { Config.caretStyle ); - const wordLen = TestWords.words.getCurrent().length; + let wordLen = TestWords.words.getCurrent().length; const inputLen = TestInput.input.current.length; - const letterIsInvisibleExtra = - (Config.blindMode || Config.hideExtraLetters) && inputLen > wordLen; + if (Config.mode === "zen") wordLen = inputLen; const activeWordEl = document?.querySelector("#words .active") as HTMLElement; //insert temporary character so the caret will work in zen mode const activeWordEmpty = activeWordEl?.children.length === 0; @@ -153,28 +155,29 @@ export async function updatePosition(noAnim = false): Promise { | HTMLElement | undefined; - const spaceWidth = getSpaceWidth(activeWordEl); - const currentLanguage = await JSONData.getCurrentLanguage(Config.language); const isLanguageRightToLeft = currentLanguage.rightToLeft; // in blind mode, and hide extra letters, extra letters have zero offsets // offsetTop and offsetHeight is the same for all visible letters const letterHeight = + currentLetter?.offsetHeight || lastWordLetter?.offsetHeight || Config.fontSize * Numbers.convertRemToPixels(1); - const letterPosTop = lastWordLetter?.offsetTop ?? 0; + const letterPosTop = + currentLetter?.offsetTop || lastWordLetter?.offsetTop || 0; const diff = letterHeight - caret.offsetHeight; let newTop = activeWordEl.offsetTop + letterPosTop + diff / 2; if (Config.caretStyle === "underline") { newTop = activeWordEl.offsetTop + letterPosTop - caret.offsetHeight / 2; } - let letterWidth = currentLetter?.offsetWidth || spaceWidth; - if (currentLetter?.offsetWidth === 0 && !letterIsInvisibleExtra) { - // other than in extra letters in blind mode, it could be zero - // if current letter is a zero-width character e.g, diacritics) + let letterWidth = currentLetter?.offsetWidth; + if (letterWidth === undefined || activeWordEmpty) { + letterWidth = getSpaceWidth(activeWordEl); + } else if (letterWidth === 0) { + // current letter is a zero-width character e.g, diacritics) letterWidth = 0; for (let i = inputLen; i >= 0; i--) { letterWidth = (currentWordNodeList[i] as HTMLElement)?.offsetWidth; @@ -187,6 +190,7 @@ export async function updatePosition(noAnim = false): Promise { fullWidthCaret, isLanguageRightToLeft, activeWordEl, + activeWordEmpty, currentWordNodeList, letterWidth, wordLen, diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index b6db482c2..99c4d09f1 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -422,6 +422,10 @@ export function showWords(): void { }, 125); updateWordWrapperClasses(); + + if (Config.mode === "zen") { + $(document.querySelector(".word") as Element).remove(); + } } const posUpdateLangList = ["japanese", "chinese", "korean"]; @@ -508,7 +512,7 @@ function updateWordsHeight(force = false): void { CustomText.getLimitValue() !== 0 ) { // overflow-x should not be visible in tape mode, but since showAllLines can't - // be enabled simultaneously with tape mode we don' need to check it's off + // be enabled simultaneously with tape mode we don't need to check it's off $("#words") .css("height", "auto") .css("overflow", "visible clip") @@ -587,10 +591,6 @@ function updateWordsHeight(force = false): void { ); }, 0); } - - if (Config.mode === "zen") { - $(document.querySelector(".word") as Element).remove(); - } } export function addWord(word: string): void {