Rebounce navigation events
This commit is contained in:
@@ -53,12 +53,19 @@ export class FSNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
last_requested_path: string = ""
|
||||
navigate = async (path: string, push_history: boolean) => {
|
||||
if (path === this.last_requested_path) {
|
||||
console.debug("FSNavigator: Requested path is equal to current path. Debouncing")
|
||||
return
|
||||
}
|
||||
this.last_requested_path = path
|
||||
|
||||
if (path[0] !== "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
console.debug("Navigating to path", path, push_history)
|
||||
console.debug("FSNavigator: Navigating to path", path, push_history)
|
||||
|
||||
try {
|
||||
loading_start()
|
||||
|
||||
@@ -69,7 +69,7 @@ const file_event: FileActionHandler = (action: FileAction, index: number, orig:
|
||||
if (navigator.maxTouchPoints && navigator.maxTouchPoints > 0) {
|
||||
select_node(index)
|
||||
} else {
|
||||
file_menu.open(nav.children[index], orig.target)
|
||||
file_menu.open(nav.children[index], orig.target, orig)
|
||||
}
|
||||
break
|
||||
case FileAction.Edit:
|
||||
@@ -86,7 +86,7 @@ const file_event: FileActionHandler = (action: FileAction, index: number, orig:
|
||||
select_node(index)
|
||||
break
|
||||
case FileAction.Menu:
|
||||
file_menu.open(nav.children[index], orig.target)
|
||||
file_menu.open(nav.children[index], orig.target, orig)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,23 @@ let {
|
||||
let dialog: Dialog = $state()
|
||||
let node: FSNode = $state(null)
|
||||
|
||||
export const open = async (n: FSNode, target: EventTarget) => {
|
||||
export const open = async (n: FSNode, target: EventTarget, event: Event) => {
|
||||
node = n
|
||||
let el: HTMLElement = (target as Element).closest("button")
|
||||
if (el === null) {
|
||||
el = (target as Element).closest("a")
|
||||
}
|
||||
|
||||
// Wait for the view to update, so the dialog gets the proper measurements
|
||||
await tick()
|
||||
dialog.open(el.getBoundingClientRect())
|
||||
|
||||
let el: HTMLElement = (target as Element).closest("button")
|
||||
if (el !== null) {
|
||||
dialog.open(el.getBoundingClientRect())
|
||||
return
|
||||
}
|
||||
|
||||
if (event instanceof MouseEvent) {
|
||||
dialog.open(event)
|
||||
return
|
||||
}
|
||||
|
||||
console.error("Cannot find suitable target for spawning dialog window")
|
||||
}
|
||||
|
||||
const delete_node = async () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ let { children }: {
|
||||
} = $props();
|
||||
let dialog: HTMLDialogElement = $state()
|
||||
|
||||
export const open = (button_rect: DOMRect) => {
|
||||
export const open = (origin: DOMRect|MouseEvent) => {
|
||||
// Show the window so we can get the location
|
||||
dialog.showModal()
|
||||
|
||||
@@ -15,10 +15,18 @@ export const open = (button_rect: DOMRect) => {
|
||||
const max_left = window.innerWidth - dialog_rect.width - edge_offset
|
||||
const max_top = window.innerHeight - dialog_rect.height - edge_offset
|
||||
|
||||
// Position the dialog in horizontally in the center of the button and
|
||||
// verticially below it
|
||||
const min_left = Math.max((button_rect.left + (button_rect.width/2)) - (dialog_rect.width/2), edge_offset)
|
||||
const min_top = Math.max(button_rect.bottom, edge_offset)
|
||||
let min_left: number, min_top: number
|
||||
if (origin instanceof DOMRect) {
|
||||
// Position the dialog in horizontally in the center of the button and
|
||||
// verticially below it
|
||||
min_left = Math.max((origin.left + (origin.width/2)) - (dialog_rect.width/2), edge_offset)
|
||||
min_top = Math.max(origin.bottom, edge_offset)
|
||||
} else if (origin instanceof MouseEvent) {
|
||||
// Place the dialog at the bottom right of the mouse pointer, like
|
||||
// regular context menus
|
||||
min_left = Math.max(origin.clientX, edge_offset)
|
||||
min_top = Math.max(origin.clientY, edge_offset)
|
||||
}
|
||||
|
||||
// Place the window
|
||||
dialog.style.left = Math.round(Math.min(min_left, max_left)) + "px"
|
||||
@@ -35,6 +43,7 @@ export const close = () => {
|
||||
// the dialog itself then the click was on the dialog background
|
||||
const click = (e: MouseEvent) => {
|
||||
if (e.target === dialog) {
|
||||
e.preventDefault()
|
||||
dialog.close()
|
||||
}
|
||||
}
|
||||
@@ -42,7 +51,7 @@ const click = (e: MouseEvent) => {
|
||||
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
||||
<dialog bind:this={dialog} onclick={click}>
|
||||
<dialog bind:this={dialog} onclick={click} oncontextmenu={click}>
|
||||
{@render children?.()}
|
||||
</dialog>
|
||||
|
||||
|
||||
@@ -63,7 +63,11 @@ onMount(async () => {
|
||||
let current_page: Tab = $state(null)
|
||||
|
||||
const load_page = (pathname: string, history: boolean): boolean => {
|
||||
console.debug("Navigating to page", pathname, "log history:", history)
|
||||
console.debug(
|
||||
"Page router: Navigating to page", pathname,
|
||||
"current path", window.location.pathname,
|
||||
"log history:", history,
|
||||
)
|
||||
|
||||
const path_decoded = decodeURIComponent(pathname)
|
||||
let page_by_path: Tab = null
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { global_navigator } from "filesystem/FSNavigator";
|
||||
import { fs_encode_path, FSNode } from "lib/FilesystemAPI.svelte";
|
||||
import { highlight_current_page } from "lib/HighlightCurrentPage";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let siblings: FSNode[] = $state([])
|
||||
@@ -25,9 +26,9 @@ onMount(() => {
|
||||
<div class="row">
|
||||
<a class="button" href="/d{fs_encode_path(node.path)}">
|
||||
{#if node.is_shared()}
|
||||
<i class="icon">folder_shared</i>
|
||||
<i class="icon small">folder_shared</i>
|
||||
{:else}
|
||||
<i class="icon">folder</i>
|
||||
<i class="icon small">folder</i>
|
||||
{/if}
|
||||
<span>{node.name}</span>
|
||||
</a>
|
||||
@@ -52,11 +53,13 @@ onMount(() => {
|
||||
{#each siblings as node}
|
||||
{#if !node.is_hidden()}
|
||||
<div class="row">
|
||||
<a class="button" href="/d{fs_encode_path(node.path)}">
|
||||
{#if node.type === "dir"}
|
||||
<i class="icon">folder</i>
|
||||
<a class="button" href="/d{fs_encode_path(node.path)}" use:highlight_current_page>
|
||||
{#if node.is_shared()}
|
||||
<i class="icon small">folder_shared</i>
|
||||
{:else if node.type === "dir"}
|
||||
<i class="icon small">folder</i>
|
||||
{:else}
|
||||
<i class="icon">image</i>
|
||||
<i class="icon small">image</i>
|
||||
{/if}
|
||||
<span>{node.name}</span>
|
||||
</a>
|
||||
|
||||
@@ -21,6 +21,7 @@ export default defineConfig({
|
||||
outDir: builddir,
|
||||
emptyOutDir: true,
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
lib: {
|
||||
entry: "src/wrap.js",
|
||||
name: "fnx_web",
|
||||
|
||||
Reference in New Issue
Block a user