mirror of
https://github.com/zadam/trilium.git
synced 2025-10-05 21:15:01 +08:00
feat(react/floating_buttons): port edit button
This commit is contained in:
parent
e290635ba5
commit
cdbb89482e
2 changed files with 63 additions and 92 deletions
|
@ -4,12 +4,16 @@ import Button from "./react/Button";
|
|||
import ActionButton from "./react/ActionButton";
|
||||
import FNote from "../entities/fnote";
|
||||
import NoteContext from "../components/note_context";
|
||||
import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useTriliumOptionBool } from "./react/hooks";
|
||||
import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useNoteProperty, useTriliumEvent, useTriliumEvents, useTriliumOption, useTriliumOptionBool } from "./react/hooks";
|
||||
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
|
||||
import { ParentComponent } from "./react/react_utils";
|
||||
import Component from "../components/component";
|
||||
import { VNode } from "preact";
|
||||
import attributes from "../services/attributes";
|
||||
import appContext from "../components/app_context";
|
||||
import protected_session_holder from "../services/protected_session_holder";
|
||||
import options from "../services/options";
|
||||
import { AttributeRow } from "../services/load_results";
|
||||
|
||||
interface FloatingButtonContext {
|
||||
parentComponent: Component;
|
||||
|
@ -19,7 +23,7 @@ interface FloatingButtonContext {
|
|||
|
||||
interface FloatingButtonDefinition {
|
||||
component: (context: FloatingButtonContext) => VNode;
|
||||
isEnabled: (context: FloatingButtonContext) => boolean;
|
||||
isEnabled: (context: FloatingButtonContext) => boolean | Promise<boolean>;
|
||||
}
|
||||
|
||||
const FLOATING_BUTTON_DEFINITIONS: FloatingButtonDefinition[] = [
|
||||
|
@ -37,9 +41,27 @@ const FLOATING_BUTTON_DEFINITIONS: FloatingButtonDefinition[] = [
|
|||
(note.type === "mermaid" || note.getLabelValue("viewType") === "geoMap")
|
||||
&& note.isContentAvailable()
|
||||
&& noteContext.viewScope?.viewMode === "default"
|
||||
},
|
||||
{
|
||||
component: EditButton,
|
||||
isEnabled: async ({ note, noteContext }) =>
|
||||
noteContext.viewScope?.viewMode === "default"
|
||||
&& (!note.isProtected || protected_session_holder.isProtectedSessionAvailable())
|
||||
&& !options.is("databaseReadonly")
|
||||
&& await noteContext?.isReadOnly()
|
||||
}
|
||||
];
|
||||
|
||||
async function getFloatingButtonDefinitions(context: FloatingButtonContext) {
|
||||
const defs: FloatingButtonDefinition[] = [];
|
||||
for (const def of FLOATING_BUTTON_DEFINITIONS) {
|
||||
if (await def.isEnabled(context)) {
|
||||
defs.push(def);
|
||||
}
|
||||
}
|
||||
return defs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
*
|
||||
|
@ -64,15 +86,23 @@ export default function FloatingButtons() {
|
|||
const [ refreshCounter, setRefreshCounter ] = useState(0);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (loadResults.getAttributeRows().find(attrRow => attributes.isAffecting(attrRow, note))) {
|
||||
setRefreshCounter(refreshCounter+1);
|
||||
setRefreshCounter(refreshCounter + 1);
|
||||
}
|
||||
});
|
||||
useTriliumEvent("readOnlyTemporarilyDisabled", ({ noteContext: eventNoteContext }) => {
|
||||
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
||||
setRefreshCounter(refreshCounter + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const definitions = useMemo<FloatingButtonDefinition[]>(() => {
|
||||
if (!context) return [];
|
||||
return FLOATING_BUTTON_DEFINITIONS.filter(def => def.isEnabled(context));
|
||||
}, [ context, refreshCounter ]);
|
||||
|
||||
// Manage the list of items
|
||||
const noteMime = useNoteProperty(note, "mime");
|
||||
const [ definitions, setDefinitions ] = useState<FloatingButtonDefinition[]>([]);
|
||||
useEffect(() => {
|
||||
if (!context) return;
|
||||
getFloatingButtonDefinitions(context).then(setDefinitions);
|
||||
}, [ context, refreshCounter, noteMime ]);
|
||||
|
||||
return (
|
||||
<div className="floating-buttons no-print">
|
||||
<div className="floating-buttons-children">
|
||||
|
@ -115,6 +145,31 @@ function ToggleReadOnlyButton({ note }: FloatingButtonContext) {
|
|||
/>
|
||||
}
|
||||
|
||||
function EditButton({ noteContext }: FloatingButtonContext) {
|
||||
const [ animationClass, setAnimationClass ] = useState("");
|
||||
|
||||
// make the edit button stand out on the first display, otherwise
|
||||
// it's difficult to notice that the note is readonly
|
||||
useEffect(() => {
|
||||
setAnimationClass("bx-tada bx-lg");
|
||||
setTimeout(() => {
|
||||
setAnimationClass("");
|
||||
}, 1700);
|
||||
}, []);
|
||||
|
||||
return <ActionButton
|
||||
text={t("edit_button.edit_this_note")}
|
||||
icon="bx bx-pencil"
|
||||
className={animationClass}
|
||||
onClick={() => {
|
||||
if (noteContext.viewScope) {
|
||||
noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
/**
|
||||
* Show button that displays floating button after click on close button
|
||||
*/
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
import OnClickButtonWidget from "../buttons/onclick_button.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import attributeService from "../../services/attributes.js";
|
||||
import protectedSessionHolder from "../../services/protected_session_holder.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import LoadResults from "../../services/load_results.js";
|
||||
import type { AttributeRow } from "../../services/load_results.js";
|
||||
import FNote from "../../entities/fnote.js";
|
||||
import options from "../../services/options.js";
|
||||
|
||||
export default class EditButton extends OnClickButtonWidget {
|
||||
isEnabled(): boolean {
|
||||
return Boolean(super.isEnabled() && this.note && this.noteContext?.viewScope?.viewMode === "default");
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.icon("bx-pencil")
|
||||
.title(t("edit_button.edit_this_note"))
|
||||
.titlePlacement("bottom")
|
||||
.onClick((widget) => {
|
||||
if (this.noteContext?.viewScope) {
|
||||
this.noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext: this.noteContext });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async refreshWithNote(note: FNote): Promise<void> {
|
||||
if (options.is("databaseReadonly")) {
|
||||
this.toggleInt(false);
|
||||
return;
|
||||
}
|
||||
if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||
this.toggleInt(false);
|
||||
} else {
|
||||
// prevent flickering by assuming hidden before async operation
|
||||
this.toggleInt(false);
|
||||
|
||||
const wasVisible = this.isVisible();
|
||||
|
||||
// can't do this in isEnabled() since isReadOnly is async
|
||||
const isReadOnly = await this.noteContext?.isReadOnly();
|
||||
this.toggleInt(Boolean(isReadOnly));
|
||||
|
||||
// make the edit button stand out on the first display, otherwise
|
||||
// it's difficult to notice that the note is readonly
|
||||
if (this.isVisible() && !wasVisible && this.$widget) {
|
||||
this.$widget.addClass("bx-tada bx-lg");
|
||||
|
||||
setTimeout(() => {
|
||||
this.$widget?.removeClass("bx-tada bx-lg");
|
||||
}, 1700);
|
||||
}
|
||||
}
|
||||
|
||||
await super.refreshWithNote(note);
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({ loadResults }: { loadResults: LoadResults }): void {
|
||||
if (loadResults.getAttributeRows().find((attr: AttributeRow) =>
|
||||
attr.type === "label" &&
|
||||
attr.name?.toLowerCase().includes("readonly") &&
|
||||
this.note &&
|
||||
attributeService.isAffecting(attr, this.note)
|
||||
)) {
|
||||
if (this.noteContext?.viewScope) {
|
||||
this.noteContext.viewScope.readOnlyTemporarilyDisabled = false;
|
||||
}
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
readOnlyTemporarilyDisabledEvent() {
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
async noteTypeMimeChangedEvent({ noteId }: { noteId: string }): Promise<void> {
|
||||
if (this.isNote(noteId)) {
|
||||
await this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue