@ -121,6 +121,7 @@ import {
CANVAS_ONLY_ACTIONS ,
DEFAULT_VERTICAL_ALIGN ,
GRID_SIZE ,
LOCAL_STORAGE_KEY_COLLAB_FORCE_FLAG ,
} from "../constants" ;
import {
INITAL_SCENE_UPDATE_TIMEOUT ,
@ -356,6 +357,39 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this . onSceneUpdated ( ) ;
} ;
private shouldForceLoadScene (
scene : ResolutionType < typeof loadScene > ,
) : boolean {
if ( ! scene . elements . length ) {
return true ;
}
const roomMatch = getCollaborationLinkData ( window . location . href ) ;
if ( ! roomMatch ) {
return false ;
}
const collabForceLoadFlag = localStorage . getItem (
LOCAL_STORAGE_KEY_COLLAB_FORCE_FLAG ,
) ;
if ( collabForceLoadFlag ) {
try {
const {
room : previousRoom ,
timestamp ,
} : { room : string ; timestamp : number } = JSON . parse (
collabForceLoadFlag ,
) ;
// if loading same room as the one previously unloaded within 15sec
// force reload without prompting
if ( previousRoom === roomMatch [ 1 ] && Date . now ( ) - timestamp < 15000 ) {
return true ;
}
} catch { }
}
return false ;
}
private initializeScene = async ( ) = > {
const searchParams = new URLSearchParams ( window . location . search ) ;
const id = searchParams . get ( "id" ) ;
@ -363,20 +397,28 @@ class App extends React.Component<ExcalidrawProps, AppState> {
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/ ,
) ;
const isCollaborationScene = getCollaborationLinkData ( window . location . href ) ;
let scene = await loadScene ( null ) ;
let isCollaborationScene = ! ! getCollaborationLinkData ( window . location . href ) ;
const isExternalScene = ! ! ( id || jsonMatch || isCollaborationScene ) ;
if ( ! isCollaborationScene ) {
let scene : ResolutionType < typeof loadScene > | undefined ;
// Backwards compatibility with legacy url format
if ( id ) {
scene = await loadScene ( id ) ;
} else if ( jsonMatch ) {
scene = await loadScene ( jsonMatch [ 1 ] , jsonMatch [ 2 ] ) ;
if ( isExternalScene ) {
if (
this . shouldForceLoadScene ( scene ) ||
window . confirm ( t ( "alerts.loadSceneOverridePrompt" ) )
) {
// Backwards compatibility with legacy url format
if ( id ) {
scene = await loadScene ( id ) ;
} else if ( jsonMatch ) {
scene = await loadScene ( jsonMatch [ 1 ] , jsonMatch [ 2 ] ) ;
}
if ( ! isCollaborationScene ) {
window . history . replaceState ( { } , "Excalidraw" , window . location . origin ) ;
}
} else {
scene = await loadScene ( null ) ;
}
if ( scene ) {
this . syncActionResult ( scene ) ;
isCollaborationScene = false ;
window . history . replaceState ( { } , "Excalidraw" , window . location . origin ) ;
}
}
@ -384,9 +426,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
this . setState ( { isLoading : false } ) ;
}
// run this last else the `isLoading` state
if ( isCollaborationScene ) {
this . initializeSocketClient ( { showLoadingState : true } ) ;
} else if ( scene ) {
this . syncActionResult ( scene ) ;
}
} ;
@ -515,6 +558,15 @@ class App extends React.Component<ExcalidrawProps, AppState> {
}
private beforeUnload = withBatchedUpdates ( ( event : BeforeUnloadEvent ) = > {
if ( this . state . isCollaborating && this . portal . roomID ) {
localStorage . setItem (
LOCAL_STORAGE_KEY_COLLAB_FORCE_FLAG ,
JSON . stringify ( {
timestamp : Date.now ( ) ,
room : this.portal.roomID ,
} ) ,
) ;
}
if (
this . state . isCollaborating &&
globalSceneState . getElements ( ) . length > 0