Skip to content

Commit

Permalink
feat(AssetManager): Allow editing asset names without a popup
Browse files Browse the repository at this point in the history
  • Loading branch information
rexy712 authored Nov 8, 2024
1 parent 81bcc19 commit 7a70b20
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ tech changes will usually be stripped from release notes for the public
- [tech] Select tool:
- Delayed syncing of selection state to the global state from mouse down to mouse move/up
- This fixes some of the entries in the Fixed section
- AssetManager:
- Changed UI of renaming assets, allowing inline editing rather than opening a popup

### Removed

Expand Down
19 changes: 9 additions & 10 deletions client/src/assetManager/AssetContext.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
import { computed, defineEmits, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import ContextMenu from "../core/components/contextMenu/ContextMenu.vue";
import type { Section } from "../core/components/contextMenu/types";
import { useModal } from "../core/plugins/modals/plugin";
import { coreStore } from "../store/core";
import AssetShare from "./AssetShare.vue";
import { assetContextLeft, assetContextTop, showAssetContextMenu } from "./context";
import type { AssetId } from "./models";
import { assetState } from "./state";
import { assetSystem } from ".";
const emit = defineEmits<{(event: "rename", payload: AssetId): void;}>();
const cm = ref<{ $el: HTMLDivElement } | null>(null);
const modals = useModal();
const { t } = useI18n();
Expand Down Expand Up @@ -47,21 +51,16 @@ function close(): void {
showAssetContextMenu.value = false;
}
async function rename(): Promise<void> {
function rename(): void {
if (assetState.raw.selected.length !== 1) return;
const asset = assetState.raw.idMap.get(assetState.raw.selected[0]!);
if (asset === undefined) {
console.error("Attempt to rename unknown file");
return close();
}
const name = await modals.prompt(
t("assetManager.AssetContextMenu.new_name"),
t("assetManager.AssetContextMenu.renaming_NAME", { name: asset.name }),
);
if (name !== undefined) {
assetSystem.renameAsset(asset.id, name);
}
emit("rename", asset.id);
close();
}
Expand All @@ -79,7 +78,7 @@ async function remove(): Promise<void> {
close();
}
const sections = computed(() => [
const sections = computed<Section[]>(() => [
{
title: t("common.rename"),
action: rename,
Expand Down
79 changes: 71 additions & 8 deletions client/src/dashboard/Assets.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import trimEnd from "lodash/trimEnd";
import { type DeepReadonly, computed, onMounted, ref } from "vue";
import { type DeepReadonly, computed, nextTick, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n";
import { onBeforeRouteLeave, onBeforeRouteUpdate, useRoute } from "vue-router";
import type { RouteLocationNormalized } from "vue-router";
Expand Down Expand Up @@ -31,6 +31,9 @@ const body = document.getElementsByTagName("body")[0];
const activeSelectionUrl = `url(${baseAdjust("/static/img/assetmanager/active_selection.png")})`;
const emptySelectionUrl = `url(${baseAdjust("/static/img/assetmanager/empty_selection.png")})`;
const contextTargetElement = ref<HTMLElement | null>(null);
const currentRenameAsset = ref<AssetId | null>(null);
function getCurrentPath(path?: string): string {
path ??= route.path;
const i = path.indexOf("/assets");
Expand Down Expand Up @@ -161,13 +164,39 @@ function openContextMenu(event: MouseEvent, key: AssetId): void {
return;
}
// event is generated by the parent element containing both the image/icon and
// the name of the asset. We only want to operate on the name, so we have to
// get the child element with the 'title' class
const parent = event.currentTarget as HTMLElement;
contextTargetElement.value = parent.querySelector(":scope > .title");
assetSystem.clearSelected();
assetSystem.addSelectedInode(key);
openAssetContextMenu(event);
}
let draggingSelection = false;
function renameAsset(event: FocusEvent, file: AssetId, oldName: string): void {
if(!canEdit(file, false)) {
return;
}
const target = event.target as HTMLElement;
if(target.textContent === null){
target.textContent = oldName;
currentRenameAsset.value = null;
return;
}
const name = target.textContent.trim();
if (name === undefined || name === "" || name === "..") {
target.textContent = oldName;
} else if (name !== oldName) {
assetSystem.renameAsset(file, name);
}
currentRenameAsset.value = null;
}
function startDrag(event: DragEvent, file: AssetId): void {
if (event.dataTransfer === null) return;
Expand Down Expand Up @@ -265,6 +294,29 @@ function canEdit(data: AssetId | DeepReadonly<ApiAsset> | undefined, includeRoot
}
return true;
}
function selectElementContents(el: HTMLElement) : void {
const range = document.createRange();
range.selectNodeContents(el);
const sel = window.getSelection();
if(sel) {
sel.removeAllRanges();
sel.addRange(range);
}
}
async function showRenameUI(id: AssetId) : Promise<void> {
const el = contextTargetElement.value;
contextTargetElement.value = null;
if (el) {
currentRenameAsset.value = id;
await nextTick(() => {
el.focus();
selectElementContents(el);
});
}
}
</script>

<template>
Expand Down Expand Up @@ -339,7 +391,14 @@ function canEdit(data: AssetId | DeepReadonly<ApiAsset> | undefined, includeRoot
>
<font-awesome-icon v-if="isShared(folder)" icon="user-tag" class="asset-link" />
<font-awesome-icon icon="folder" style="font-size: 12.5em" />
<div class="title">{{ folder.name }}</div>
<div
:contenteditable="folder.id === currentRenameAsset"
class="title"
@keydown.enter="($event!.target as HTMLElement).blur()"
@blur="renameAsset($event, folder.id, folder.name)"
>
{{ folder.name }}
</div>
</div>
<div
v-for="file of files"
Expand All @@ -357,9 +416,17 @@ function canEdit(data: AssetId | DeepReadonly<ApiAsset> | undefined, includeRoot
>
<font-awesome-icon v-if="isShared(file)" icon="user-tag" class="asset-link" />
<img :src="getIdImageSrc(file.id)" width="50" alt="" />
<div class="title">{{ file.name }}</div>
<div
:contenteditable="file.id === currentRenameAsset"
class="title"
@keydown.enter="($event!.target as HTMLElement).blur()"
@blur="renameAsset($event, file.id, file.name)"
>
{{ file.name }}
</div>
</div>
</div>

<div
v-show="
assetState.reactive.expectedUploads > 0 &&
Expand All @@ -380,7 +447,7 @@ function canEdit(data: AssetId | DeepReadonly<ApiAsset> | undefined, includeRoot
</div>
</div>
</div>
<AssetContextMenu />
<AssetContextMenu @rename="showRenameUI" />
</template>

<style lang="scss">
Expand Down Expand Up @@ -485,10 +552,6 @@ function canEdit(data: AssetId | DeepReadonly<ApiAsset> | undefined, includeRoot
cursor: pointer;
}
* {
pointer-events: none; // prevent drag shenanigans
}
> img {
width: 12.5rem;
height: 12.5rem;
Expand Down

0 comments on commit 7a70b20

Please sign in to comment.