Skip to content

Commit

Permalink
Merge pull request #251 from mgreminger/drag-fixes
Browse files Browse the repository at this point in the history
fix: fix cell drag to reorder
  • Loading branch information
mgreminger authored Apr 7, 2024
2 parents d97fd90 + d3f5637 commit 65d25d4
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
const apiUrl = window.location.origin;
const currentVersion = 20240404;
const currentVersion = 20240406;
const tutorialHash = "fFjTsnFoSQMLwcvteVoNtL";
const termsVersion = 20240110;
Expand Down
105 changes: 51 additions & 54 deletions src/CellList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> {
let markdown = "";
Expand All @@ -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);
Expand All @@ -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 {
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -176,6 +172,7 @@
border: 2px solid lightgray;
border-radius: 10px;
position: fixed;
z-index: 100;
}
</style>

Expand All @@ -190,7 +187,7 @@
<li>
<ButtonBar on:insertSheet index={i} />
<div class="outer-container" class:first={i===0} class:last={i===$cells.length-1}
bind:this={containers[i]}
id={`cell-container-${i}`}
class:dragging={dragging && draggingSourceIndex === i}
>
<Cell
Expand Down
9 changes: 9 additions & 0 deletions src/Updates.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
}
</style>

<em>April 6, 2024</em>
<h4>Drag to Reorder Cells Improvements</h4>
<p>
Using the mouse or touch actions to drag and reorder cells has been improved
and no longer has issues after repeated drag events.
</p>

<br>

<em>April 4, 2024</em>
<h4>Differentiation and Integration Improvements</h4>
<p>
Expand Down
129 changes: 128 additions & 1 deletion tests/test_basic.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
});

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);

});

0 comments on commit 65d25d4

Please sign in to comment.