mirror of
https://github.com/zadam/trilium.git
synced 2025-11-26 02:24:23 +01:00
fix(text): classic toolbar broken on mobile due to prior change
This commit is contained in:
parent
c76f368fa0
commit
9b3ca65492
@ -10,16 +10,21 @@ import { TabContext } from "./ribbon-interface";
|
|||||||
* The ribbon item is active by default for text notes, as long as they are not in read-only mode.
|
* The ribbon item is active by default for text notes, as long as they are not in read-only mode.
|
||||||
*
|
*
|
||||||
* ! The toolbar is not only used in the ribbon, but also in the quick edit feature.
|
* ! The toolbar is not only used in the ribbon, but also in the quick edit feature.
|
||||||
|
* * The mobile toolbar is handled separately (see `MobileEditorToolbar`).
|
||||||
*/
|
*/
|
||||||
export default function FormattingToolbar({ hidden, ntxId }: TabContext) {
|
export default function FormattingToolbar({ hidden, ntxId }: TabContext) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [ textNoteEditorType ] = useTriliumOption("textNoteEditorType");
|
const [ textNoteEditorType ] = useTriliumOption("textNoteEditorType");
|
||||||
|
|
||||||
|
// Attach the toolbar from the CKEditor.
|
||||||
useTriliumEvent("textEditorRefreshed", ({ ntxId: eventNtxId, editor }) => {
|
useTriliumEvent("textEditorRefreshed", ({ ntxId: eventNtxId, editor }) => {
|
||||||
if (eventNtxId !== ntxId) return;
|
if (eventNtxId !== ntxId || !containerRef.current) return;
|
||||||
const toolbar = editor.ui.view.toolbar?.element;
|
const toolbar = editor.ui.view.toolbar?.element;
|
||||||
if (toolbar && containerRef.current) {
|
|
||||||
|
if (toolbar) {
|
||||||
containerRef.current.replaceChildren(toolbar);
|
containerRef.current.replaceChildren(toolbar);
|
||||||
|
} else {
|
||||||
|
containerRef.current.replaceChildren();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -233,12 +233,6 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
onWatchdogStateChange={onWatchdogStateChange}
|
onWatchdogStateChange={onWatchdogStateChange}
|
||||||
onChange={() => spacedUpdate.scheduleUpdate()}
|
onChange={() => spacedUpdate.scheduleUpdate()}
|
||||||
onEditorInitialized={(editor) => {
|
onEditorInitialized={(editor) => {
|
||||||
console.log("Editor has been initialized!", parentComponent, editor);
|
|
||||||
|
|
||||||
if (isClassicEditor) {
|
|
||||||
setupClassicEditor(editor, parentComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasTouchBar) {
|
if (hasTouchBar) {
|
||||||
const handler = () => refreshTouchBarRef.current?.();
|
const handler = () => refreshTouchBarRef.current?.();
|
||||||
for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) {
|
for (const event of [ "bold", "italic", "underline", "paragraph", "heading" ]) {
|
||||||
@ -303,26 +297,6 @@ function onNotificationWarning(data, evt) {
|
|||||||
evt.stop();
|
evt.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupClassicEditor(editor: CKTextEditor, parentComponent: Component | undefined) {
|
|
||||||
if (!parentComponent) return;
|
|
||||||
|
|
||||||
if (utils.isMobile()) {
|
|
||||||
// Reposition all dropdowns to point upwards instead of downwards.
|
|
||||||
// See https://ckeditor.com/docs/ckeditor5/latest/examples/framework/bottom-toolbar-editor.html for more info.
|
|
||||||
const toolbarView = (editor as ClassicEditor).ui.view.toolbar;
|
|
||||||
for (const item of toolbarView.items) {
|
|
||||||
if (!("panelView" in item)) continue;
|
|
||||||
|
|
||||||
item.on("change:isOpen", () => {
|
|
||||||
if (!("isOpen" in item) || !item.isOpen) return;
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
item.panelView.position = item.panelView.position.replace("s", "n");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditableTextTouchBar({ watchdogRef, refreshTouchBarRef }: { watchdogRef: RefObject<EditorWatchdog | null>, refreshTouchBarRef: RefObject<() => void> }) {
|
function EditableTextTouchBar({ watchdogRef, refreshTouchBarRef }: { watchdogRef: RefObject<EditorWatchdog | null>, refreshTouchBarRef: RefObject<() => void> }) {
|
||||||
const [ headingSelectedIndex, setHeadingSelectedIndex ] = useState<number>();
|
const [ headingSelectedIndex, setHeadingSelectedIndex ] = useState<number>();
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { MutableRef, useCallback, useEffect, useRef, useState } from "preact/hooks";
|
import { MutableRef, useCallback, useEffect, useRef, useState } from "preact/hooks";
|
||||||
import { useNoteContext } from "../../react/hooks";
|
import { useNoteContext, useTriliumEvent } from "../../react/hooks";
|
||||||
import "./mobile_editor_toolbar.css";
|
import "./mobile_editor_toolbar.css";
|
||||||
import { isIOS } from "../../../services/utils";
|
import { isIOS } from "../../../services/utils";
|
||||||
|
import { CKTextEditor, ClassicEditor } from "@triliumnext/ckeditor5";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the editing toolbar for CKEditor in mobile mode. The toolbar acts as a floating bar, with two different mechanism:
|
* Handles the editing toolbar for CKEditor in mobile mode. The toolbar acts as a floating bar, with two different mechanism:
|
||||||
@ -10,12 +11,12 @@ import { isIOS } from "../../../services/utils";
|
|||||||
* - On Android, the viewport change makes the keyboard resize the content area, all we have to do is to hide the tab bar and global menu (handled in the global style).
|
* - On Android, the viewport change makes the keyboard resize the content area, all we have to do is to hide the tab bar and global menu (handled in the global style).
|
||||||
*/
|
*/
|
||||||
export default function MobileEditorToolbar() {
|
export default function MobileEditorToolbar() {
|
||||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const { note, noteContext } = useNoteContext();
|
const { note, noteContext, ntxId } = useNoteContext();
|
||||||
const [ shouldDisplay, setShouldDisplay ] = useState(false);
|
const [ shouldDisplay, setShouldDisplay ] = useState(false);
|
||||||
const [ dropdownActive, setDropdownActive ] = useState(false);
|
const [ dropdownActive, setDropdownActive ] = useState(false);
|
||||||
|
|
||||||
usePositioningOniOS(wrapperRef);
|
usePositioningOniOS(containerRef);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
noteContext?.isReadOnly().then(isReadOnly => {
|
noteContext?.isReadOnly().then(isReadOnly => {
|
||||||
@ -23,15 +24,28 @@ export default function MobileEditorToolbar() {
|
|||||||
});
|
});
|
||||||
}, [ note ]);
|
}, [ note ]);
|
||||||
|
|
||||||
|
// Attach the toolbar from the CKEditor.
|
||||||
|
useTriliumEvent("textEditorRefreshed", ({ ntxId: eventNtxId, editor }) => {
|
||||||
|
if (eventNtxId !== ntxId || !containerRef.current) return;
|
||||||
|
const toolbar = editor.ui.view.toolbar?.element;
|
||||||
|
|
||||||
|
repositionDropdowns(editor);
|
||||||
|
if (toolbar) {
|
||||||
|
containerRef.current.replaceChildren(toolbar);
|
||||||
|
} else {
|
||||||
|
containerRef.current.replaceChildren();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Observe when a dropdown is expanded to apply a style that allows the dropdown to be visible, since we can't have the element both visible and the toolbar scrollable.
|
// Observe when a dropdown is expanded to apply a style that allows the dropdown to be visible, since we can't have the element both visible and the toolbar scrollable.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!wrapperRef.current) return;
|
if (!containerRef.current) return;
|
||||||
|
|
||||||
const observer = new MutationObserver(e => {
|
const observer = new MutationObserver(e => {
|
||||||
setDropdownActive(e.map((e) => (e.target as any).ariaExpanded === "true").reduce((acc, e) => acc && e));
|
setDropdownActive(e.map((e) => (e.target as any).ariaExpanded === "true").reduce((acc, e) => acc && e));
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(wrapperRef.current, {
|
observer.observe(containerRef.current, {
|
||||||
attributeFilter: ["aria-expanded"],
|
attributeFilter: ["aria-expanded"],
|
||||||
subtree: true
|
subtree: true
|
||||||
});
|
});
|
||||||
@ -41,7 +55,7 @@ export default function MobileEditorToolbar() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`classic-toolbar-outer-container ${!shouldDisplay ? "hidden-ext" : "visible"} ${isIOS() ? "ios" : ""}`}>
|
<div className={`classic-toolbar-outer-container ${!shouldDisplay ? "hidden-ext" : "visible"} ${isIOS() ? "ios" : ""}`}>
|
||||||
<div ref={wrapperRef} className={`classic-toolbar-widget ${dropdownActive ? "dropdown-active" : ""}`}></div>
|
<div ref={containerRef} className={`classic-toolbar-widget ${dropdownActive ? "dropdown-active" : ""}`}></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -50,7 +64,7 @@ function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
|||||||
const adjustPosition = useCallback(() => {
|
const adjustPosition = useCallback(() => {
|
||||||
if (!wrapperRef.current) return;
|
if (!wrapperRef.current) return;
|
||||||
let bottom = window.innerHeight - (window.visualViewport?.height || 0);
|
let bottom = window.innerHeight - (window.visualViewport?.height || 0);
|
||||||
wrapperRef.current.style.bottom = `${bottom}px`;
|
wrapperRef.current.style.bottom = `${bottom}px`;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -65,3 +79,22 @@ function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reposition all dropdowns to point upwards instead of downwards.
|
||||||
|
* See https://ckeditor.com/docs/ckeditor5/latest/examples/framework/bottom-toolbar-editor.html for more info.
|
||||||
|
* @param editor
|
||||||
|
*/
|
||||||
|
function repositionDropdowns(editor: CKTextEditor) {
|
||||||
|
const toolbarView = (editor as ClassicEditor).ui.view.toolbar;
|
||||||
|
for (const item of toolbarView.items) {
|
||||||
|
if (!("panelView" in item)) continue;
|
||||||
|
|
||||||
|
item.on("change:isOpen", () => {
|
||||||
|
if (!("isOpen" in item) || !item.isOpen) return;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
item.panelView.position = item.panelView.position.replace("s", "n");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user