From 3e2495638d6f7cf405ab44a6c2525cf968af5898 Mon Sep 17 00:00:00 2001 From: Nad Alaba <37968805+nadalaba@users.noreply.github.com> Date: Wed, 15 Apr 2026 02:25:46 +0300 Subject: [PATCH 1/3] fix mutli line tape shifting horizontally --- frontend/src/ts/test/test-ui.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 71e3ca0fa80c..d3814069b3b8 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -955,6 +955,7 @@ export async function scrollTape(noAnimation = false): Promise { const widthRemovedFromLine: number[] = []; const afterNewlinesNewMargins: number[] = []; const toRemove: ElementWithUtils[] = []; + let removedAfterNewlines = 0; /* remove leading `.afterNewline` elements */ for (const child of wordsChildrenArr) { @@ -970,6 +971,7 @@ export async function scrollTape(noAnimation = false): Promise { toRemove.push(child); leadingNewLine = true; lastAfterNewLineElement = child; + removedAfterNewlines++; } } @@ -1051,6 +1053,7 @@ export async function scrollTape(noAnimation = false): Promise { /* remove overflown elements */ if (toRemove.length > 0) { for (const el of toRemove) el.remove(); + afterNewLineEls.splice(0, removedAfterNewlines); for (let i = 0; i < widthRemovedFromLine.length; i++) { const afterNewlineEl = afterNewLineEls[i] as ElementWithUtils; const currentLineIndent = From 6750a7e4b2f981c726f3c4ae889c177d365763b6 Mon Sep 17 00:00:00 2001 From: Nad Alaba <37968805+nadalaba@users.noreply.github.com> Date: Wed, 15 Apr 2026 11:34:02 +0300 Subject: [PATCH 2/3] refactor: use dom util getOuterWidth() --- frontend/src/ts/test/test-ui.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index d3814069b3b8..b6749f0e4b8f 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -980,7 +980,7 @@ export async function scrollTape(noAnimation = false): Promise { // index of the active word in all #words.children // (which contains .word/.newline/.beforeNewline/.afterNewline elements) const activeWordIndex = wordsChildrenArr.indexOf(activeWordEl); - // this will be 0 or 1 + // this will between 0 and 2 const newLinesBeforeActiveWord = wordsChildrenArr .slice(0, activeWordIndex) .filter((child) => child.hasClass("afterNewline")).length; @@ -1006,16 +1006,12 @@ export async function scrollTape(noAnimation = false): Promise { const child = wordsChildrenArr[i] as ElementWithUtils; if (child.hasClass("word")) { leadingNewLine = false; - const childComputedStyle = window.getComputedStyle(child.native); - const wordOuterWidth = - child.getOffsetWidth() + - parseFloat(childComputedStyle.marginRight) + - parseFloat(childComputedStyle.marginLeft); - const forWordLeft = Math.floor(child.getOffsetLeft()); - const forWordWidth = Math.floor(child.getOffsetWidth()); + const wordOuterWidth = child.getOuterWidth(); + const wordLeft = Math.floor(child.getOffsetLeft()); + const wordWidth = Math.floor(child.getOffsetWidth()); if ( - (!isTestRightToLeft && forWordLeft < 0 - forWordWidth) || - (isTestRightToLeft && forWordLeft > wordsWrapperWidth) + (!isTestRightToLeft && wordLeft < 0 - wordWidth) || + (isTestRightToLeft && wordLeft > wordsWrapperWidth) ) { toRemove.push(child); widthRemoved += wordOuterWidth; From c7667e800d414763fea5a13785824778f2001746 Mon Sep 17 00:00:00 2001 From: Nad Alaba <37968805+nadalaba@users.noreply.github.com> Date: Wed, 15 Apr 2026 11:17:01 +0300 Subject: [PATCH 3/3] fix multi line tape shifting vertically on linejump update #wordsInput position after linejumping because when overflow of #wordsWrapper is hidden (in tape mode), typing in #wordsInput causes automatic scrolling until it is visible don't return immediately when previousActiveWordTop is null because we need to updateWordsInputPosition when backspacing to previous word --- frontend/src/ts/test/test-ui.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index b6749f0e4b8f..a4cb58bb66a2 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -169,25 +169,25 @@ export function updateActiveElement( activeWordTop = newActiveWord.getOffsetTop(); activeWordHeight = newActiveWord.getOffsetHeight(); - updateWordsInputPosition(); - - if (previousActiveWordTop === null) return; - - const isTimedTest = - Config.mode === "time" || - (Config.mode === "custom" && CustomText.getLimitMode() === "time") || - (Config.mode === "custom" && CustomText.getLimitValue() === 0); + if (previousActiveWordTop !== null) { + const isTimedTest = + Config.mode === "time" || + (Config.mode === "custom" && CustomText.getLimitMode() === "time") || + (Config.mode === "custom" && CustomText.getLimitValue() === 0); - if (isTimedTest || !Config.showAllLines) { - const newActiveWordTop = newActiveWord.getOffsetTop(); - if (newActiveWordTop > previousActiveWordTop) { - await lineJump(previousActiveWordTop); + if (isTimedTest || !Config.showAllLines) { + const newActiveWordTop = newActiveWord.getOffsetTop(); + if (newActiveWordTop > previousActiveWordTop) { + await lineJump(previousActiveWordTop); + } } } if (!initial && Config.tapeMode !== "off") { await scrollTape(); } + + updateWordsInputPosition(); }); }