Merge branch 'v2.6.x-release' into tldraw-with-annotation-export

This commit is contained in:
Daniel Petri Rocha 2022-05-24 10:33:04 +02:00
commit 745034da12
22 changed files with 269 additions and 5637 deletions

View File

@ -108,17 +108,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
#TD-Tools > div { #TD-Tools > div {
flex-direction: column; flex-direction: column;
} }
#TD-Styles + div {
display: none;
}
</style> </style>
<script> <script>
document.addEventListener('gesturestart', function (e) { document.addEventListener('gesturestart', function (e) {
e.preventDefault(); e.preventDefault();
}); });
</script> </script>
<script src="compatibility/adapter.js?v=VERSION" language="javascript"></script>
<script src="compatibility/sip.js?v=VERSION" language="javascript"></script> <script src="compatibility/sip.js?v=VERSION" language="javascript"></script>
<script src="compatibility/kurento-utils.js?v=VERSION" language="javascript"></script> <script src="compatibility/kurento-utils.js?v=VERSION" language="javascript"></script>
<script src="compatibility/tflite-simd.js?v=VERSION" language="javascript"></script> <script src="compatibility/tflite-simd.js?v=VERSION" language="javascript"></script>

View File

@ -31,6 +31,9 @@ import ChatAdapter from '/imports/ui/components/components-data/chat-context/ada
import UsersAdapter from '/imports/ui/components/components-data/users-context/adapter'; import UsersAdapter from '/imports/ui/components/components-data/users-context/adapter';
import GroupChatAdapter from '/imports/ui/components/components-data/group-chat-context/adapter'; import GroupChatAdapter from '/imports/ui/components/components-data/group-chat-context/adapter';
import { liveDataEventBrokerInitializer } from '/imports/ui/services/LiveDataEventBroker/LiveDataEventBroker'; import { liveDataEventBrokerInitializer } from '/imports/ui/services/LiveDataEventBroker/LiveDataEventBroker';
// The adapter import is "unused" as far as static code is concerned, but it
// needs to here to override global prototypes. So: don't remove it - prlanzarin 25 Apr 2022
import adapter from 'webrtc-adapter';
import collectionMirrorInitializer from './collection-mirror-initializer'; import collectionMirrorInitializer from './collection-mirror-initializer';

View File

@ -30,11 +30,9 @@ const process = () => {
}; };
export default function handleWhiteboardSend({ header, body }, meetingId) { export default function handleWhiteboardSend({ header, body }, meetingId) {
//console.log("!!!!!!!!!! handleWhiteboardSend!!!!!!!!!!: ");
const userId = header.userId; const userId = header.userId;
const whiteboardId = body.whiteboardId; const whiteboardId = body.whiteboardId;
const annotations = body.annotations; const annotations = body.annotations;
//console.log(annotations);
check(userId, String); check(userId, String);
check(whiteboardId, String); check(whiteboardId, String);
@ -45,13 +43,11 @@ export default function handleWhiteboardSend({ header, body }, meetingId) {
} }
annotations.map(annotation => { annotations.map(annotation => {
annotationsQueue[meetingId].push({ meetingId, whiteboardId, userId, annotation }); annotationsQueue[meetingId].push({ meetingId, whiteboardId, userId: annotation.userId, annotation });
addAnnotation(meetingId, whiteboardId, userId, annotation); addAnnotation(meetingId, whiteboardId, annotation.userId, annotation);
}) })
if (queueMetrics) { if (queueMetrics) {
Metrics.setAnnotationQueueLength(meetingId, annotationsQueue[meetingId].length); Metrics.setAnnotationQueueLength(meetingId, annotationsQueue[meetingId].length);
} }
if (!annotationsRecieverIsRunning) process(); if (!annotationsRecieverIsRunning) process();
//return addAnnotation(meetingId, whiteboardId, userId, annotation);
} }

View File

@ -22,13 +22,6 @@ export default function deleteAnnotations(annotations, whiteboardId) {
annotationsIds: annotations, annotationsIds: annotations,
}; };
console.log('$$$$$$$$$$$ shapes to remove $$$$$$$$$$$$$$$$$$$$$$')
console.log('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
console.log(annotations)
console.log('$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
// shape.meetingId = meetingId;
//deleteShape(shape);
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
} catch (err) { } catch (err) {
Logger.error(`Exception while invoking method deleteAnnotation ${err.stack}`); Logger.error(`Exception while invoking method deleteAnnotation ${err.stack}`);

View File

@ -23,9 +23,6 @@ export default function sendAnnotationHelper(annotations, meetingId, requesterUs
annotations: whiteboardAnnotations, annotations: whiteboardAnnotations,
}; };
//console.log("AEAFAEWFEWFWE")
//console.log(annotations)
RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
}); });

View File

@ -5,7 +5,6 @@ import transferUser from './methods/transferUser';
import toggleLockSettings from './methods/toggleLockSettings'; import toggleLockSettings from './methods/toggleLockSettings';
import toggleWebcamsOnlyForModerator from './methods/toggleWebcamsOnlyForModerator'; import toggleWebcamsOnlyForModerator from './methods/toggleWebcamsOnlyForModerator';
import clearRandomlySelectedUser from './methods/clearRandomlySelectedUser'; import clearRandomlySelectedUser from './methods/clearRandomlySelectedUser';
import changeCurrentSlide from './methods/changeCurrentSlide';
import changeLayout from './methods/changeLayout'; import changeLayout from './methods/changeLayout';
Meteor.methods({ Meteor.methods({
@ -16,5 +15,4 @@ Meteor.methods({
toggleWebcamsOnlyForModerator, toggleWebcamsOnlyForModerator,
clearRandomlySelectedUser, clearRandomlySelectedUser,
changeLayout, changeLayout,
changeCurrentSlide,
}); });

View File

@ -1,31 +0,0 @@
import Logger from '/imports/startup/server/logger';
import RedisPubSub from '/imports/startup/server/redis';
import { extractCredentials } from '/imports/api/common/server/helpers';
import { check } from 'meteor/check';
import setCurrentSlide from '../modifiers/setCurrentSlide';
export default function changeCurrentSlide(slideNum) {
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
const EVENT_NAME = 'BroadcastLayoutMsg';
console.log('$$$$$$$$$$$$$$$$$$$')
console.log(slideNum)
console.log('$$$$$$$$$$$$$$$$$$$')
try {
const { meetingId, requesterUserId } = extractCredentials(this.userId);
setCurrentSlide(meetingId, slideNum);
// check(meetingId, String);
// check(requesterUserId, String);
// const payload = {
// layout,
// };
// RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
} catch (err) {
// Logger.error(`Exception while invoking method changeLayout ${err.stack}`);
}
}

View File

@ -1,25 +0,0 @@
import Logger from '/imports/startup/server/logger';
import Meetings from '/imports/api/meetings';
import { check } from 'meteor/check';
export default function setCurrentSlide(meetingId, slideNum) {
try {
const selector = {
meetingId,
};
const modifier = {
$set: {
activeSlide: slideNum,
},
};
const activeUpdate = Meetings.update(selector, modifier);
if (activeUpdate) {
Logger.info(`Meeting active slide changed for meeting=${meetingId}`);
}
} catch (err) {
Logger.error(`Exception while invoking method setCurrentSlide ${err.stack}`);
}
}

View File

@ -1,12 +1,3 @@
// import { Meteor } from 'meteor/meteor';
// import switchSlide from './methods/switchSlide';
// import zoomSlide from './methods/zoomSlide';
// Meteor.methods({
// switchSlide,
// zoomSlide,
// });
import { Meteor } from 'meteor/meteor'; import { Meteor } from 'meteor/meteor';
import switchSlide from './methods/switchSlide'; import switchSlide from './methods/switchSlide';
import zoomSlide from './methods/zoomSlide'; import zoomSlide from './methods/zoomSlide';
@ -16,4 +7,4 @@ Meteor.methods({
switchSlide, switchSlide,
zoomSlide, zoomSlide,
persistAsset, persistAsset,
}); });

