mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-07 09:42:10 +01:00
m now adds the row under the cursor to a set of marks and steps on, so
mmm picks up three; M takes the whole folder, Esc or :unmark puts it all
back. Marks stay while the list walks, so they can be gathered from
several folders. p, :mv and Shift+digit move the whole set.
With a pointer, Ctrl- or Cmd-click marks a row and Shift-click every row
from the cursor to it. Rows drag onto a folder row, a crumb or a space
pill; a marked row carries every marked node with it.
POST /api/nodes/move takes { ids, parent_id } and moves them all or
none: every node is checked before any moves, sealing into a sealed
folder happens before the one transaction that moves them, and two of a
name get slugs of their own. The single move goes the same way.
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
/*
|
|
* Rows dragged out of the list onto a folder row, a crumb or a space pill —
|
|
* the pointer's way of `m` and `p`. A marked row carries every marked node,
|
|
* any other row only itself. The nodes stay here; the drag carries a type of
|
|
* its own, so files from the desktop, or text, are never taken for them.
|
|
*/
|
|
import type { Attachment } from 'svelte/attachments'
|
|
import type { NodeSummary } from './api'
|
|
import { workspace } from './store.svelte'
|
|
|
|
const NODES = 'application/x-workspace-nodes'
|
|
|
|
let carried: NodeSummary[] = []
|
|
|
|
/** `ondragstart` of a row. */
|
|
export function carry(event: DragEvent, node: NodeSummary) {
|
|
if (!event.dataTransfer) return
|
|
carried = workspace.isMarked(node.id) ? workspace.marked : [node]
|
|
event.dataTransfer.setData(NODES, JSON.stringify(carried.map((n) => n.id)))
|
|
event.dataTransfer.effectAllowed = 'move'
|
|
}
|
|
|
|
/** `ondragend` of a row: dropped or not, nothing is carried any more. */
|
|
export function release() {
|
|
carried = []
|
|
}
|
|
|
|
/** Make an element a place the carried nodes can be dropped into `parent`. */
|
|
export function into(parent: number | null, where: string): Attachment<HTMLElement> {
|
|
return (element) => {
|
|
if (parent === null) return
|
|
// A folder does not take itself, or a drag that is not of rows.
|
|
const takes = (event: DragEvent) =>
|
|
!!event.dataTransfer?.types.includes(NODES) && carried.length > 0 && !carried.some((n) => n.id === parent)
|
|
const over = (event: DragEvent) => {
|
|
if (!takes(event)) return
|
|
event.preventDefault()
|
|
event.stopPropagation()
|
|
event.dataTransfer!.dropEffect = 'move'
|
|
element.classList.add('carry-over')
|
|
}
|
|
const leave = () => element.classList.remove('carry-over')
|
|
const drop = (event: DragEvent) => {
|
|
leave()
|
|
if (!takes(event)) return
|
|
event.preventDefault()
|
|
event.stopPropagation()
|
|
const nodes = carried
|
|
carried = []
|
|
void workspace.guard(() => workspace.moveNodes(nodes, parent, where))
|
|
}
|
|
element.addEventListener('dragover', over)
|
|
element.addEventListener('dragleave', leave)
|
|
element.addEventListener('drop', drop)
|
|
return () => {
|
|
element.removeEventListener('dragover', over)
|
|
element.removeEventListener('dragleave', leave)
|
|
element.removeEventListener('drop', drop)
|
|
}
|
|
}
|
|
}
|