-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Desktop: Multiple window support #11181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
laurent22
merged 116 commits into
laurent22:dev
from
personalizedrefrigerator:test/editor-in-iframe
Nov 8, 2024
Merged
Changes from 3 commits
Commits
Show all changes
116 commits
Select commit
Hold shift + click to select a range
3e91f53
Refresh note when changed in database
personalizedrefrigerator e7294f0
Desktop: PoC: Show the note editor in a new window
personalizedrefrigerator 63de97d
Allow opening notes in new windows
personalizedrefrigerator 954b382
Refactoring & style fixes
personalizedrefrigerator 24ab7c0
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator 1bdb91d
Merge commit '3e91f535d9edb0316f14afc4121fbea41e94a1ba' into test/edi…
personalizedrefrigerator cd4996c
Simplify useFormNote logic
personalizedrefrigerator 00d3150
Merge remote-tracking branch 'refs/remotes/origin/test/editor-in-ifra…
personalizedrefrigerator 7b8b626
Fix editor commands frequently applied to the wrong editor
personalizedrefrigerator d61f8fc
WIP: Allow showing dialogs in secondary windows
personalizedrefrigerator 1991fef
Fix import/export modal is sometimes never hidden when multiple windows
personalizedrefrigerator a2a68ba
Fix crash when closing settings: Move window commands out of MainScre…
personalizedrefrigerator 15d2ea7
Fix styles: Migrate plugin dialog containers away from styled-components
personalizedrefrigerator fad84d4
Fix useFormNote now refreshes too often
personalizedrefrigerator a268057
Reduce debug logging
personalizedrefrigerator 6184579
Fix tag dialog and styled components don't work in new windows
personalizedrefrigerator 093bd79
Revert migration away from styled-components for dialogs, toolbar
personalizedrefrigerator b271333
Add note about @emotion/ transitive dependency
personalizedrefrigerator 8fb96f7
Merge remote-tracking branch 'upstream/dev' into test/editor-in-iframe
personalizedrefrigerator f440489
Fix GotoAnything has wrong height in secondary windows
personalizedrefrigerator 2aa5576
Fix links in new windows
personalizedrefrigerator f7998f4
Update reducer.ts to give different windows different selections
personalizedrefrigerator 55ca853
Always use the data from the main window for the sidebar and note list
personalizedrefrigerator 67d36de
Fix secondary windows close when opening settings
personalizedrefrigerator a9096a1
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator a1c6afa
WIP: Allow different windows to show different editors
personalizedrefrigerator 7211620
Merge remote-tracking branch 'refs/remotes/origin/test/editor-in-ifra…
personalizedrefrigerator 9790498
Refactor NoteEditor to allow the "runtime must be registered" assertion
personalizedrefrigerator 74213e7
Fix context menus in secondary windows
personalizedrefrigerator 4179b4f
Make background toolbar buttons be enabled/disabled based on their
personalizedrefrigerator 5c70bd0
Merge remote-tracking branch 'upstream/dev' into test/editor-in-iframe
personalizedrefrigerator 395f015
Fix adding tags in a new window causes navigation
personalizedrefrigerator a2f23e0
Remove unneeded props
personalizedrefrigerator 888f52a
Fix dropping notes into secondary windows
personalizedrefrigerator 78bb6f6
Allow different windows to have different editor layouts
personalizedrefrigerator 13a7b42
Remove now-unused useNowEffect hook
personalizedrefrigerator cc16b92
Fix adding tags in new windows causes the new window to navigate
personalizedrefrigerator ded0b64
Make visible dialogs per-window
personalizedrefrigerator 278b335
Load custom app CSS in new windows
personalizedrefrigerator b0e39cd
Avoid refreshing notes unnecessarily
personalizedrefrigerator 14eb7d1
Allow toggling devtools for secondary windows
personalizedrefrigerator 7c7c116
Attempting to fix failing tests: Load commands sooner
personalizedrefrigerator 7b8ff88
Fixing new note/new to-do buttons incorrectly enabled/disabled in
personalizedrefrigerator 4f80b40
On delete/move, update note history in all windows
personalizedrefrigerator 5dd04f8
Retitle background windows
personalizedrefrigerator b14895c
Replace 'default' -> defaultWindowId
personalizedrefrigerator a6a9514
Attempt to make tests less flaky
personalizedrefrigerator d7cfdda
Refactoring: Rename NoteEditor wrapper -> EditorWindow
personalizedrefrigerator b517c08
Merge remote-tracking branch 'upstream/dev' into test/editor-in-iframe
personalizedrefrigerator 06960c8
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator 67bbfd0
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator 955f179
Fixing useFormNote tests
personalizedrefrigerator 40616c3
Fix legacy editor fails to load in secondary windows
personalizedrefrigerator 8e826f4
Refactoring: Resolve prompt dialog to-do
personalizedrefrigerator a63e0e5
Draft of background windows technical spec
personalizedrefrigerator 48379f7
Merge remote-tracking branch 'upstream/dev' into test/editor-in-iframe
personalizedrefrigerator db68b7e
Fix useFormNote memory regression
personalizedrefrigerator 829453b
Commenting
personalizedrefrigerator 5734035
Commenting
personalizedrefrigerator 72e9429
Apply plugin custom CSS to all windows
personalizedrefrigerator 294203a
Fix custom userchrome CSS not applied
personalizedrefrigerator 4ed84b6
Refactoring: NoteListWrapper
personalizedrefrigerator 1bed661
Fix error logged when custom CSS file doesn't exist
personalizedrefrigerator 0c51822
Fix plugin note viewer IPC
personalizedrefrigerator 6c23455
Fix error on NoteTextViewer component unmount
personalizedrefrigerator 0d40c79
Attempting to fix dialog messaging
personalizedrefrigerator b4ee664
Improve menubar/navigation
personalizedrefrigerator 29bb7d2
Move main-window focusing logic to MenuBar
personalizedrefrigerator e055289
Fix note viewer in secondary windows
personalizedrefrigerator 7bc9f73
Make "focus sidebar" and "focus note list" commands show the main window
personalizedrefrigerator 63e737b
Fixing tests: Use the same menu for all windows
personalizedrefrigerator 294018a
When closing the last user-visible window, quit the app if the tray icon
personalizedrefrigerator 406cb83
Fix tsc: Remove unused prop
personalizedrefrigerator 888a78f
Fix menubar flashes on startup
personalizedrefrigerator 536d912
Fix print command
personalizedrefrigerator 4c65e5e
Fix certain dialogs are only shown in the main window
personalizedrefrigerator 7bbd59c
Switch focus to the main window when it navigates
personalizedrefrigerator cbaac1c
Only allow one copy of each plugin dialog to be open at a time
personalizedrefrigerator f04b00f
Refactoring: Code cleanup and preparation for per-window smalltalk/notyf
personalizedrefrigerator b76b42a
Fix smalltalk dialogs in secondary windows
personalizedrefrigerator f3812d2
Trying to fix CI
personalizedrefrigerator a5af549
Merge remote-tracking branch 'upstream/dev' into test/editor-in-iframe
personalizedrefrigerator 5b5706a
Trying to fix CI
personalizedrefrigerator d8abbda
Update background_windows.md
personalizedrefrigerator b8a5ae6
Updating CI fix: Make app-mobile types/node match version of other ty…
personalizedrefrigerator 34ea5b5
Changes from self-review of code
personalizedrefrigerator 214a578
Attempting to fix failing useFormNote test
personalizedrefrigerator 3a00d7c
Reducer refactoring and testing
personalizedrefrigerator 38ddf66
Fix Rich Text Editor context menu
personalizedrefrigerator 7c7f15a
Fix MacOS context menu shown in wrong window
personalizedrefrigerator 6bce24c
Attempt to fix quickly switching windows can lead to invalid state if…
personalizedrefrigerator 5df7273
Refactoring and commenting
personalizedrefrigerator fbb3ba1
Linux: Fix CodeMirror context menu
personalizedrefrigerator 65b78a5
Fix replaceMisspelling in secondary windows
personalizedrefrigerator 9e7b1ee
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator 79098bd
Update yarn.lock
personalizedrefrigerator aab2f1a
Merge branch 'dev' into test/editor-in-iframe
laurent22 62f6b4a
Throw if openNoteInNewWindow is called with no note selected
personalizedrefrigerator 07dbd7a
Rename WindowCommandHandler to WindowCommandsAndDialogs
personalizedrefrigerator d11074b
Fix clicking on links in the Rich Text editor opens two copies of the
personalizedrefrigerator 61f3f6b
Merge remote-tracking branch 'upstream/dev' into test/editor-in-iframe
personalizedrefrigerator a72e4e3
Fix errors post merge
personalizedrefrigerator 7475319
Trying to fix flaky test
personalizedrefrigerator f2757f9
Update background_windows.md with more information about React portals
personalizedrefrigerator 6cae888
Add a limitations section to background_windows.md
personalizedrefrigerator ef4b9a2
Rename useDom -> useDocument
personalizedrefrigerator a2aa2fe
Fix Mermaid diagram download button
personalizedrefrigerator 5f01b68
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator bbc42a6
Revert unnecessary change to app-mobile/package.json
personalizedrefrigerator d3b3beb
Commenting
personalizedrefrigerator 9919dca
Remove throw new Error from openNoteInNewWindow command
personalizedrefrigerator 8fd861f
Merge remote-tracking branch 'refs/remotes/origin/test/editor-in-ifra…
personalizedrefrigerator 8f8dfd9
Don't duplicate cssUrls
personalizedrefrigerator 6461966
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator f1a6157
Commenting
personalizedrefrigerator c5dc803
Merge branch 'dev' into test/editor-in-iframe
personalizedrefrigerator File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService'; | ||
| import { _ } from '@joplin/lib/locale'; | ||
| import { stateUtils } from '@joplin/lib/reducer'; | ||
|
|
||
| export const declaration: CommandDeclaration = { | ||
| name: 'openNoteInNewWindow', | ||
| label: () => _('Edit in new window'), | ||
| iconName: 'icon-share', | ||
| }; | ||
|
|
||
| export const runtime = (): CommandRuntime => { | ||
| return { | ||
| execute: async (context: CommandContext, noteId: string = null) => { | ||
| noteId = noteId || stateUtils.selectedNoteId(context.state); | ||
| context.dispatch({ type: 'NOTE_WINDOW_OPEN', noteId }); | ||
| }, | ||
| enabledCondition: 'oneNoteSelected', | ||
| }; | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| import shim from '@joplin/lib/shim'; | ||
| import * as React from 'react'; | ||
| import { useState, useEffect, useRef } from 'react'; | ||
| import { createPortal } from 'react-dom'; | ||
|
|
||
| interface Props { | ||
| // Note: children will be rendered in a different DOM from this node. Avoid using document.* methods | ||
| // in child components. | ||
| children: React.ReactNode[]|React.ReactNode; | ||
| newWindow: boolean; | ||
| onClose: ()=> void; | ||
| } | ||
|
|
||
| const NewWindowOrIFrame: React.FC<Props> = props => { | ||
| const [iframeRef, setIframeRef] = useState<HTMLIFrameElement|null>(null); | ||
| const [loaded, setLoaded] = useState(false); | ||
| const [doc, setDoc] = useState<Document>(null); | ||
|
|
||
| const onCloseRef = useRef(props.onClose); | ||
| onCloseRef.current = props.onClose; | ||
|
|
||
| useEffect(() => { | ||
| let openedWindow: Window|null = null; | ||
| const unmounted = false; | ||
| if (iframeRef) { | ||
| setDoc(iframeRef?.contentWindow?.document); | ||
| } else if (props.newWindow) { | ||
| openedWindow = window.open('about:blank'); | ||
| setDoc(openedWindow.document); | ||
|
|
||
| // .onbeforeunload and .onclose events don't seem to fire when closed by a user -- rely on polling | ||
| // instead: | ||
| void (async () => { | ||
| while (!unmounted) { | ||
| await new Promise<void>(resolve => { | ||
| shim.setTimeout(() => resolve(), 2000); | ||
| }); | ||
|
|
||
| if (openedWindow?.closed) { | ||
| onCloseRef.current?.(); | ||
| openedWindow = null; | ||
| break; | ||
| } | ||
| } | ||
| })(); | ||
| } | ||
|
|
||
| return () => { | ||
| // Delay: Closing immediately causes Electron to crash | ||
| setTimeout(() => { | ||
| if (!openedWindow?.closed) { | ||
| openedWindow?.close(); | ||
| onCloseRef.current?.(); | ||
| openedWindow = null; | ||
| } | ||
| }, 200); | ||
|
|
||
| if (iframeRef && !openedWindow) { | ||
| onCloseRef.current?.(); | ||
| } | ||
| }; | ||
| }, [iframeRef, props.newWindow]); | ||
|
|
||
| useEffect(() => { | ||
| if (!doc) return; | ||
|
|
||
| doc.open(); | ||
| doc.write('<!DOCTYPE html><html><head></head><body></body></html>'); | ||
| doc.close(); | ||
|
|
||
| const cssUrls = [ | ||
| 'style.min.css', | ||
| 'style/icons/style.css', | ||
| 'vendor/lib/@fortawesome/fontawesome-free/css/all.min.css', | ||
| 'vendor/lib/react-datetime/css/react-datetime.css', | ||
| 'vendor/lib/smalltalk/css/smalltalk.css', | ||
| 'vendor/lib/roboto-fontface/css/roboto/roboto-fontface.css', | ||
| 'vendor/lib/codemirror/lib/codemirror.css', | ||
| ]; | ||
|
|
||
| for (const url of cssUrls) { | ||
| const style = doc.createElement('link'); | ||
| style.rel = 'stylesheet'; | ||
| style.href = url; | ||
| doc.head.appendChild(style); | ||
| } | ||
|
|
||
| doc.body.style.height = '100vh'; | ||
|
|
||
| setLoaded(true); | ||
| }, [doc]); | ||
| const parentNode = loaded ? doc?.body : null; | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Needed to allow adding the portal to the DOM | ||
| const contentPortal = parentNode && createPortal(props.children, parentNode) as any; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related documentation/explanation:
|
||
| if (props.newWindow) { | ||
| return <div style={{ display: 'none' }}>{contentPortal}</div>; | ||
| } else { | ||
| return <iframe | ||
| ref={setIframeRef} | ||
| style={{ flexGrow: 1, width: '100%', height: '100%', border: 'none' }} | ||
| > | ||
| {contentPortal} | ||
| </iframe>; | ||
| } | ||
| }; | ||
|
|
||
| export default NewWindowOrIFrame; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.