View File

@ -101,17 +101,16 @@ export default function addSlide(meetingId, podId, presentationId, slide) {
const slideData = { const slideData = {
width, width,
height, height,
x: xCamera, xCamera,
y: yCamera, yCamera,
zoom, zoom,
}; };
const slidePosition = calculateSlideData(slideData); //const slidePosition = calculateSlideData(slideData);
addSlidePositions(meetingId, podId, presentationId, slideId, slideData); addSlidePositions(meetingId, podId, presentationId, slideId, slideData);
} }
try { try {
console.log("modifier!!! ", modifier )
const { insertedId, numberAffected } = Slides.upsert(selector, modifier); const { insertedId, numberAffected } = Slides.upsert(selector, modifier);
requestWhiteboardHistory(meetingId, slideId); requestWhiteboardHistory(meetingId, slideId);

View File

@ -18,8 +18,8 @@ export default function addSlidePositions(
check(slidePosition, { check(slidePosition, {
width: Number, width: Number,
height: Number, height: Number,
x: Number, xCamera: Number,
y: Number, yCamera: Number,
zoom: Number, zoom: Number,
}); });

View File

@ -931,7 +931,8 @@ class Presentation extends PureComponent {
slidePosition={slidePosition} slidePosition={slidePosition}
getSvgRef={this.getSvgRef} getSvgRef={this.getSvgRef}
setTldrawAPI={this.setTldrawAPI} setTldrawAPI={this.setTldrawAPI}
curPageId={this.state.tldrawAPI?.getPage()?.id} curPageId={currentSlide?.num.toString()}
svgUri={currentSlide?.svgUri}
/> />
{isFullscreen && <PollingContainer />} {isFullscreen && <PollingContainer />}
{this.renderPresentationToolbar()} {this.renderPresentationToolbar()}

View File

@ -1,78 +1,74 @@
import React, { PureComponent } from "react"; import React, { PureComponent } from 'react';
import PropTypes from "prop-types"; import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from "react-intl"; import { defineMessages, injectIntl } from 'react-intl';
import deviceInfo from "/imports/utils/deviceInfo"; import deviceInfo from '/imports/utils/deviceInfo';
import injectWbResizeEvent from "/imports/ui/components/presentation/resize-wrapper/component"; import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component';
import { import { HUNDRED_PERCENT, MAX_PERCENT, STEP } from '/imports/utils/slideCalcUtils';
HUNDRED_PERCENT, import Styled from './styles';
MAX_PERCENT, import ZoomTool from './zoom-tool/component';
STEP, import TooltipContainer from '/imports/ui/components/common/tooltip/container';
} from "/imports/utils/slideCalcUtils"; import KEY_CODES from '/imports/utils/keyCodes';
import Styled from "./styles";
import ZoomTool from "./zoom-tool/component";
import TooltipContainer from "/imports/ui/components/common/tooltip/container";
import KEY_CODES from "/imports/utils/keyCodes";
const intlMessages = defineMessages({ const intlMessages = defineMessages({
previousSlideLabel: { previousSlideLabel: {
id: "app.presentation.presentationToolbar.prevSlideLabel", id: 'app.presentation.presentationToolbar.prevSlideLabel',
description: "Previous slide button label", description: 'Previous slide button label',
}, },
previousSlideDesc: { previousSlideDesc: {
id: "app.presentation.presentationToolbar.prevSlideDesc", id: 'app.presentation.presentationToolbar.prevSlideDesc',
description: "Aria description for when switching to previous slide", description: 'Aria description for when switching to previous slide',
}, },
nextSlideLabel: { nextSlideLabel: {
id: "app.presentation.presentationToolbar.nextSlideLabel", id: 'app.presentation.presentationToolbar.nextSlideLabel',
description: "Next slide button label", description: 'Next slide button label',
}, },
nextSlideDesc: { nextSlideDesc: {
id: "app.presentation.presentationToolbar.nextSlideDesc", id: 'app.presentation.presentationToolbar.nextSlideDesc',
description: "Aria description for when switching to next slide", description: 'Aria description for when switching to next slide',
}, },
noNextSlideDesc: { noNextSlideDesc: {
id: "app.presentation.presentationToolbar.noNextSlideDesc", id: 'app.presentation.presentationToolbar.noNextSlideDesc',
description: "", description: '',
}, },
noPrevSlideDesc: { noPrevSlideDesc: {
id: "app.presentation.presentationToolbar.noPrevSlideDesc", id: 'app.presentation.presentationToolbar.noPrevSlideDesc',
description: "", description: '',
}, },
skipSlideLabel: { skipSlideLabel: {
id: "app.presentation.presentationToolbar.skipSlideLabel", id: 'app.presentation.presentationToolbar.skipSlideLabel',
description: "Aria label for when switching to a specific slide", description: 'Aria label for when switching to a specific slide',
}, },
skipSlideDesc: { skipSlideDesc: {
id: "app.presentation.presentationToolbar.skipSlideDesc", id: 'app.presentation.presentationToolbar.skipSlideDesc',
description: "Aria description for when switching to a specific slide", description: 'Aria description for when switching to a specific slide',
}, },
goToSlide: { goToSlide: {
id: "app.presentation.presentationToolbar.goToSlide", id: 'app.presentation.presentationToolbar.goToSlide',
description: "button for slide select", description: 'button for slide select',
}, },
selectLabel: { selectLabel: {
id: "app.presentation.presentationToolbar.selectLabel", id: 'app.presentation.presentationToolbar.selectLabel',
description: "slide select label", description: 'slide select label',
}, },
fitToWidth: { fitToWidth: {
id: "app.presentation.presentationToolbar.fitToWidth", id: 'app.presentation.presentationToolbar.fitToWidth',
description: "button for fit to width", description: 'button for fit to width',
}, },
fitToWidthDesc: { fitToWidthDesc: {
id: "app.presentation.presentationToolbar.fitWidthDesc", id: 'app.presentation.presentationToolbar.fitWidthDesc',
description: "Aria description to display the whole width of the slide", description: 'Aria description to display the whole width of the slide',
}, },
fitToPage: { fitToPage: {
id: "app.presentation.presentationToolbar.fitToPage", id: 'app.presentation.presentationToolbar.fitToPage',
description: "button label for fit to width", description: 'button label for fit to width',
}, },
fitToPageDesc: { fitToPageDesc: {
id: "app.presentation.presentationToolbar.fitScreenDesc", id: 'app.presentation.presentationToolbar.fitScreenDesc',
description: "Aria description to display the whole slide", description: 'Aria description to display the whole slide',
}, },
presentationLabel: { presentationLabel: {
id: "app.presentationUploder.title", id: 'app.presentationUploder.title',
description: "presentation area element label", description: 'presentation area element label',
}, },
}); });
@ -80,10 +76,6 @@ class PresentationToolbar extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {
curPageId: 1,
};
this.handleSkipToSlideChange = this.handleSkipToSlideChange.bind(this); this.handleSkipToSlideChange = this.handleSkipToSlideChange.bind(this);
this.change = this.change.bind(this); this.change = this.change.bind(this);
this.renderAriaDescs = this.renderAriaDescs.bind(this); this.renderAriaDescs = this.renderAriaDescs.bind(this);
@ -94,16 +86,16 @@ class PresentationToolbar extends PureComponent {
} }
componentDidMount() { componentDidMount() {
document.addEventListener("keydown", this.switchSlide); document.addEventListener('keydown', this.switchSlide);
} }
componentWillUnmount() { componentWillUnmount() {
document.removeEventListener("keydown", this.switchSlide); document.removeEventListener('keydown', this.switchSlide);
} }
switchSlide(event) { switchSlide(event) {
const { target, which } = event; const { target, which } = event;
const isBody = target.nodeName === "BODY"; const isBody = target.nodeName === 'BODY';
if (isBody) { if (isBody) {
switch (which) { switch (which) {
@ -124,26 +116,34 @@ class PresentationToolbar extends PureComponent {
} }
handleSkipToSlideChange(event) { handleSkipToSlideChange(event) {
const { skipToSlide, podId } = this.props; const {
skipToSlide,
podId,
} = this.props;
const requestedSlideNum = Number.parseInt(event.target.value, 10); const requestedSlideNum = Number.parseInt(event.target.value, 10);
if (event) event.currentTarget.blur(); if (event) event.currentTarget.blur();
// skipToSlide(requestedSlideNum, podId); skipToSlide(requestedSlideNum, podId);
this.props?.tldrawAPI?.changePage(requestedSlideNum);
this.setState({
curPageId: parseInt(this.props?.tldrawAPI?.getPage()?.id),
});
} }
nextSlideHandler(event) { nextSlideHandler(event) {
const { nextSlide, currentSlideNum, numberOfSlides, podId } = this.props; const {
nextSlide,
currentSlideNum,
numberOfSlides,
podId,
} = this.props;
if (event) event.currentTarget.blur(); if (event) event.currentTarget.blur();
nextSlide(currentSlideNum, numberOfSlides, podId); nextSlide(currentSlideNum, numberOfSlides, podId);
} }
previousSlideHandler(event) { previousSlideHandler(event) {
const { previousSlide, currentSlideNum, podId } = this.props; const {
previousSlide,
currentSlideNum,
podId,
} = this.props;
if (event) event.currentTarget.blur(); if (event) event.currentTarget.blur();
previousSlide(currentSlideNum, podId); previousSlide(currentSlideNum, podId);
@ -160,13 +160,13 @@ class PresentationToolbar extends PureComponent {
} = this.props; } = this.props;
handleToggleFullScreen(fullscreenRef); handleToggleFullScreen(fullscreenRef);
const newElement = isFullscreen ? "" : fullscreenElementId; const newElement = isFullscreen ? '' : fullscreenElementId;
layoutContextDispatch({ layoutContextDispatch({
type: fullscreenAction, type: fullscreenAction,
value: { value: {
element: newElement, element: newElement,
group: "", group: '',
}, },
}); });
} }
@ -211,11 +211,15 @@ class PresentationToolbar extends PureComponent {
const { intl } = this.props; const { intl } = this.props;
const optionList = []; const optionList = [];
for (let i = 1; i <= numberOfSlides; i += 1) { for (let i = 1; i <= numberOfSlides; i += 1) {
optionList.push( optionList.push((
<option value={i} key={i}> <option
{intl.formatMessage(intlMessages.goToSlide, { 0: i })} value={i}
</option> key={i}
); >
{
intl.formatMessage(intlMessages.goToSlide, { 0: i })
}
</option>));
} }
return optionList; return optionList;
@ -241,47 +245,42 @@ class PresentationToolbar extends PureComponent {
const { isMobile } = deviceInfo; const { isMobile } = deviceInfo;
const startOfSlides = parseInt(this.state.curPageId) === 1; const startOfSlides = !(currentSlideNum > 1);
const endOfSlides = parseInt(this.state.curPageId) === numberOfSlides; const endOfSlides = !(currentSlideNum < numberOfSlides);
const prevSlideAriaLabel = startOfSlides const prevSlideAriaLabel = startOfSlides
? intl.formatMessage(intlMessages.previousSlideLabel) ? intl.formatMessage(intlMessages.previousSlideLabel)
: `${intl.formatMessage(intlMessages.previousSlideLabel)} (${ : `${intl.formatMessage(intlMessages.previousSlideLabel)} (${currentSlideNum <= 1 ? '' : (currentSlideNum - 1)})`;
parseInt(this.props?.tldrawAPI?.getPage()?.id) <= 1
? ""
: parseInt(this.props?.tldrawAPI?.getPage()?.id) - 1
})`;
const nextSlideAriaLabel = endOfSlides const nextSlideAriaLabel = endOfSlides
? intl.formatMessage(intlMessages.nextSlideLabel) ? intl.formatMessage(intlMessages.nextSlideLabel)
: `${intl.formatMessage(intlMessages.nextSlideLabel)} (${ : `${intl.formatMessage(intlMessages.nextSlideLabel)} (${currentSlideNum >= 1 ? (currentSlideNum + 1) : ''})`;
parseInt(this.props?.tldrawAPI?.getPage()?.id) >= 1
? parseInt(this.props?.tldrawAPI?.getPage()?.id) + 1
: ""
})`;
return ( return (
<Styled.PresentationToolbarWrapper <Styled.PresentationToolbarWrapper
id="presentationToolbarWrapper" id="presentationToolbarWrapper"
style={{ style={
width: "100%", {
}} width: toolbarWidth,
> }
}>
{this.renderAriaDescs()} {this.renderAriaDescs()}
{ {
<div> <div>
{isPollingEnabled ? ( {isPollingEnabled
<Styled.QuickPollButton ? (
{...{ <Styled.QuickPollButton
currentSlidHasContent, {...{
intl, currentSlidHasContent,
amIPresenter, intl,
parseCurrentSlideContent, amIPresenter,
startPoll, parseCurrentSlideContent,
currentSlide, startPoll,
}} currentSlide,
/> }}
) : null} />
) : null
}
</div> </div>
} }
{ {
@ -289,29 +288,18 @@ class PresentationToolbar extends PureComponent {
<Styled.PrevSlideButton <Styled.PrevSlideButton
role="button" role="button"
aria-label={prevSlideAriaLabel} aria-label={prevSlideAriaLabel}
aria-describedby={ aria-describedby={startOfSlides ? 'noPrevSlideDesc' : 'prevSlideDesc'}
startOfSlides ? "noPrevSlideDesc" : "prevSlideDesc"
}
disabled={startOfSlides || !isMeteorConnected} disabled={startOfSlides || !isMeteorConnected}
color="default" color="default"
icon="left_arrow" icon="left_arrow"
size="md" size="md"
onClick={() => { onClick={this.previousSlideHandler}
this.props?.tldrawAPI?.changePage(
parseInt(this.props?.tldrawAPI?.getPage()?.id) - 1
);
this.setState({
curPageId: parseInt(this.props?.tldrawAPI?.getPage()?.id),
});
}}
label={intl.formatMessage(intlMessages.previousSlideLabel)} label={intl.formatMessage(intlMessages.previousSlideLabel)}
hideLabel hideLabel
data-test="prevSlide" data-test="prevSlide"
/> />
<TooltipContainer <TooltipContainer title={intl.formatMessage(intlMessages.selectLabel)}>
title={intl.formatMessage(intlMessages.selectLabel)}
>
<Styled.SkipSlideSelect <Styled.SkipSlideSelect
id="skipSlide" id="skipSlide"
aria-label={intl.formatMessage(intlMessages.skipSlideLabel)} aria-label={intl.formatMessage(intlMessages.skipSlideLabel)}
@ -319,7 +307,7 @@ class PresentationToolbar extends PureComponent {
aria-live="polite" aria-live="polite"
aria-relevant="all" aria-relevant="all"
disabled={!isMeteorConnected} disabled={!isMeteorConnected}
value={this.state.curPageId} value={currentSlideNum}
onChange={this.handleSkipToSlideChange} onChange={this.handleSkipToSlideChange}
data-test="skipSlide" data-test="skipSlide"
> >
@ -329,21 +317,12 @@ class PresentationToolbar extends PureComponent {
<Styled.NextSlideButton <Styled.NextSlideButton
role="button" role="button"
aria-label={nextSlideAriaLabel} aria-label={nextSlideAriaLabel}
aria-describedby={ aria-describedby={endOfSlides ? 'noNextSlideDesc' : 'nextSlideDesc'}
endOfSlides ? "noNextSlideDesc" : "nextSlideDesc"
}
disabled={endOfSlides || !isMeteorConnected} disabled={endOfSlides || !isMeteorConnected}
color="default" color="default"
icon="right_arrow" icon="right_arrow"
size="md" size="md"
onClick={() => { onClick={this.nextSlideHandler}
this.props?.tldrawAPI?.changePage(
parseInt(this.props?.tldrawAPI?.getPage()?.id) + 1
);
this.setState({
curPageId: parseInt(this.props?.tldrawAPI?.getPage()?.id),
});
}}
label={intl.formatMessage(intlMessages.nextSlideLabel)} label={intl.formatMessage(intlMessages.nextSlideLabel)}
hideLabel hideLabel
data-test="nextSlide" data-test="nextSlide"
@ -352,12 +331,16 @@ class PresentationToolbar extends PureComponent {
} }
{ {
<Styled.PresentationZoomControls> <Styled.PresentationZoomControls>
{!isMobile ? ( {
<TooltipContainer> !isMobile
? (
<TooltipContainer>
<ZoomTool <ZoomTool
zoomValue={ zoomValue={
//this.props?.tldrawAPI?.pageStates[currentSlideNum.toString()]?.camera?.zoom
this.props?.tldrawAPI?.getPageState()?.camera?.zoom this.props?.tldrawAPI?.getPageState()?.camera?.zoom
} }
currentSlideNum={currentSlideNum}
change={this.change} change={this.change}
minBound={0.1} minBound={0.1}
maxBound={5} maxBound={5}
@ -365,19 +348,16 @@ class PresentationToolbar extends PureComponent {
isMeteorConnected={isMeteorConnected} isMeteorConnected={isMeteorConnected}
tldrawAPI={this.props?.tldrawAPI} tldrawAPI={this.props?.tldrawAPI}
/> />
</TooltipContainer> </TooltipContainer>
) : null} )
: null
}
<Styled.FitToWidthButton <Styled.FitToWidthButton
role="button" role="button"
aria-describedby={fitToWidth ? "fitPageDesc" : "fitWidthDesc"} aria-describedby={fitToWidth ? 'fitPageDesc' : 'fitWidthDesc'}
aria-label={ aria-label={fitToWidth
fitToWidth ? `${intl.formatMessage(intlMessages.presentationLabel)} ${intl.formatMessage(intlMessages.fitToPage)}`
? `${intl.formatMessage( : `${intl.formatMessage(intlMessages.presentationLabel)} ${intl.formatMessage(intlMessages.fitToWidth)}`
intlMessages.presentationLabel
)} ${intl.formatMessage(intlMessages.fitToPage)}`
: `${intl.formatMessage(
intlMessages.presentationLabel
)} ${intl.formatMessage(intlMessages.fitToWidth)}`
} }
color="default" color="default"
disabled={!isMeteorConnected} disabled={!isMeteorConnected}

View File

@ -190,7 +190,7 @@ class ZoomTool extends PureComponent {
aria-describedby="resetZoomDescription" aria-describedby="resetZoomDescription"
disabled={(stateZoomValue === minBound) || !isMeteorConnected} disabled={(stateZoomValue === minBound) || !isMeteorConnected}
color="default" color="default"
customIcon={`${this.props?.tldrawAPI?.getPageState()?.camera?.zoom * 100}%`} customIcon={`${parseInt(this.props?.tldrawAPI?.getPageState()?.camera?.zoom * 100)}%`}
size="md" size="md"
onClick={() => tldrawAPI?.zoomTo(1)} onClick={() => tldrawAPI?.zoomTo(1)}
label={intl.formatMessage(intlMessages.resetZoomLabel)} label={intl.formatMessage(intlMessages.resetZoomLabel)}

View File

@ -32,7 +32,7 @@ class UserContent extends PureComponent {
return ( return (
<Styled.Content data-test="userListContent"> <Styled.Content data-test="userListContent">
{isChatEnabled() ? <UserMessagesContainer /> : null} {isChatEnabled() ? <UserMessagesContainer /> : null}
{/* {currentUser.role === ROLE_MODERATOR ? <UserCaptionsContainer /> : null} */} {currentUser.role === ROLE_MODERATOR ? <UserCaptionsContainer /> : null}
<UserNotesContainer /> <UserNotesContainer />
{showWaitingRoom && currentUser.role === ROLE_MODERATOR {showWaitingRoom && currentUser.role === ROLE_MODERATOR
? ( ? (

View File

@ -38,13 +38,13 @@ export default function Whiteboard(props) {
assets, assets,
currentUser, currentUser,
curPres, curPres,
curSlide,
changeCurrentSlide,
whiteboardId, whiteboardId,
podId, podId,
zoomSlide, zoomSlide,
skipToSlide,
slidePosition, slidePosition,
curPageId, curPageId,
svgUri,
} = props; } = props;
const { pages, pageStates } = initDefaultPages(curPres?.pages.length || 1); const { pages, pageStates } = initDefaultPages(curPres?.pages.length || 1);
@ -57,138 +57,96 @@ export default function Whiteboard(props) {
bindings: {}, bindings: {},
assets, assets,
}); });
const [doc, setDoc] = React.useState(rDocument.current); //const [doc, setDoc] = React.useState(rDocument.current);
const [curPage, setCurPage] = React.useState({ id: "1" });
const [_assets, setAssets] = React.useState(assets); const [_assets, setAssets] = React.useState(assets);
const [command, setCommand] = React.useState(""); const [command, setCommand] = React.useState("");
const [wbAccess, setWBAccess] = React.useState(props?.hasMultiUserAccess(props.whiteboardId, props.currentUser.userId)); const [wbAccess, setWBAccess] = React.useState(props?.hasMultiUserAccess(props.whiteboardId, props.currentUser.userId));
const [selectedIds, setSelectedIds] = React.useState([]); const [selectedIds, setSelectedIds] = React.useState([]);
const [tldrawAPI, setTLDrawAPI] = React.useState(null); const [tldrawAPI, setTLDrawAPI] = React.useState(null);
const prevShapes = usePrevious(shapes); const prevShapes = usePrevious(shapes);
const prevPage = usePrevious(curPage);
const prevSlidePosition = usePrevious(slidePosition); const prevSlidePosition = usePrevious(slidePosition);
const prevPageId = usePrevious(curPageId);
const handleChange = React.useCallback((state, reason) => { const doc = React.useMemo(() => {
rDocument.current = state.document;
}, []);
React.useMemo(() => {
const currentDoc = rDocument.current; const currentDoc = rDocument.current;
const propShapes = Object.entries(shapes.filter(s => s.parentId === tldrawAPI?.getPage()?.id) || {})?.map(([k, v]) => v.id);
if (tldrawAPI) { let next = { ...currentDoc };
tldrawAPI?.getPage()?.id && tldrawAPI.changePage(tldrawAPI?.getPage()?.id);
let pageBindings = null;
let history = null;
let stack = null;
let changed = false;
if (next.pageStates[curPageId] && !_.isEqual(prevShapes, shapes)) {
// mergeDocument loses bindings and history, save it
pageBindings = tldrawAPI?.getPage(curPageId)?.bindings;
history = tldrawAPI?.history
stack = tldrawAPI?.stack
next.pages[curPageId].shapes = shapes;
changed = true;
} }
const next = { ...currentDoc }; if (next.pages[curPageId] && !next.pages[curPageId].shapes["slide-background-shape"]) {
next.assets[`slide-background-asset-${curPageId}`] = {
id: `slide-background-asset-${curPageId}`,
size: [slidePosition?.width || 0, slidePosition?.height || 0],
src: svgUri,
type: "image",
};
next.assets = { ...assets }; next.pages[curPageId].shapes["slide-background-shape"] = {
assetId: `slide-background-asset-${curPageId}`,
childIndex: 1,
id: "slide-background-shape",
name: "Image",
type: TDShapeType.Image,
parentId: `${curPageId}`,
point: [0, 0],
isLocked: true,
size: [slidePosition?.width || 0, slidePosition?.height || 0],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
};
const pShapes = Object.entries(shapes || {})?.map(([k, v]) => v.id); changed = true;
shapes.filter(s => s.parentId === tldrawAPI?.getPage()?.id)?.forEach((s) => { }
try {
Object.keys(next.pages[s.parentId].shapes).forEach((k) => {
if (!pShapes.includes(k) && s.parentId === tldrawAPI?.getPage()?.id) {
delete next.pages[s.parentId].shapes[k];
}
});
next.pages[s.parentId] = {
...next.pages[s.parentId],
shapes: {
...next.pages[s.parentId].shapes,
[s.id]: { ...s },
},
};
} catch (err) {
if (changed) {
tldrawAPI?.mergeDocument(next);
if (tldrawAPI && history) tldrawAPI.history = history;
if (tldrawAPI && stack) tldrawAPI.stack = stack;
if (pageBindings && Object.keys(pageBindings).length !== 0) {
currentDoc.pages[curPageId].bindings = pageBindings;
} }
});
if (curPres?.pages.length) {
curPres.pages.map((p, i) => {
next.assets[`slide-background-asset-${i}`] = {
id: `slide-background-asset-${i}`,
size: [slidePosition?.width || 0, slidePosition?.height || 0],
src: curPres?.pages[i]?.svgUri,
type: "image",
};
try {
next.pages[i + 1]["shapes"]["slide-background-shape"] = {
assetId: `slide-background-asset-${i}`,
childIndex: 1,
id: "slide-background-shape",
name: "Image",
type: TDShapeType.Image,
parentId: `${i + 1}`,
point: [0, 0],
isLocked: true,
size: [slidePosition?.width || 0, slidePosition?.height || 0],
style: {
dash: DashStyle.Draw,
size: SizeStyle.Medium,
color: ColorStyle.Blue,
},
};
} catch (err) {
logger.error({
logCode: 'whiteboard_set_slide_background_error',
extraInfo: { error: err },
}, 'Error on adding background slide image');
}
return p;
// setDoc(next);
});
} }
rDocument.current = next; return currentDoc;
}, [assets, shapes, tldrawAPI, curPageId, slidePosition]);
const pageID = tldrawAPI?.getPage()?.id;
if (next.pageStates[pageID]?.selectedIds.length > 0) {
// if a selected id is not in the list of shapes remove it from list
next.pageStates[pageID]?.selectedIds.map((k) => {
if (!next.pages[pageID].shapes[k]) {
next.pageStates[pageID].selectedIds =
next.pageStates[pageID].selectedIds.filter(
(id) => id !== k
);
}
});
}
if (next.pageStates[pageID] && !isPresenter && !_.isEqual(slidePosition, prevSlidePosition)) {
next.pageStates[pageID].camera.point = [slidePosition.xCamera, slidePosition.yCamera]
next.pageStates[pageID].camera.zoom = slidePosition.zoom
}
setDoc(next);
if (
tldrawAPI &&
!_.isEqual(shapes, prevShapes) &&
!_.isEqual(assets, _assets)
) {
setAssets(assets);
tldrawAPI?.replacePageContent(next?.pages[pageID]?.shapes, {}, assets);
}
if (tldrawAPI && !_.isEqual(shapes, prevShapes) && !_.isEqual(assets, _assets)) {
tldrawAPI?.replacePageContent(next?.pages[pageID]?.shapes, {}, assets);
}
}, [assets, shapes, curPres, tldrawAPI, curPageId]);
// change tldraw page when presentation page changes
React.useEffect(() => { React.useEffect(() => {
isPresenter && curPage && changeCurrentSlide(curPage?.id); const previousPageZoom = tldrawAPI?.getPageState()?.camera?.zoom;
}, [curPage]); tldrawAPI &&
curPageId &&
tldrawAPI.changePage(curPageId)
//change zoom of the new page to follow the previous one
previousPageZoom &&
tldrawAPI.zoomTo(previousPageZoom)
}, [curPageId]);
// change tldraw camera when slidePosition changes
React.useEffect(() => { React.useEffect(() => {
tldrawAPI && tldrawAPI &&
!isPresenter && !isPresenter &&
curSlide?.activeSlide && curPageId &&
tldrawAPI.changePage(curSlide?.activeSlide); slidePosition &&
}, [curSlide]); tldrawAPI?.setCamera([slidePosition.xCamera, slidePosition.yCamera], slidePosition.zoom);
}, [curPageId, slidePosition]);
const hasWBAccess = props?.hasMultiUserAccess(props.whiteboardId, props.currentUser.userId); const hasWBAccess = props?.hasMultiUserAccess(props.whiteboardId, props.currentUser.userId);
@ -202,47 +160,58 @@ export default function Whiteboard(props) {
<Tldraw <Tldraw
document={doc} document={doc}
disableAssets={false} disableAssets={false}
onChangePage={(app, s, b, a) => {
setCurPage(app.getPage());
}}
onMount={(app) => { onMount={(app) => {
setTLDrawAPI(app); setTLDrawAPI(app);
props.setTldrawAPI(app); props.setTldrawAPI(app);
curPageId && app.changePage(curPageId);
curPageId && app.setCamera([slidePosition.xCamera, slidePosition.yCamera], slidePosition.zoom)
}} }}
onChange={handleChange} //onChange={handleChange}
onPersist={(e) => { onPersist={(e) => {
///////////// handle assets ///////////////////////// ///////////// handle assets /////////////////////////
e?.assets?.forEach((a) => { e?.assets?.forEach((a) => {
persistAsset(a); //persistAsset(a);
}); });
}} }}
showPages={false} showPages={false}
showZoom={false} showZoom={false}
showUI={isPresenter || hasWBAccess} showUI={curPres ? (isPresenter || hasWBAccess) : true}
showMenu={false} showMenu={curPres ? false : true}
showMultiplayerMenu={false} showMultiplayerMenu={false}
readOnly={!isPresenter && !hasWBAccess} readOnly={!isPresenter && !hasWBAccess}
onUndo={s => { onUndo={(e, s) => {
s?.selectedIds?.map(id => { e?.selectedIds?.map(id => {
persistShape(s.getShape(id), whiteboardId); persistShape(e.getShape(id), whiteboardId);
})
const pageShapes = e.state.document.pages[e.getPage()?.id]?.shapes;
let shapesIdsToRemove = findRemoved(Object.keys(shapes), Object.keys(pageShapes))
removeShapes(shapesIdsToRemove, whiteboardId)
}}
onRedo={(e, s) => {
e?.selectedIds?.map(id => {
persistShape(e.getShape(id), whiteboardId);
});
const pageShapes = e.state.document.pages[e.getPage()?.id]?.shapes;
let shapesIdsToRemove = findRemoved(Object.keys(shapes), Object.keys(pageShapes))
removeShapes(shapesIdsToRemove, whiteboardId)
let shapeIdsToReAdd = findRemoved(Object.keys(pageShapes), Object.keys(shapes))
shapeIdsToReAdd.forEach(id => {
persistShape(pageShapes[id], whiteboardId);
}) })
}} }}
onRedo={s => {
s?.selectedIds?.map(id => {
persistShape(s.getShape(id), whiteboardId);
});
}}
onChangePage={(app, s, b, a) => { onChangePage={(app, s, b, a) => {
if (curPage?.id !== app.getPage()?.id) setCurPage(app.getPage()); if (app.getPage()?.id !== curPageId) {
skipToSlide(Number.parseInt(app.getPage()?.id), podId)
}
}} }}
onCommand={(e, s, g) => { onCommand={(e, s, g) => {
if (s.includes("session:complete:DrawSession")) { if (s.includes("session:complete:DrawSession")) {
Object.entries(rDocument?.current?.pages[e.getPage()?.id]?.shapes) Object.entries(e.state.document.pages[e.getPage()?.id]?.shapes)
.filter(([k, s]) => s?.type === 'draw') .filter(([k, s]) => s?.type === 'draw')
.forEach(([k, s]) => { .forEach(([k, s]) => {
if (!e.prevShapes[k] || !k.includes('slide-background')) { if (!e.prevShapes[k] && !k.includes('slide-background')) {
persistShape(s, whiteboardId); persistShape(s, whiteboardId);
} }
}); });
@ -262,39 +231,44 @@ export default function Whiteboard(props) {
//remove shapes on origin page //remove shapes on origin page
removeShapes(e.selectedIds, whiteboardId); removeShapes(e.selectedIds, whiteboardId);
//persist shapes for destination page //persist shapes for destination page
const newWhiteboardId = curPres.pages.find(page => page.num === Number.parseInt(e.getPage()?.id)).id;
movedShapes.forEach(s => { movedShapes.forEach(s => {
persistShape(s, whiteboardId); persistShape(s, newWhiteboardId);
}); });
} }
if (s?.includes("session:complete:TransformSingleSession") const conditions = [
|| s?.includes("session:complete:TranslateSession") "session:complete:TransformSingleSession", "session:complete:TranslateSession",
|| s?.includes("updated_shapes") "session:complete:TranslateSession", "session:complete:RotateSession",
|| s?.includes("session:complete:RotateSession")) { "session:complete:HandleSession", "updated_shapes", "duplicate",
"stretch", "align", "move", "create", "flip", "toggle", "group",
]
if (conditions.some(el => s?.includes(el))) {
e.selectedIds.forEach(id => { e.selectedIds.forEach(id => {
persistShape(e.getShape(id), whiteboardId); persistShape(e.getShape(id), whiteboardId);
//checks to find any bindings assosiated with the selected shapes. //checks to find any bindings assosiated with the selected shapes.
//If any, they need to be updated as well. //If any, they need to be updated as well.
const pageBindings = rDocument?.current?.pages[e.getPage()?.id]?.bindings; const pageBindings = e.state.document.pages[e.getPage()?.id]?.bindings;
const boundShapes = []; const boundShapes = [];
if (pageBindings) { if (pageBindings) {
Object.entries(pageBindings).map(([k,b]) => { Object.entries(pageBindings).map(([k,b]) => {
if (b.toId.includes(id), whiteboardId) { if (b.toId.includes(id)) {
boundShapes.push(rDocument?.current?.pages[e.getPage()?.id]?.shapes[b.fromId]) boundShapes.push(e.state.document.pages[e.getPage()?.id]?.shapes[b.fromId])
} }
}) })
} }
//persist shape(s) that was updated by the client and any shapes bound to it. //persist shape(s) that was updated by the client and any shapes bound to it.
boundShapes.forEach(bs => persistShape(bs, whiteboardId)) boundShapes.forEach(bs => persistShape(bs, whiteboardId))
const children = e.getShape(id).children
//also persist children of the selected shape (grouped shapes)
children && children.forEach(c => persistShape(e.getShape(c), whiteboardId))
}); });
} }
if (s?.includes("session:complete:EraseSession") || s?.includes("delete")) { if (s?.includes("session:complete:EraseSession") || s?.includes("delete")) {
let shapesIdsToRemove = [] const pageShapes = e.state.document.pages[e.getPage()?.id]?.shapes;
shapes.forEach(s => { let shapesIdsToRemove = findRemoved(Object.keys(shapes), Object.keys(pageShapes))
const ids = e.shapes.map(ss => ss.id);
if (!ids.includes(s.id)) shapesIdsToRemove.push(s.id);
});
removeShapes(shapesIdsToRemove, whiteboardId) removeShapes(shapesIdsToRemove, whiteboardId)
} }
}} }}

View File

@ -18,7 +18,6 @@ export default withTracker(({ whiteboardId }) => {
const shapes = Service.getShapes(whiteboardId); const shapes = Service.getShapes(whiteboardId);
const assets = Service.getAssets(); const assets = Service.getAssets();
const curPres = Service.getCurrentPres(); const curPres = Service.getCurrentPres();
const curSlide = Service.getCurSlide();
return { return {
initDefaultPages: Service.initDefaultPages, initDefaultPages: Service.initDefaultPages,
@ -27,11 +26,11 @@ export default withTracker(({ whiteboardId }) => {
isMultiUserActive: Service.isMultiUserActive, isMultiUserActive: Service.isMultiUserActive,
hasMultiUserAccess: Service.hasMultiUserAccess, hasMultiUserAccess: Service.hasMultiUserAccess,
changeCurrentSlide: Service.changeCurrentSlide, changeCurrentSlide: Service.changeCurrentSlide,
curSlide,
shapes: shapes, shapes: shapes,
assets: assets, assets: assets,
curPres, curPres,
removeShapes: Service.removeShapes, removeShapes: Service.removeShapes,
zoomSlide: PresentationToolbarService.zoomSlide, zoomSlide: PresentationToolbarService.zoomSlide,
skipToSlide: PresentationToolbarService.skipToSlide,
}; };
})(WhiteboardContainer); })(WhiteboardContainer);

View File

@ -1,12 +1,10 @@
import Cursor from '/imports/ui/components/cursor/service'; import Cursor, { publishCursorUpdate } from '/imports/ui/components/cursor/service';
import Users from '/imports/api/users'; import Users from '/imports/api/users';
import { publishCursorUpdate } from '/imports/ui/components/cursor/service';
const getCurrentCursors = (whiteboardId) => { const getCurrentCursors = (whiteboardId) => {
const selector = { whiteboardId }; const selector = { whiteboardId };
const filter = {}; const filter = {};
const cursors = Cursor.find(selector, filter).fetch(); const cursors = Cursor.find(selector, filter).fetch();
//console.log('CURSORS!!!!!!!!! : ',cursors);
return cursors.map(cursor => { return cursors.map(cursor => {
const { userId } = cursor; const { userId } = cursor;
const user = Users.findOne({ userId }, { fields: { name: 1, presenter: 1, userId: 1, role: 1 } }); const user = Users.findOne({ userId }, { fields: { name: 1, presenter: 1, userId: 1, role: 1 } });

View File

@ -1,6 +1,5 @@
import Users from '/imports/api/users'; import Users from '/imports/api/users';
import Captions from "/imports/api/captions"; import Captions from "/imports/api/captions";
import Meetings from "/imports/api/meetings";
import Auth from '/imports/ui/services/auth'; import Auth from '/imports/ui/services/auth';
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user'; import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user';
import addAnnotationQuery from '/imports/api/annotations/addAnnotation'; import addAnnotationQuery from '/imports/api/annotations/addAnnotation';
@ -8,7 +7,6 @@ import { Slides } from '/imports/api/slides';
import { makeCall } from '/imports/ui/services/api'; import { makeCall } from '/imports/ui/services/api';
import PresentationService from '/imports/ui/components/presentation/service'; import PresentationService from '/imports/ui/components/presentation/service';
import logger from '/imports/startup/client/logger'; import logger from '/imports/startup/client/logger';
import { isEqual } from 'lodash';
const Annotations = new Mongo.Collection(null); const Annotations = new Mongo.Collection(null);
@ -17,7 +15,6 @@ const ANNOTATION_CONFIG = Meteor.settings.public.whiteboard.annotations;
const DRAW_START = ANNOTATION_CONFIG.status.start; const DRAW_START = ANNOTATION_CONFIG.status.start;
const DRAW_UPDATE = ANNOTATION_CONFIG.status.update; const DRAW_UPDATE = ANNOTATION_CONFIG.status.update;
const DRAW_END = ANNOTATION_CONFIG.status.end; const DRAW_END = ANNOTATION_CONFIG.status.end;
const ANNOTATION_TYPE_PENCIL = "pencil";
let annotationsStreamListener = null; let annotationsStreamListener = null;
@ -30,63 +27,6 @@ function clearFakeAnnotations() {
Annotations.remove({ id: /-fake/g }); Annotations.remove({ id: /-fake/g });
} }
function handleAddedLiveSyncPreviewAnnotation({
meetingId, whiteboardId, userId, annotation,
}) {
const isOwn = Auth.meetingID === meetingId && Auth.userID === userId;
const query = addAnnotationQuery(meetingId, whiteboardId, userId, annotation);
if (!isOwn) {
Annotations.upsert(query.selector, query.modifier);
return;
}
const fakeAnnotation = Annotations.findOne({ id: `${annotation.id}-fake` });
let fakePoints;
if (fakeAnnotation) {
fakePoints = fakeAnnotation.annotationInfo.points;
const { points: lastPoints } = annotation.annotationInfo;
if (annotation.annotationType !== 'pencil') {
Annotations.update(fakeAnnotation._id, {
$set: {
position: annotation.position,
'annotationInfo.color': isEqual(fakePoints, lastPoints) || annotation.status === DRAW_END
? annotation.annotationInfo.color : fakeAnnotation.annotationInfo.color,
},
$inc: { version: 1 }, // TODO: Remove all this version stuff
});
return;
}
}
Annotations.upsert(query.selector, query.modifier, (err) => {
if (err) {
logger.error({
logCode: 'whiteboard_annotation_upsert_error',
extraInfo: { error: err },
}, 'Error on adding an annotation');
return;
}
// Remove fake annotation for pencil on draw end
if (annotation.status === DRAW_END) {
Annotations.remove({ id: `${annotation.id}-fake` });
return;
}
if (annotation.status === DRAW_START) {
Annotations.update(fakeAnnotation._id, {
$set: {
position: annotation.position - 1,
},
$inc: { version: 1 }, // TODO: Remove all this version stuff
});
}
});
}
function handleAddedAnnotation({ function handleAddedAnnotation({
meetingId, meetingId,
whiteboardId, whiteboardId,
@ -156,20 +96,8 @@ export function initAnnotationsStreamListener() {
annotationsStreamListener.on("removed", handleRemovedAnnotation); annotationsStreamListener.on("removed", handleRemovedAnnotation);
// <<<<<<< HEAD
// annotationsStreamListener.on('added', ({ annotations }) => {
// annotations.forEach((annotation) => {
// const tool = annotation.annotation.annotationType;
// if (tool === ANNOTATION_TYPE_TEXT) {
// handleAddedLiveSyncPreviewAnnotation(annotation);
// } else {
// handleAddedAnnotation(annotation);
// }
// });
// =======
annotationsStreamListener.on("added", ({ annotations }) => { annotationsStreamListener.on("added", ({ annotations }) => {
annotations.forEach((annotation) => handleAddedAnnotation(annotation)); annotations.forEach((annotation) => handleAddedAnnotation(annotation));
// >>>>>>> embed Tldraw into BBB client
}); });
}); });
} }
@ -364,7 +292,7 @@ const persistShape = (shape, whiteboardId) => {
id: shape.id, id: shape.id,
annotationInfo: shape, annotationInfo: shape,
wbId: whiteboardId, wbId: whiteboardId,
userId: Auth.userID, userId: shape.userId ? shape.userId : Auth.userID,
}; };
sendAnnotation(annotation); sendAnnotation(annotation);
@ -384,11 +312,16 @@ const getShapes = (whiteboardId) => {
whiteboardId, whiteboardId,
}, },
{ {
fields: { annotationInfo: 1, }, fields: { annotationInfo: 1, userId: 1, },
}, },
).fetch(); ).fetch();
let result = annotations.map(a => a.annotationInfo); let result = {};
annotations.forEach((annotation) => {
annotation.annotationInfo.userId = annotation.userId;
result[annotation.annotationInfo.id] = annotation.annotationInfo;
});
return result; return result;
}; };
@ -397,11 +330,6 @@ const getCurrentPres = () => {
return PresentationService.getCurrentPresentation(podId); return PresentationService.getCurrentPresentation(podId);
} }
const getCurSlide = () => {
let m = Meetings.findOne({ meetingId: Auth.meetingID });
return m;
}
const getAssets = () => { const getAssets = () => {
// temporary storage for assets // temporary storage for assets
let a = Captions.find().fetch().filter(s => s.src); let a = Captions.find().fetch().filter(s => s.src);

View File

@ -6325,6 +6325,11 @@
"object-assign": "^4.1.1" "object-assign": "^4.1.1"
} }
}, },
"sdp": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.0.3.tgz",
"integrity": "sha512-8EkfckS+XZQaPLyChu4ey7PghrdcraCVNpJe2Gfdi2ON1ylQ7OasuKX+b37R9slnRChwIAiQgt+oj8xXGD8x+A=="
},
"sdp-transform": { "sdp-transform": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.7.0.tgz", "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.7.0.tgz",
@ -7019,6 +7024,14 @@
"resolved": "https://registry.npmjs.org/wasm-check/-/wasm-check-2.0.3.tgz", "resolved": "https://registry.npmjs.org/wasm-check/-/wasm-check-2.0.3.tgz",
"integrity": "sha512-UbZqpDMO4TZskoVKDH3B9NqY+yJllDJX8I9lUU4nuQjBGeU57jCjjgCslP3r8xiE+yf5GTIfeGvznvubgCdbhw==" "integrity": "sha512-UbZqpDMO4TZskoVKDH3B9NqY+yJllDJX8I9lUU4nuQjBGeU57jCjjgCslP3r8xiE+yf5GTIfeGvznvubgCdbhw=="
}, },
"webrtc-adapter": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.1.1.tgz",
"integrity": "sha512-1yXevP7TeZGmklEXkvQVrZp3fOSJlLeXNGCA7NovQokxgP3/e2T3EVGL0eKU87S9vKppWjvRWqnJeSANEspOBg==",
"requires": {
"sdp": "^3.0.2"
}
},
"which": { "which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -88,6 +88,7 @@
"tippy.js": "^5.1.3", "tippy.js": "^5.1.3",
"use-context-selector": "^1.3.7", "use-context-selector": "^1.3.7",
"wasm-check": "^2.0.3", "wasm-check": "^2.0.3",
"webrtc-adapter": "^8.1.1",
"winston": "^3.7.2", "winston": "^3.7.2",
"yaml": "^1.7.2" "yaml": "^1.7.2"
}, },

File diff suppressed because it is too large Load Diff