Skip to content
Open
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
46 changes: 21 additions & 25 deletions frontend/src/ts/elements/caret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,59 +446,53 @@ export class Caret {
}

const spaceWidth = getTotalInlineMargin(options.word.native);
let width = spaceWidth;
if (this.isFullWidth() && options.side === "beforeLetter") {
width = letter.getOffsetWidth();
let width = letter.getOffsetWidth();
if (options.side === "afterLetter") {
width = spaceWidth;
}

let left = 0;
let top = 0;

const tapeOffset =
wordsWrapperCache.getOffsetWidth() * (Config.tapeMargin / 100);
const isTestRightToLeft = options.isDirectionReversed
? !options.isLanguageRightToLeft
: options.isLanguageRightToLeft;

let tapeOffsetRatio = Config.tapeMargin / 100;
if (isTestRightToLeft) tapeOffsetRatio = 1 - tapeOffsetRatio;
const tapeOffset = wordsWrapperCache.getOffsetWidth() * tapeOffsetRatio;

// yes, this is all super verbose, but its easier to maintain and understand
if (isWordRTL) {
if (!checkRtlByLetter && isFullMatch) options.word.addClass("wordRtl");
let afterLetterCorrection = 0;
if (options.side === "afterLetter") {
if (this.isFullWidth()) {
afterLetterCorrection += spaceWidth * -1;
} else {
afterLetterCorrection += letter.getOffsetWidth() * -1;
}
if (this.isFullWidth() && options.side === "afterLetter") {
afterLetterCorrection += spaceWidth * -1;
} else if (!this.isFullWidth() && options.side === "beforeLetter") {
afterLetterCorrection += width;
}
if (Config.tapeMode === "off") {
if (!this.isFullWidth()) {
left += letter.getOffsetWidth();
}
left += letter.getOffsetLeft();
left += options.word.getOffsetLeft();
left += afterLetterCorrection;
} else if (Config.tapeMode === "word") {
if (!this.isFullWidth()) {
left += letter.getOffsetWidth();
}
left += options.word.getOffsetWidth() * -1;
left += letter.getOffsetLeft();
left += afterLetterCorrection;
if (this.isMainCaret && lockedMainCaretInTape) {
left += wordsWrapperCache.getOffsetWidth() - tapeOffset;
left += tapeOffset - options.word.getOffsetWidth();
left += spaceWidth * 0.5; // center current letter
} else {
left += options.word.getOffsetLeft();
left += options.word.getOffsetWidth();
}
} else if (Config.tapeMode === "letter") {
if (this.isFullWidth()) {
left += width * -1;
}
if (this.isMainCaret && lockedMainCaretInTape) {
left += wordsWrapperCache.getOffsetWidth() - tapeOffset;
left += tapeOffset;
if (this.isFullWidth()) left += width * -1;
left += spaceWidth * 0.5; // center current letter
} else {
left += letter.getOffsetLeft();
left += options.word.getOffsetLeft();
left += afterLetterCorrection;
left += width;
}
}
} else {
Expand All @@ -515,12 +509,14 @@ export class Caret {
left += afterLetterCorrection;
if (this.isMainCaret && lockedMainCaretInTape) {
left += tapeOffset;
left += spaceWidth * -0.5; // center current letter
} else {
left += options.word.getOffsetLeft();
}
} else if (Config.tapeMode === "letter") {
if (this.isMainCaret && lockedMainCaretInTape) {
left += tapeOffset;
left += spaceWidth * -0.5; // center current letter
} else {
left += letter.getOffsetLeft();
left += options.word.getOffsetLeft();
Expand Down
39 changes: 32 additions & 7 deletions frontend/src/ts/test/funbox/funbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,16 +219,41 @@ async function setFunboxBodyClasses(): Promise<boolean> {
return true;
}

async function applyFunboxCSS(): Promise<boolean> {
async function applyFunboxCSS(): Promise<void> {
qsa(".funBoxTheme").remove();

await Promise.all(
getActiveFunboxesWithProperty("hasCssFile").map(
async (funbox) =>
new Promise<void>((resolve, reject) => {
const css = document.createElement("link");
css.classList.add("funBoxTheme");
css.rel = "stylesheet";
css.href = "funbox/" + funbox.name + ".css";
css.onload = () => resolve();
css.onerror = reject;
document.head.appendChild(css);
}),
),
);

/*
const promises = [];
for (const funbox of getActiveFunboxesWithProperty("hasCssFile")) {
const css = document.createElement("link");
css.classList.add("funBoxTheme");
css.rel = "stylesheet";
css.href = "funbox/" + funbox.name + ".css";
document.head.appendChild(css);
promises.push(
new Promise<void>((resolve, reject) => {
const css = document.createElement("link");
css.classList.add("funBoxTheme");
css.rel = "stylesheet";
css.href = "funbox/" + funbox.name + ".css";
css.onload = () => resolve();
css.onerror = reject;
document.head.appendChild(css);
}),
);
}
return true;
await Promise.all(promises);
*/
}

configEvent.subscribe(async ({ key }) => {
Expand Down
89 changes: 63 additions & 26 deletions frontend/src/ts/test/test-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ import {
import { getTheme } from "../states/theme";
import { skipBreakdownEvent } from "../states/header";
import { wordsHaveNewline } from "../states/test";
import { isWordRightToLeft } from "../utils/strings";
import { getTotalInlineMargin } from "../utils/misc";

export const updateHintsPositionDebounced = Misc.debounceUntilResolved(
updateHintsPosition,
Expand Down Expand Up @@ -995,9 +997,7 @@ export async function scrollTape(noAnimation = false): Promise<void> {
}
}

const wordRightMargin = parseFloat(
window.getComputedStyle(activeWordEl.native).marginRight,
);
const spaceWidth = getTotalInlineMargin(activeWordEl.native);

/*calculate .afterNewline & #words new margins + determine elements to remove*/
for (let i = 0; i <= lastElementIndex; i++) {
Expand All @@ -1024,7 +1024,7 @@ export async function scrollTape(noAnimation = false): Promise<void> {
} else if (child.hasClass("afterNewline")) {
if (leadingNewLine) continue;
const nlCharWidth = getNlCharWidth(wordsChildrenArr[i - 3]);
fullLineWidths -= nlCharWidth + wordRightMargin;
fullLineWidths -= nlCharWidth + spaceWidth;
if (i < activeWordIndex) wordsWidthBeforeActive = fullLineWidths;

/** words that are wider than limit can cause a barely visible bottom line shifting,
Expand Down Expand Up @@ -1067,43 +1067,80 @@ export async function scrollTape(noAnimation = false): Promise<void> {
}

/* calculate current word width to add to #words margin */
let inputWord = TestInput.input.current;
const targetWord = TestWords.words.getCurrent() || inputWord; // fallback for zen mode
const [isActiveWordRTL, _] = isWordRightToLeft(
targetWord,
TestState.isLanguageRightToLeft,
TestState.isDirectionReversed,
);
let currentWordWidth = 0;
const inputLength = TestInput.input.current.length;
if (Config.tapeMode === "letter" && inputLength > 0) {
const letters = activeWordEl.qsa("letter");
let lastPositiveLetterWidth = 0;
for (let i = 0; i < inputLength; i++) {
const letter = letters[i];
if (
(Config.blindMode || Config.hideExtraLetters) &&
letter?.hasClass("extra")
) {
continue;
}
const letterOuterWidth = letter?.getOffsetWidth() ?? 0;
currentWordWidth += letterOuterWidth;
if (letterOuterWidth > 0) lastPositiveLetterWidth = letterOuterWidth;
if (Config.tapeMode === "letter") {
let inputLength = inputWord.length;
const targetWordLength = targetWord.length;
if (Config.blindMode || Config.hideExtraLetters) {
inputLength = Math.min(targetWordLength, inputLength);
}

let letterIndex;
let side: "beforeLetter" | "afterLetter";
if (
inputLength < targetWordLength ||
(Config.mode === "zen" && inputLength === 0)
) {
side = "beforeLetter";
letterIndex = inputLength;
} else {
side = "afterLetter";
letterIndex = inputLength - 1;
}

// if current letter has zero width move the tape to previous positive width letter
if (letters[inputLength]?.getOffsetWidth() === 0) {
currentWordWidth -= lastPositiveLetterWidth;
let i = letterIndex;
const letters = activeWordEl.qsa("letter");
let ltr;
while ((ltr = letters[i]) && ltr.getOffsetWidth() === 0 && i > 0) i--;
let currentLetterOffset = ltr?.getOffsetLeft() ?? 0;
let currentLetterWidth = ltr?.getOffsetWidth() ?? 0;
if (side === "afterLetter") currentLetterWidth = spaceWidth;

if (
(isActiveWordRTL && side === "beforeLetter") ||
(!isActiveWordRTL && side === "afterLetter")
) {
currentLetterOffset += currentLetterWidth;
}

if (isTestRightToLeft) {
currentWordWidth = activeWordEl.getOffsetWidth() - currentLetterOffset;
} else {
currentWordWidth = currentLetterOffset;
}
}

if (Config.tapeMode === "word" && isTestRightToLeft !== isActiveWordRTL) {
currentWordWidth += activeWordEl.getOffsetWidth();
}

/* change to new #words & .afterNewline margins */
const tapeMarginPx = wordsWrapperWidth * (Config.tapeMargin / 100);
let newMarginOffset = wordsWidthBeforeActive + currentWordWidth;
let newMargin = tapeMarginPx - newMarginOffset;
let typedWidth = -1 * (wordsWidthBeforeActive + currentWordWidth);
let newMargin = tapeMarginPx + typedWidth;
if (isTestRightToLeft) {
newMarginOffset *= -1;
newMargin = wordRightMargin - newMargin;
typedWidth *= -1;
newMargin *= -1;
newMargin += spaceWidth;
}

// center current letter
if (isActiveWordRTL) newMargin += 0.5 * spaceWidth;
else newMargin -= 0.5 * spaceWidth;

const duration = noAnimation ? 0 : 125;
const ease = "inOut(1.25)";

const caretScrollOptions = {
newValue: newMarginOffset * -1,
newValue: typedWidth,
duration: Config.smoothLineScroll ? duration : 0,
ease,
};
Expand Down
Loading