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
11 changes: 6 additions & 5 deletions src/ui/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,9 +291,10 @@ export class FormulaDisplay {
let nearest: { dist: number; g: any; key: string } | null = null;
const cands: { dist: number; g: any; key: string; bl: number }[] = [];
for (const [key, g] of lay.rows) {
// the stops of a right-to-left row run backwards: its extent is the span between the two ends, whichever is left
const hxs = g.hx ?? g.xs;
const x1 = hxs[0];
const x2 = hxs[hxs.length - 1];
const x1 = Math.min(hxs[0], hxs[hxs.length - 1]);
const x2 = Math.max(hxs[0], hxs[hxs.length - 1]);
const bands: { y: number; a: number; d: number }[] = key === '' ? lay.lines.map((l) => ({ y: l.y, a: l.a, d: l.d })) : [{ y: g.y, a: g.a, d: g.d }];
for (const bnd of bands) {
// table cells and slots have padding around their content; empty slots show a small box
Expand Down Expand Up @@ -327,16 +328,16 @@ export class FormulaDisplay {
if (root && root.structs) {
let ei = -1;
for (let i = 0; i < root.structs.length; i++) {
if (root.structs[i] && px >= root.xs[i] && px <= root.xs[i + 1]) ei = i;
if (root.structs[i] && px >= Math.min(root.xs[i], root.xs[i + 1]) && px <= Math.max(root.xs[i], root.xs[i + 1])) ei = i;
}
if (ei >= 0) {
let near: { dist: number; g: any; key: string } | null = null;
for (const [key, g] of lay.rows) {
if (key === '' || !g.path.length || g.path[0][0] !== ei) continue;
if (g.stops && !g.stops.some(Boolean)) continue;
const bnd = { y: g.y, a: g.a, d: g.d };
const x1 = g.xs[0];
const x2 = g.xs[g.xs.length - 1];
const x1 = Math.min(g.xs[0], g.xs[g.xs.length - 1]);
const x2 = Math.max(g.xs[0], g.xs[g.xs.length - 1]);
const dx = px < x1 ? x1 - px : px > x2 ? px - x2 : 0;
const dy = py < bnd.y - bnd.a ? bnd.y - bnd.a - py : py > bnd.y + bnd.d ? py - bnd.y - bnd.d : 0;
const dist = dx * dx + dy * dy * 4;
Expand Down
10 changes: 10 additions & 0 deletions src/ui/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ export class MathEditor implements ToolbarHost {
const pe = e as PointerEvent;
if (pe.pointerType !== 'touch' || !pe.isPrimary) return;
this.lastTouchAt = Date.now();
this.touchPt = { x: pe.clientX, y: pe.clientY, t: this.lastTouchAt };
cancelPress();
pressAt = { x: pe.clientX, y: pe.clientY };
press = setTimeout(() => {
Expand Down Expand Up @@ -1343,9 +1344,18 @@ export class MathEditor implements ToolbarHost {

/* ---------------------------------------------------------------- mouse */
private contentPoint(e: MouseEvent): { x: number; y: number } {
// the mouse events a browser sends for a tap carry a "touch adjusted" position (snapped to the nearest clickable
// thing, a few pixels away from the finger): the caret goes where the finger touched, not where the browser moved it
const tp = this.touchPt;
if ((e.type === 'mousedown' || e.type === 'dblclick') && Date.now() - tp.t < 1000 && Math.hypot(e.clientX - tp.x, e.clientY - tp.y) < 48) {
return this.display.toContent(tp.x, tp.y);
}
return this.display.toContent(e.clientX, e.clientY);
}

/** where the last finger went down (client px) and when */
private touchPt = { x: 0, y: 0, t: 0 };

private longPressedAt = 0;
private lastTouchAt = 0;

Expand Down
51 changes: 51 additions & 0 deletions tools/probe_rtl_touch.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// RTL vs LTR on a phone, directly on the formula: tap every caret position of every row, double tap, long press + handle drags
const { chromium } = require('playwright');
const NS = 'xmlns="http://www.w3.org/1998/Math/MathML"';
const F = {
flat: '<mi>a</mi><mo>+</mo><mn>12</mn><mo>=</mo><mi>c</mi><mo>-</mo><mi>d</mi>',
arabic: '<mi>س</mi><mo>+</mo><mi>ص</mi><mo>=</mo><mn>٣</mn><mo>×</mo><mi>ع</mi>',
frac: '<mi>x</mi><mo>+</mo><mfrac><mrow><mi>a</mi><mo>+</mo><mn>1</mn></mrow><mrow><mi>b</mi><mo>-</mo><mi>c</mi></mrow></mfrac><mo>=</mo><msqrt><mi>y</mi><mo>+</mo><mn>2</mn></msqrt>',
mix: '<mtext>مرحبا بالعالم</mtext><mo>+</mo><mn>12</mn><mo>=</mo><msup><mi>x</mi><mn>2</mn></msup>',
};
(async () => {
const b = await chromium.launch({ channel: 'chrome' });
for (const name of (process.env.ONLY||Object.keys(F).join(",")).split(",")) for (const rtl of [false, true]) {
const ctx = await b.newContext({ viewport: { width: 390, height: 844 }, hasTouch: true, isMobile: true, deviceScaleFactor: 2 });
const p = await ctx.newPage();
await p.goto(process.env.URL || 'http://localhost:8099/?output=0');
await p.waitForFunction(() => window.editor && document.querySelector('#editorContainer .wrs_toolbar button'));
await p.waitForTimeout(600);
await p.evaluate(({ rtl, NS, m }) => editor.setMathML(`<math ${rtl ? 'dir="rtl" ' : ''}${NS}>${m}</math>`), { rtl, NS, m: F[name] });
await p.waitForTimeout(500);
await p.touchscreen.tap(200, 700); await p.waitForTimeout(1200);
// every row, every caret position: client x/y of the position, then tap slightly inside the cell toward each neighbour
const rows = await p.evaluate(() => {
const d = editor.display, lay = d.layout, r = d.content.getBoundingClientRect(), out = [];
for (const [key, g] of lay.rows) {
const y = key === '' ? lay.lines[0].y : g.y;
out.push({ key, path: g.path, xs: g.xs.map((x) => r.left + x), hx: (g.hx || g.xs).map((x) => r.left + x), y: r.top + y - g.a / 2 });
}
return out;
});
let bad = 0, n = 0;
for (const row of rows) {
const hx = row.hx;
for (let i = 0; i < hx.length; i++) {
// tap exactly on the stop, then 2px toward the inside
for (const dx of [0]) {
const x = hx[i] + dx;
await p.touchscreen.tap(x, row.y);
await p.waitForTimeout(Number(process.env.GAP||650));
const got = await p.evaluate(() => ({ p: JSON.stringify(editor.core.caret.path), i: editor.core.caret.index }));
n++;
// acceptable: same row & index, or a neighbouring stop at the same x
const ok = got.p === JSON.stringify(row.path) && (got.i === i || Math.abs(hx[got.i] - hx[i]) < 1.5);
if (!ok) { bad++; console.log(` ${name} ${rtl ? 'RTL' : 'LTR'} row "${row.key}" stop ${i} x=${Math.round(x)} y=${Math.round(row.y)} -> ${got.p} ${got.i}`); }
}
}
}
console.log(`${name} ${rtl ? 'RTL' : 'LTR'}: ${n} taps, ${bad} off`);
await ctx.close();
}
await b.close();
})().catch((e) => { console.error(e); process.exit(1); });
Loading