From 73cddedc1f4f3ac430bd472f73b4b89adb805410 Mon Sep 17 00:00:00 2001 From: Nathan Wang Date: Tue, 22 Aug 2023 18:17:42 -0700 Subject: [PATCH] fix copy input / scribble bug; allow multiple default values --- src/components/RealtimeEditor.tsx | 15 ++++++--------- src/context/EditorContext.tsx | 16 ++++++++-------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/components/RealtimeEditor.tsx b/src/components/RealtimeEditor.tsx index 9d5f945..f5771f0 100644 --- a/src/components/RealtimeEditor.tsx +++ b/src/components/RealtimeEditor.tsx @@ -26,17 +26,13 @@ const WEBSOCKET_SERVER = SHOULD_USE_DEV_YJS_SERVER const RealtimeEditor = ({ onMount, - /** - * Warning: with the current implementation (EditorContext.doNotInitializeCodeRef), - * only one realtime editor can have defaultValue (the main code editor). - */ defaultValue, yjsDocumentId, useEditorWithVim = false, dataTestId = '', ...props }: RealtimeEditorProps): JSX.Element => { - const { doNotInitializeCodeRef } = useEditorContext(); + const { doNotInitializeTheseFileIdsRef } = useEditorContext(); const [editor, setEditor] = useState(null); const { userData, firebaseUser } = useUserContext(); @@ -126,17 +122,18 @@ const RealtimeEditor = ({ ); provider.on('sync', (isSynced: boolean) => { // Handle file initialization - // We need to check for doNotInitializeCodeRef.current here + // We need to check for doNotInitializeTheseFileIdsRef.current here // to make sure we're the client that's supposed to initialize the document. // This is to prevent multiple clients from initializing the document when the language changes. // See EditorContext.tsx for more information - if (isSynced && defaultValue && !doNotInitializeCodeRef.current) { + if (isSynced && !doNotInitializeTheseFileIdsRef.current[yjsDocumentId]) { const isInitializedMap = ydocument.getMap('isInitialized'); if (!isInitializedMap.get('isInitialized')) { isInitializedMap.set('isInitialized', true); - if (monacoText.length === 0) monacoText.insert(0, defaultValue ?? ''); + if (monacoText.length === 0 && defaultValue) + monacoText.insert(0, defaultValue ?? ''); } - doNotInitializeCodeRef.current = true; + doNotInitializeTheseFileIdsRef.current[yjsDocumentId] = true; } setIsSynced(isSynced); setLoading(false); diff --git a/src/context/EditorContext.tsx b/src/context/EditorContext.tsx index 275ad3a..92ff689 100644 --- a/src/context/EditorContext.tsx +++ b/src/context/EditorContext.tsx @@ -51,19 +51,19 @@ export type EditorContextType = { fileData: FileData; updateFileData: (firebaseUpdateData: Partial) => Promise; /** + * Maps YJS File ID ==> true / false + * If file ID is not in the map, assume it's false + * * If true, this client should NOT initialize the code if it's empty. * This solves the bug that if multiple people are on the same document, * and the document changes languages, every client will try to initialize * the code (resuting in multiple templates being inserted). * - * Instead, after the file is loaded & synced, doNotInitializeCode is set + * Instead, after the file is loaded & synced, doNotInitializeTheseFileIds is set * to true. Then, if the language is changed, the client who triggered the * language change (and only that client) will have this set to false. - * - * Note that with our current implementation, only one defaultValue will work - * (ie. you can only have one RealtimeEdtior component with a defaultValue) */ - doNotInitializeCodeRef: MutableRefObject; + doNotInitializeTheseFileIdsRef: MutableRefObject>; }; const EditorContext = createContext(null); @@ -92,7 +92,7 @@ export function EditorProvider({ const { userData } = useUserContext(); const [fileData, setFileData] = useState(null); const [loading, setLoading] = useState(true); - const doNotInitializeCodeRef = useRef(false); + const doNotInitializeTheseFileIdsRef = useRef>({}); useEffect(() => { setLoading(true); @@ -132,8 +132,8 @@ export function EditorProvider({ ); const editorContextValue = useMemo(() => { - return { fileData, updateFileData, doNotInitializeCodeRef }; - }, [fileData, updateFileData, doNotInitializeCodeRef]); + return { fileData, updateFileData, doNotInitializeTheseFileIdsRef }; + }, [fileData, updateFileData, doNotInitializeTheseFileIdsRef]); if (loading) { return <>{loadingUI};