|
|
@ -176,7 +176,11 @@ import {
|
|
|
|
import { MaybeTransformHandleType } from "../element/transformHandles";
|
|
|
|
import { MaybeTransformHandleType } from "../element/transformHandles";
|
|
|
|
import { renderSpreadsheet } from "../charts";
|
|
|
|
import { renderSpreadsheet } from "../charts";
|
|
|
|
import { isValidLibrary } from "../data/json";
|
|
|
|
import { isValidLibrary } from "../data/json";
|
|
|
|
import { loadFromFirebase, saveToFirebase } from "../data/firebase";
|
|
|
|
import {
|
|
|
|
|
|
|
|
loadFromFirebase,
|
|
|
|
|
|
|
|
saveToFirebase,
|
|
|
|
|
|
|
|
isSavedToFirebase,
|
|
|
|
|
|
|
|
} from "../data/firebase";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @param func handler taking at most single parameter (event).
|
|
|
|
* @param func handler taking at most single parameter (event).
|
|
|
@ -469,7 +473,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const roomId = roomMatch[1];
|
|
|
|
const roomID = roomMatch[1];
|
|
|
|
|
|
|
|
|
|
|
|
let collabForceLoadFlag;
|
|
|
|
let collabForceLoadFlag;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
@ -488,7 +492,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
// if loading same room as the one previously unloaded within 15sec
|
|
|
|
// if loading same room as the one previously unloaded within 15sec
|
|
|
|
// force reload without prompting
|
|
|
|
// force reload without prompting
|
|
|
|
if (previousRoom === roomId && Date.now() - timestamp < 15000) {
|
|
|
|
if (previousRoom === roomID && Date.now() - timestamp < 15000) {
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch {}
|
|
|
|
} catch {}
|
|
|
@ -784,7 +788,17 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
);
|
|
|
|
);
|
|
|
|
} catch {}
|
|
|
|
} catch {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.state.isCollaborating && this.scene.getElements().length > 0) {
|
|
|
|
const syncableElements = getSyncableElements(
|
|
|
|
|
|
|
|
this.scene.getElementsIncludingDeleted(),
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
this.state.isCollaborating &&
|
|
|
|
|
|
|
|
!isSavedToFirebase(this.portal, syncableElements)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// this won't run in time if user decides to leave the site, but
|
|
|
|
|
|
|
|
// the purpose is to run in immediately after user decides to stay
|
|
|
|
|
|
|
|
this.saveCollabRoomToFirebase(syncableElements);
|
|
|
|
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
event.preventDefault();
|
|
|
|
// NOTE: modern browsers no longer allow showing a custom message here
|
|
|
|
// NOTE: modern browsers no longer allow showing a custom message here
|
|
|
|
event.returnValue = "";
|
|
|
|
event.returnValue = "";
|
|
|
@ -1182,6 +1196,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
closePortal = () => {
|
|
|
|
closePortal = () => {
|
|
|
|
|
|
|
|
this.saveCollabRoomToFirebase();
|
|
|
|
window.history.pushState({}, "Excalidraw", window.location.origin);
|
|
|
|
window.history.pushState({}, "Excalidraw", window.location.origin);
|
|
|
|
this.destroySocketClient();
|
|
|
|
this.destroySocketClient();
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1227,8 +1242,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const roomMatch = getCollaborationLinkData(window.location.href);
|
|
|
|
const roomMatch = getCollaborationLinkData(window.location.href);
|
|
|
|
if (roomMatch) {
|
|
|
|
if (roomMatch) {
|
|
|
|
const roomId = roomMatch[1];
|
|
|
|
const roomID = roomMatch[1];
|
|
|
|
const roomSecret = roomMatch[2];
|
|
|
|
const roomKey = roomMatch[2];
|
|
|
|
|
|
|
|
|
|
|
|
const initialize = () => {
|
|
|
|
const initialize = () => {
|
|
|
|
this.portal.socketInitialized = true;
|
|
|
|
this.portal.socketInitialized = true;
|
|
|
@ -1358,7 +1373,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
/* webpackChunkName: "socketIoClient" */ "socket.io-client"
|
|
|
|
/* webpackChunkName: "socketIoClient" */ "socket.io-client"
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
this.portal.open(socketIOClient(SOCKET_SERVER), roomId, roomSecret);
|
|
|
|
this.portal.open(socketIOClient(SOCKET_SERVER), roomID, roomKey);
|
|
|
|
|
|
|
|
|
|
|
|
// All socket listeners are moving to Portal
|
|
|
|
// All socket listeners are moving to Portal
|
|
|
|
this.portal.socket!.on(
|
|
|
|
this.portal.socket!.on(
|
|
|
@ -1430,7 +1445,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const elements = await loadFromFirebase(roomId, roomSecret);
|
|
|
|
const elements = await loadFromFirebase(roomID, roomKey);
|
|
|
|
if (elements) {
|
|
|
|
if (elements) {
|
|
|
|
updateScene(
|
|
|
|
updateScene(
|
|
|
|
{ type: "SCENE_UPDATE", payload: { elements } },
|
|
|
|
{ type: "SCENE_UPDATE", payload: { elements } },
|
|
|
@ -1484,6 +1499,18 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
saveCollabRoomToFirebase = async (
|
|
|
|
|
|
|
|
syncableElements: ExcalidrawElement[] = getSyncableElements(
|
|
|
|
|
|
|
|
this.scene.getElementsIncludingDeleted(),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
await saveToFirebase(this.portal, syncableElements);
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error(error);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// maybe should move to Portal
|
|
|
|
// maybe should move to Portal
|
|
|
|
broadcastScene = async (
|
|
|
|
broadcastScene = async (
|
|
|
|
sceneType: SCENE.INIT | SCENE.UPDATE,
|
|
|
|
sceneType: SCENE.INIT | SCENE.UPDATE,
|
|
|
@ -1530,16 +1557,10 @@ class App extends React.Component<ExcalidrawProps, AppState> {
|
|
|
|
data as SocketUpdateData,
|
|
|
|
data as SocketUpdateData,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (syncAll && this.portal.roomID && this.portal.roomKey) {
|
|
|
|
if (syncAll && this.state.isCollaborating) {
|
|
|
|
await Promise.all([
|
|
|
|
await Promise.all([
|
|
|
|
broadcastPromise,
|
|
|
|
broadcastPromise,
|
|
|
|
saveToFirebase(
|
|
|
|
this.saveCollabRoomToFirebase(syncableElements),
|
|
|
|
this.portal.roomID,
|
|
|
|
|
|
|
|
this.portal.roomKey,
|
|
|
|
|
|
|
|
syncableElements,
|
|
|
|
|
|
|
|
).catch((e) => {
|
|
|
|
|
|
|
|
console.error(e);
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
]);
|
|
|
|
]);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
await broadcastPromise;
|
|
|
|
await broadcastPromise;
|
|
|
|