mirror of
https://github.com/zadam/trilium.git
synced 2025-11-09 14:55:50 +01:00
client/read only note info bar: refactor
This commit is contained in:
@@ -4,7 +4,7 @@ import Component from "../components/component";
|
|||||||
import NoteContext from "../components/note_context";
|
import NoteContext from "../components/note_context";
|
||||||
import FNote from "../entities/fnote";
|
import FNote from "../entities/fnote";
|
||||||
import ActionButton, { ActionButtonProps } from "./react/ActionButton";
|
import ActionButton, { ActionButtonProps } from "./react/ActionButton";
|
||||||
import { useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useWindowSize } from "./react/hooks";
|
import { useIsNoteReadOnly, useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useWindowSize } from "./react/hooks";
|
||||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||||
import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils";
|
import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils";
|
||||||
import server from "../services/server";
|
import server from "../services/server";
|
||||||
@@ -13,8 +13,6 @@ import toast from "../services/toast";
|
|||||||
import { t } from "../services/i18n";
|
import { t } from "../services/i18n";
|
||||||
import { copyImageReferenceToClipboard } from "../services/image";
|
import { copyImageReferenceToClipboard } from "../services/image";
|
||||||
import tree from "../services/tree";
|
import tree from "../services/tree";
|
||||||
import protected_session_holder from "../services/protected_session_holder";
|
|
||||||
import options from "../services/options";
|
|
||||||
import { getHelpUrlForNote } from "../services/in_app_help";
|
import { getHelpUrlForNote } from "../services/in_app_help";
|
||||||
import froca from "../services/froca";
|
import froca from "../services/froca";
|
||||||
import NoteLink from "./react/NoteLink";
|
import NoteLink from "./react/NoteLink";
|
||||||
@@ -102,47 +100,25 @@ function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingBut
|
|||||||
}
|
}
|
||||||
|
|
||||||
function EditButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) {
|
function EditButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) {
|
||||||
const [ animationClass, setAnimationClass ] = useState("");
|
const [animationClass, setAnimationClass] = useState("");
|
||||||
const [ isEnabled, setIsEnabled ] = useState(false);
|
const {isReadOnly, enableEditing} = useIsNoteReadOnly();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
noteContext.isReadOnly().then(isReadOnly => {
|
|
||||||
setIsEnabled(
|
|
||||||
isDefaultViewMode
|
|
||||||
&& (!note.isProtected || protected_session_holder.isProtectedSessionAvailable())
|
|
||||||
&& !options.is("databaseReadonly")
|
|
||||||
&& isReadOnly
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}, [ note ]);
|
|
||||||
|
|
||||||
useTriliumEvent("readOnlyTemporarilyDisabled", ({ noteContext: eventNoteContext }) => {
|
|
||||||
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
|
||||||
setIsEnabled(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// make the edit button stand out on the first display, otherwise
|
// make the edit button stand out on the first display, otherwise
|
||||||
// it's difficult to notice that the note is readonly
|
// it's difficult to notice that the note is readonly
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEnabled) {
|
if (isReadOnly) {
|
||||||
setAnimationClass("bx-tada bx-lg");
|
setAnimationClass("bx-tada bx-lg");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setAnimationClass("");
|
setAnimationClass("");
|
||||||
}, 1700);
|
}, 1700);
|
||||||
}
|
}
|
||||||
}, [ isEnabled ]);
|
}, [ isReadOnly ]);
|
||||||
|
|
||||||
return isEnabled && <FloatingButton
|
return isReadOnly && <FloatingButton
|
||||||
text={t("edit_button.edit_this_note")}
|
text={t("edit_button.edit_this_note")}
|
||||||
icon="bx bx-pencil"
|
icon="bx bx-pencil"
|
||||||
className={animationClass}
|
className={animationClass}
|
||||||
onClick={() => {
|
onClick={() => enableEditing()}
|
||||||
if (noteContext.viewScope) {
|
|
||||||
noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
|
||||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext });
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
import { Inputs, MutableRef, useCallback, useContext, useDebugValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
import { CSSProperties } from "preact/compat";
|
||||||
import { CommandListenerData, EventData, EventNames } from "../../components/app_context";
|
import { DragData } from "../note_tree";
|
||||||
import { ParentComponent } from "./react_utils";
|
|
||||||
import SpacedUpdate from "../../services/spaced_update";
|
|
||||||
import { FilterLabelsByType, KeyboardActionNames, OptionNames, RelationNames } from "@triliumnext/commons";
|
import { FilterLabelsByType, KeyboardActionNames, OptionNames, RelationNames } from "@triliumnext/commons";
|
||||||
import options, { type OptionValue } from "../../services/options";
|
import { Inputs, MutableRef, useCallback, useContext, useDebugValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||||
import utils, { escapeRegExp, reloadFrontendApp } from "../../services/utils";
|
import { ParentComponent } from "./react_utils";
|
||||||
import NoteContext from "../../components/note_context";
|
|
||||||
import BasicWidget, { ReactWrappedWidget } from "../basic_widget";
|
|
||||||
import FNote from "../../entities/fnote";
|
|
||||||
import attributes from "../../services/attributes";
|
|
||||||
import FBlob from "../../entities/fblob";
|
|
||||||
import NoteContextAwareWidget from "../note_context_aware_widget";
|
|
||||||
import { RefObject, VNode } from "preact";
|
import { RefObject, VNode } from "preact";
|
||||||
import { Tooltip } from "bootstrap";
|
import { Tooltip } from "bootstrap";
|
||||||
import { CSSProperties } from "preact/compat";
|
import { ViewMode } from "../../services/link";
|
||||||
|
import appContext, { CommandListenerData, EventData, EventNames } from "../../components/app_context";
|
||||||
|
import attributes from "../../services/attributes";
|
||||||
|
import BasicWidget, { ReactWrappedWidget } from "../basic_widget";
|
||||||
|
import Component from "../../components/component";
|
||||||
|
import FBlob from "../../entities/fblob";
|
||||||
|
import FNote from "../../entities/fnote";
|
||||||
import keyboard_actions from "../../services/keyboard_actions";
|
import keyboard_actions from "../../services/keyboard_actions";
|
||||||
import Mark from "mark.js";
|
import Mark from "mark.js";
|
||||||
import { DragData } from "../note_tree";
|
import NoteContext from "../../components/note_context";
|
||||||
import Component from "../../components/component";
|
import NoteContextAwareWidget from "../note_context_aware_widget";
|
||||||
|
import options, { type OptionValue } from "../../services/options";
|
||||||
|
import protected_session_holder from "../../services/protected_session_holder";
|
||||||
|
import SpacedUpdate from "../../services/spaced_update";
|
||||||
import toast, { ToastOptions } from "../../services/toast";
|
import toast, { ToastOptions } from "../../services/toast";
|
||||||
import { ViewMode } from "../../services/link";
|
import utils, { escapeRegExp, reloadFrontendApp } from "../../services/utils";
|
||||||
|
|
||||||
export function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void) {
|
export function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void) {
|
||||||
const parentComponent = useContext(ParentComponent);
|
const parentComponent = useContext(ParentComponent);
|
||||||
@@ -701,3 +702,52 @@ export function useResizeObserver(ref: RefObject<HTMLElement>, callback: () => v
|
|||||||
return () => observer.disconnect();
|
return () => observer.disconnect();
|
||||||
}, [ callback, ref ]);
|
}, [ callback, ref ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the current note is in read-only mode, while an editing mode is available,
|
||||||
|
* and provides a way to switch to editing mode.
|
||||||
|
*/
|
||||||
|
export function useIsNoteReadOnly() {
|
||||||
|
const {note, noteContext} = useNoteContext();
|
||||||
|
const [isReadOnly, setIsReadOnly] = useState(false);
|
||||||
|
|
||||||
|
const enableEditing = useCallback(() => {
|
||||||
|
if (noteContext?.viewScope) {
|
||||||
|
noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||||
|
appContext.triggerEvent("readOnlyTemporarilyDisabled", {noteContext});
|
||||||
|
}
|
||||||
|
}, [noteContext]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (note && noteContext) {
|
||||||
|
isNoteReadOnly(note, noteContext).then((readOnly) => {
|
||||||
|
setIsReadOnly(readOnly);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [note, noteContext]);
|
||||||
|
|
||||||
|
useTriliumEvent("readOnlyTemporarilyDisabled", ({noteContext: eventNoteContext}) => {
|
||||||
|
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
||||||
|
setIsReadOnly(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {isReadOnly, enableEditing};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isNoteReadOnly(note: FNote, noteContext: NoteContext) {
|
||||||
|
|
||||||
|
if (note.isProtected && !protected_session_holder.isProtectedSessionAvailable()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.is("databaseReadonly")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noteContext.viewScope?.viewMode !== "default" || !await noteContext.isReadOnly()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
import "./read-only-note-info-bar.css";
|
import "./read_only_note_info_bar.css";
|
||||||
import { t } from "../services/i18n";
|
import { t } from "../services/i18n";
|
||||||
import { useCallback, useEffect, useState } from "preact/hooks";
|
import { useIsNoteReadOnly, useNoteContext, useTriliumEvent } from "./react/hooks"
|
||||||
import { useNoteContext, useTriliumEvent } from "./react/hooks"
|
|
||||||
import appContext from "../components/app_context";
|
|
||||||
import Button from "./react/Button";
|
import Button from "./react/Button";
|
||||||
import FNote from "../entities/fnote";
|
|
||||||
import NoteContext from "../components/note_context";
|
|
||||||
import options from "../services/options";
|
|
||||||
import protected_session_holder from "../services/protected_session_holder";
|
|
||||||
|
|
||||||
export default function ReadOnlyNoteInfoBar() {
|
export default function ReadOnlyNoteInfoBar() {
|
||||||
const {isReadOnly, enableEditing} = useIsReadOnly();
|
const {isReadOnly, enableEditing} = useIsNoteReadOnly();
|
||||||
const {note} = useNoteContext();
|
const {note} = useNoteContext();
|
||||||
|
|
||||||
return <div class={`read-only-note-info-bar-widget ${(isReadOnly) ? " visible" : ""}`}>
|
return <div class={`read-only-note-info-bar-widget ${(isReadOnly) ? " visible" : ""}`}>
|
||||||
@@ -34,48 +28,3 @@ export default function ReadOnlyNoteInfoBar() {
|
|||||||
</>}
|
</>}
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useIsReadOnly() {
|
|
||||||
const {note, noteContext} = useNoteContext();
|
|
||||||
const [isReadOnly, setIsReadOnly] = useState(false);
|
|
||||||
|
|
||||||
const enableEditing = useCallback(() => {
|
|
||||||
if (noteContext?.viewScope) {
|
|
||||||
noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
|
||||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", {noteContext});
|
|
||||||
}
|
|
||||||
}, [noteContext]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (note && noteContext) {
|
|
||||||
isNoteReadOnly(note, noteContext).then((readOnly) => {
|
|
||||||
setIsReadOnly(readOnly);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [note, noteContext]);
|
|
||||||
|
|
||||||
useTriliumEvent("readOnlyTemporarilyDisabled", ({noteContext: eventNoteContext}) => {
|
|
||||||
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
|
||||||
setIsReadOnly(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {isReadOnly, enableEditing};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function isNoteReadOnly(note: FNote, noteContext: NoteContext) {
|
|
||||||
|
|
||||||
if (note.isProtected && !protected_session_holder.isProtectedSessionAvailable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.is("databaseReadonly")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noteContext.viewScope?.viewMode !== "default" || !await noteContext.isReadOnly()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user