From e625d5abad7bcb0f38f83b430a95b88816c6c7ef Mon Sep 17 00:00:00 2001 From: mgreminger Date: Sat, 6 Apr 2024 19:24:47 -0500 Subject: [PATCH 1/3] fix: fix cell drag to reorder --- src/CellList.svelte | 105 +++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/src/CellList.svelte b/src/CellList.svelte index 40610c65..e433ef5a 100644 --- a/src/CellList.svelte +++ b/src/CellList.svelte @@ -6,15 +6,14 @@ import Cell from "./Cell.svelte"; import ButtonBar from "./ButtonBar.svelte"; - let containers = []; let cellElements: Cell[] = []; let dragging = false; - let draggingSourceIndex; - let draggingContainer; - let draggingSkeleton; - let grabOffset; - let scrollingContainer; - let sheetBody; + let draggingSourceIndex: number; + let draggingSkeleton: HTMLDivElement; + let skeletonHeight: number; + let grabOffset: number; + let scrollingContainer: HTMLElement; + let sheetBody: HTMLUListElement; export async function getMarkdown(): Promise { let markdown = ""; @@ -28,29 +27,33 @@ return markdown; } - async function startDrag(event) { + function startDrag(event) { if (!dragging) { + draggingSourceIndex = event.detail.index; + scrollingContainer = document.getElementById("main-content"); + const draggingContainer = document.getElementById(`cell-container-${draggingSourceIndex}`); - draggingContainer = containers[event.detail.index]; + if (!(scrollingContainer && draggingContainer)) { + return; + } $activeCell = -1; - await tick(); - const skeletonHeight = Math.min(scrollingContainer.getBoundingClientRect().height/2, - draggingContainer.getBoundingClientRect().height); + const draggingContainerRect = draggingContainer.getBoundingClientRect(); + + skeletonHeight = Math.min(scrollingContainer.getBoundingClientRect().height/2, + draggingContainerRect.height); grabOffset = skeletonHeight / 2.0; draggingSkeleton.style.top = `${event.detail.clientY-grabOffset}px`; - draggingSkeleton.style.left = `${draggingContainer.getBoundingClientRect().left}px`; + draggingSkeleton.style.left = `${draggingContainerRect.left}px`; draggingSkeleton.style.height = `${skeletonHeight}px`; - draggingSkeleton.style.width = `${draggingContainer.getBoundingClientRect().width}px`; + draggingSkeleton.style.width = `${draggingContainerRect.width}px`; dragging = true; - draggingSourceIndex = event.detail.index; - document.body.style.cursor = "grabbing"; window.addEventListener("mousemove", dragMove); @@ -77,7 +80,7 @@ if (dragging) { event.preventDefault(); // prevent scrolling on touch screens - let clientY; + let clientY: number; if (event.type === "touchmove") { clientY = event.changedTouches[0].clientY; } else { @@ -95,50 +98,43 @@ scrollingContainer.scroll(0, scrollingContainer.scrollTop + (skeletonRect.bottom - scrollRect.bottom)); } - let targetIndex = null; - for (const [i, container] of containers.entries()) { - if (container && container !== draggingContainer) { - const rect = container.getBoundingClientRect() - if (clientY > rect.top && clientY < rect.bottom) { + let targetIndex: number | null = null; + for (let i = 0; i < $cells.length; i++) { + const container = document.getElementById(`cell-container-${i}`); + if (container && i !== draggingSourceIndex) { + const rect = container.getBoundingClientRect(); + if (i === 0 && clientY < rect.top) { + targetIndex = 0; + break; + } else if (i === $cells.length - 1 && clientY > rect.bottom) { + targetIndex = $cells.length - 1; + break; + } else if (draggingSourceIndex < i && clientY >= Math.max(rect.top, rect.bottom - skeletonHeight) && clientY <= rect.bottom) { + targetIndex = i; + break; + } else if (draggingSourceIndex > i && clientY >= rect.top && clientY <= Math.min(rect.bottom, rect.top + skeletonHeight)) { targetIndex = i; - - if (targetIndex !== draggingSourceIndex) { - if (clientY < 0.5*(rect.bottom + rect.top)) { - if (draggingSourceIndex === targetIndex - 1) { - // already moved above this element, need to prevent swapping - targetIndex = draggingSourceIndex; - } - } else { - targetIndex = i < $cells.length - 1 ? i + 1 : i - } - } - break; } } } - if (targetIndex !== null) { - if (targetIndex !== draggingSourceIndex) { - // can't jump more than one cell at a time or order will be changed before drop - if (targetIndex - draggingSourceIndex > 1) { - targetIndex = draggingSourceIndex + 1; - } else if (draggingSourceIndex - targetIndex > 1) { - targetIndex = draggingSourceIndex - 1; - } - - // Update cell location - // Need to make a shallow copy of $cells since destructuring assignment - // cannont be used on a reactive array. - let newCells = [...$cells]; - [newCells[draggingSourceIndex], newCells[targetIndex]] = [newCells[targetIndex], newCells[draggingSourceIndex]]; - $cells = newCells; + if (targetIndex !== null && targetIndex !== draggingSourceIndex) { + if (draggingSourceIndex > targetIndex) { + $cells = [...$cells.slice(0,targetIndex), $cells[draggingSourceIndex], + ...$cells.slice(targetIndex, draggingSourceIndex), + ...$cells.slice(draggingSourceIndex+1)]; + } else { + $cells = [...$cells.slice(0,draggingSourceIndex), + ...$cells.slice(draggingSourceIndex+1, targetIndex+1), + $cells[draggingSourceIndex], + ...$cells.slice(targetIndex+1)]; + } - draggingSourceIndex = targetIndex + draggingSourceIndex = targetIndex; - $results = []; - $mathCellChanged = true; - } + $results = []; + $mathCellChanged = true; } } @@ -176,6 +172,7 @@ border: 2px solid lightgray; border-radius: 10px; position: fixed; + z-index: 100; } @@ -190,7 +187,7 @@
  • Date: Sat, 6 Apr 2024 23:07:00 -0500 Subject: [PATCH 2/3] tests: add drag to reorder cells test --- tests/test_basic.spec.mjs | 129 +++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/tests/test_basic.spec.mjs b/tests/test_basic.spec.mjs index db2a41dc..838ff552 100644 --- a/tests/test_basic.spec.mjs +++ b/tests/test_basic.spec.mjs @@ -1509,4 +1509,131 @@ test('Test angular frequency conversions', async () => { expect(parseLatexFloat(content)).toBeCloseTo(3/pi, precision); content = await page.textContent('#result-units-4'); expect(content).toBe('s^-1'); -}); \ No newline at end of file +}); + +test('Test cell drag to reorder', async () => { + await page.locator('#cell-0 >> math-field.editable').type("0="); + + await page.locator('#add-math-cell').click(); + await page.locator('#cell-1 >> math-field.editable').type("1="); + + await page.locator('#add-math-cell').click(); + await page.locator('#cell-2 >> math-field.editable').type("2="); + + await page.locator('#add-math-cell').click(); + await page.locator('#cell-3 >> math-field.editable').type("3="); + + await page.locator('#add-math-cell').click(); + await page.locator('#cell-4 >> math-field.editable').type("4="); + + await page.locator('#add-math-cell').click(); + await page.locator('#cell-5 >> math-field.editable').type("5="); + + await page.locator('#add-math-cell').click(); + await page.locator('#cell-6 >> math-field.editable').type("6="); + + await page.locator('#cell-container-0 >> button[title="Drag to Move Cell"]') + .dragTo(page.locator('#cell-container-6 >> button[title="Drag to Move Cell"]')); + + await page.waitForSelector('.status-footer', { state: 'detached'}); + + let content = await page.textContent('#result-value-0'); + expect(parseLatexFloat(content)).toBeCloseTo(1, precision); + + content = await page.textContent('#result-value-1'); + expect(parseLatexFloat(content)).toBeCloseTo(2, precision); + + content = await page.textContent('#result-value-2'); + expect(parseLatexFloat(content)).toBeCloseTo(3, precision); + + content = await page.textContent('#result-value-3'); + expect(parseLatexFloat(content)).toBeCloseTo(4, precision); + + content = await page.textContent('#result-value-4'); + expect(parseLatexFloat(content)).toBeCloseTo(5, precision); + + content = await page.textContent('#result-value-5'); + expect(parseLatexFloat(content)).toBeCloseTo(6, precision); + + content = await page.textContent('#result-value-6'); + expect(parseLatexFloat(content)).toBeCloseTo(0, precision); + + await page.locator('#cell-container-6 >> button[title="Drag to Move Cell"]') + .dragTo(page.locator('#cell-container-5 >> button[title="Drag to Move Cell"]')); + + await page.waitForSelector('.status-footer', { state: 'detached'}); + + content = await page.textContent('#result-value-0'); + expect(parseLatexFloat(content)).toBeCloseTo(1, precision); + + content = await page.textContent('#result-value-1'); + expect(parseLatexFloat(content)).toBeCloseTo(2, precision); + + content = await page.textContent('#result-value-2'); + expect(parseLatexFloat(content)).toBeCloseTo(3, precision); + + content = await page.textContent('#result-value-3'); + expect(parseLatexFloat(content)).toBeCloseTo(4, precision); + + content = await page.textContent('#result-value-4'); + expect(parseLatexFloat(content)).toBeCloseTo(5, precision); + + content = await page.textContent('#result-value-5'); + expect(parseLatexFloat(content)).toBeCloseTo(0, precision); + + content = await page.textContent('#result-value-6'); + expect(parseLatexFloat(content)).toBeCloseTo(6, precision); + + await page.locator('#cell-container-5 >> button[title="Drag to Move Cell"]') + .dragTo(page.locator('#cell-container-0 >> button[title="Drag to Move Cell"]')); + + await page.waitForSelector('.status-footer', { state: 'detached'}); + + content = await page.textContent('#result-value-0'); + expect(parseLatexFloat(content)).toBeCloseTo(0, precision); + + content = await page.textContent('#result-value-1'); + expect(parseLatexFloat(content)).toBeCloseTo(1, precision); + + content = await page.textContent('#result-value-2'); + expect(parseLatexFloat(content)).toBeCloseTo(2, precision); + + content = await page.textContent('#result-value-3'); + expect(parseLatexFloat(content)).toBeCloseTo(3, precision); + + content = await page.textContent('#result-value-4'); + expect(parseLatexFloat(content)).toBeCloseTo(4, precision); + + content = await page.textContent('#result-value-5'); + expect(parseLatexFloat(content)).toBeCloseTo(5, precision); + + content = await page.textContent('#result-value-6'); + expect(parseLatexFloat(content)).toBeCloseTo(6, precision); + + await page.locator('#cell-container-1 >> button[title="Drag to Move Cell"]') + .dragTo(page.locator('#cell-container-2 >> button[title="Drag to Move Cell"]')); + + await page.waitForSelector('.status-footer', { state: 'detached'}); + + content = await page.textContent('#result-value-0'); + expect(parseLatexFloat(content)).toBeCloseTo(0, precision); + + content = await page.textContent('#result-value-1'); + expect(parseLatexFloat(content)).toBeCloseTo(2, precision); + + content = await page.textContent('#result-value-2'); + expect(parseLatexFloat(content)).toBeCloseTo(1, precision); + + content = await page.textContent('#result-value-3'); + expect(parseLatexFloat(content)).toBeCloseTo(3, precision); + + content = await page.textContent('#result-value-4'); + expect(parseLatexFloat(content)).toBeCloseTo(4, precision); + + content = await page.textContent('#result-value-5'); + expect(parseLatexFloat(content)).toBeCloseTo(5, precision); + + content = await page.textContent('#result-value-6'); + expect(parseLatexFloat(content)).toBeCloseTo(6, precision); + +}); From d3f563711f206a419cfd78c726b3aec62caafea9 Mon Sep 17 00:00:00 2001 From: mgreminger Date: Sun, 7 Apr 2024 00:05:52 -0500 Subject: [PATCH 3/3] Bump version and update new features dialog --- src/App.svelte | 2 +- src/Updates.svelte | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/App.svelte b/src/App.svelte index 3572ac09..4de08b1b 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -90,7 +90,7 @@ const apiUrl = window.location.origin; - const currentVersion = 20240404; + const currentVersion = 20240406; const tutorialHash = "fFjTsnFoSQMLwcvteVoNtL"; const termsVersion = 20240110; diff --git a/src/Updates.svelte b/src/Updates.svelte index 31686199..a4159e33 100644 --- a/src/Updates.svelte +++ b/src/Updates.svelte @@ -16,6 +16,15 @@ } +April 6, 2024 +

    Drag to Reorder Cells Improvements

    +

    + Using the mouse or touch actions to drag and reorder cells has been improved + and no longer has issues after repeated drag events. +

    + +
    + April 4, 2024

    Differentiation and Integration Improvements