Handling and publishing multi-user mode switch
This commit is contained in:
parent
b207a1275e
commit
fa1458c3eb
1
bigbluebutton-html5/imports/api/2.0/whiteboard-multi-user/index.js
Executable file
1
bigbluebutton-html5/imports/api/2.0/whiteboard-multi-user/index.js
Executable file
@ -0,0 +1 @@
|
|||||||
|
export default new Mongo.Collection('whiteboard-multi-user');
|
@ -0,0 +1,7 @@
|
|||||||
|
import RedisPubSub from '/imports/startup/server/redis2x';
|
||||||
|
import handleGetWhiteboardAccess from './handlers/getWhiteboardAccess';
|
||||||
|
import handleModifyWhiteboardAccess from './handlers/modifyWhiteboardAccess';
|
||||||
|
|
||||||
|
RedisPubSub.on('GetWhiteboardAccessRespMsg', handleGetWhiteboardAccess);
|
||||||
|
RedisPubSub.on('SyncGetWhiteboardAccessRespMsg', handleGetWhiteboardAccess);
|
||||||
|
RedisPubSub.on('ModifyWhiteboardAccessEvtMsg', handleModifyWhiteboardAccess);
|
@ -0,0 +1,37 @@
|
|||||||
|
import { check } from 'meteor/check';
|
||||||
|
import Logger from '/imports/startup/server/logger';
|
||||||
|
import WhiteboardMultiUser from '/imports/api/2.0/whiteboard-multi-user/';
|
||||||
|
|
||||||
|
export default function handleGetWhiteboardAccess({ body }, meetingId) {
|
||||||
|
const { multiUser } = body;
|
||||||
|
|
||||||
|
check(multiUser, Boolean);
|
||||||
|
check(meetingId, String);
|
||||||
|
|
||||||
|
const selector = {
|
||||||
|
meetingId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const modifier = {
|
||||||
|
$set: {
|
||||||
|
meetingId,
|
||||||
|
multiUser,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const cb = (err, numChanged) => {
|
||||||
|
if (err) {
|
||||||
|
return Logger.error(`Error while adding an entry to Multi-User collection: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { insertedId } = numChanged;
|
||||||
|
if (insertedId) {
|
||||||
|
return Logger.info(`Added multiUser flag to the meetingId=${meetingId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Logger.info(`Upserted multiUser flag into meetingId=${meetingId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return WhiteboardMultiUser.upsert(selector, modifier, cb);
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
import { check } from 'meteor/check';
|
||||||
|
import Logger from '/imports/startup/server/logger';
|
||||||
|
import WhiteboardMultiUser from '/imports/api/2.0/whiteboard-multi-user/';
|
||||||
|
|
||||||
|
export default function handleModifyWhiteboardAccess({ body }, meetingId) {
|
||||||
|
const { multiUser } = body;
|
||||||
|
|
||||||
|
check(multiUser, Boolean);
|
||||||
|
check(meetingId, String);
|
||||||
|
|
||||||
|
const selector = {
|
||||||
|
meetingId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const modifier = {
|
||||||
|
$set: {
|
||||||
|
meetingId,
|
||||||
|
multiUser,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const cb = (err, numChanged) => {
|
||||||
|
if (err) {
|
||||||
|
return Logger.error(`Error while adding an entry to Multi-User collection: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { insertedId } = numChanged;
|
||||||
|
if (insertedId) {
|
||||||
|
return Logger.info(`Added multiUser flag to the meetingId=${meetingId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Logger.info(`Upserted multiUser flag into meetingId=${meetingId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return WhiteboardMultiUser.upsert(selector, modifier, cb);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
import './eventHandlers';
|
||||||
|
import './methods';
|
||||||
|
import './publishers';
|
@ -0,0 +1,7 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import mapToAcl from '/imports/startup/mapToAcl';
|
||||||
|
import changeWhiteboardAccess from './methods/changeWhiteboardAccess';
|
||||||
|
|
||||||
|
Meteor.methods(mapToAcl(['methods.modifyWhiteboardAccess'], {
|
||||||
|
changeWhiteboardAccess,
|
||||||
|
}));
|
@ -0,0 +1,28 @@
|
|||||||
|
import RedisPubSub from '/imports/startup/server/redis2x';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { check } from 'meteor/check';
|
||||||
|
|
||||||
|
export default function changeWhiteboardAccess(credentials, multiUser) {
|
||||||
|
const REDIS_CONFIG = Meteor.settings.redis;
|
||||||
|
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||||
|
const EVENT_NAME = 'ModifyWhiteboardAccessPubMsg';
|
||||||
|
|
||||||
|
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||||
|
|
||||||
|
check(meetingId, String);
|
||||||
|
check(requesterUserId, String);
|
||||||
|
check(requesterToken, String);
|
||||||
|
check(multiUser, Boolean);
|
||||||
|
|
||||||
|
const header = {
|
||||||
|
name: EVENT_NAME,
|
||||||
|
userId: requesterUserId,
|
||||||
|
meetingId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
multiUser,
|
||||||
|
};
|
||||||
|
|
||||||
|
return RedisPubSub.publish(CHANNEL, EVENT_NAME, meetingId, payload, header);
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import WhiteboardMultiUser from '/imports/api/2.0/whiteboard-multi-user/';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { check } from 'meteor/check';
|
||||||
|
import Logger from '/imports/startup/server/logger';
|
||||||
|
import mapToAcl from '/imports/startup/mapToAcl';
|
||||||
|
|
||||||
|
function whiteboardMultiUser(credentials) {
|
||||||
|
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||||
|
|
||||||
|
check(meetingId, String);
|
||||||
|
|
||||||
|
Logger.info(`Publishing whiteboard-multi-user for ${meetingId} ${requesterUserId} ${requesterToken}`);
|
||||||
|
|
||||||
|
return WhiteboardMultiUser.find({ meetingId });
|
||||||
|
}
|
||||||
|
|
||||||
|
function publish(...args) {
|
||||||
|
const boundMultiUser = whiteboardMultiUser.bind(this);
|
||||||
|
return mapToAcl('subscriptions.whiteboard-multi-user', boundMultiUser)(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
Meteor.publish('whiteboard-multi-user', publish);
|
@ -89,7 +89,7 @@ Base.defaultProps = defaultProps;
|
|||||||
const SUBSCRIPTIONS_NAME = [
|
const SUBSCRIPTIONS_NAME = [
|
||||||
'users2x', 'users', 'chat', 'chat2x', 'cursor', 'cursor2x', 'screenshare', 'meetings', 'meetings2x',
|
'users2x', 'users', 'chat', 'chat2x', 'cursor', 'cursor2x', 'screenshare', 'meetings', 'meetings2x',
|
||||||
'polls', 'polls2x', 'presentations', 'presentations2x', 'shapes', 'shapes2x', 'slides', 'slides2x', 'captions',
|
'polls', 'polls2x', 'presentations', 'presentations2x', 'shapes', 'shapes2x', 'slides', 'slides2x', 'captions',
|
||||||
'captions2x', 'breakouts', 'breakouts2x', 'voiceUsers',
|
'captions2x', 'breakouts', 'breakouts2x', 'voiceUsers', 'whiteboard-multi-user',
|
||||||
];
|
];
|
||||||
|
|
||||||
const BaseContainer = createContainer(({ params }) => {
|
const BaseContainer = createContainer(({ params }) => {
|
||||||
|
@ -1,19 +1,26 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import styles from './styles.scss';
|
|
||||||
import Button from '/imports/ui/components/button/component';
|
|
||||||
import cx from 'classnames';
|
|
||||||
import { findDOMNode } from 'react-dom';
|
import { findDOMNode } from 'react-dom';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import cx from 'classnames';
|
||||||
|
import Button from '/imports/ui/components/button/component';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
|
||||||
export default class WhiteboardToolbar extends Component {
|
export default class WhiteboardToolbar extends Component {
|
||||||
|
|
||||||
|
static HEXToINTColor(hexColor) {
|
||||||
|
const _rrggbb = hexColor.slice(1);
|
||||||
|
const rrggbb = _rrggbb.substr(0, 2) + _rrggbb.substr(2, 2) + _rrggbb.substr(4, 2);
|
||||||
|
return parseInt(rrggbb, 16);
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
//a variable to control which list is currently open
|
// a variable to control which list is currently open
|
||||||
currentSubmenuOpen: '',
|
currentSubmenuOpen: '',
|
||||||
|
|
||||||
//variables to keep current selected draw settings
|
// variables to keep current selected draw settings
|
||||||
annotationSelected: {
|
annotationSelected: {
|
||||||
icon: 'hand',
|
icon: 'hand',
|
||||||
sessionValue: 'Hand',
|
sessionValue: 'Hand',
|
||||||
@ -25,14 +32,14 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
colorSelected: '#000000',
|
colorSelected: '#000000',
|
||||||
fontSizeSelected: 18,
|
fontSizeSelected: 18,
|
||||||
|
|
||||||
//keeping the previous color and the thickness icon's radius selected for svg animation
|
// keeping the previous color and the thickness icon's radius selected for svg animation
|
||||||
prevColorSelected: '#000000',
|
prevColorSelected: '#000000',
|
||||||
prevIconRadius: 4,
|
prevIconRadius: 4,
|
||||||
|
|
||||||
//lists of tools/thickness/colors are not direct children of main toolbar buttons
|
// lists of tools/thickness/colors are not direct children of main toolbar buttons
|
||||||
//and we want the list to close when onBlur fires at the main toolbar button
|
// and we want the list to close when onBlur fires at the main toolbar button
|
||||||
//(click anywhere on the screen) thus we have to control the blur manually by disabling it
|
// (click anywhere on the screen) thus we have to control the blur manually by disabling it
|
||||||
//when you hover over the buttons in the list and enabling when the mouse leaves the list
|
// when you hover over the buttons in the list and enabling when the mouse leaves the list
|
||||||
onBlurEnabled: true,
|
onBlurEnabled: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,6 +47,7 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
this.closeSubMenu = this.closeSubMenu.bind(this);
|
this.closeSubMenu = this.closeSubMenu.bind(this);
|
||||||
this.handleUndo = this.handleUndo.bind(this);
|
this.handleUndo = this.handleUndo.bind(this);
|
||||||
this.handleClearAll = this.handleClearAll.bind(this);
|
this.handleClearAll = this.handleClearAll.bind(this);
|
||||||
|
this.handleSwitchWhiteboardMode = this.handleSwitchWhiteboardMode.bind(this);
|
||||||
this.handleAnnotationChange = this.handleAnnotationChange.bind(this);
|
this.handleAnnotationChange = this.handleAnnotationChange.bind(this);
|
||||||
this.handleThicknessChange = this.handleThicknessChange.bind(this);
|
this.handleThicknessChange = this.handleThicknessChange.bind(this);
|
||||||
this.handleFontSizeChange = this.handleFontSizeChange.bind(this);
|
this.handleFontSizeChange = this.handleFontSizeChange.bind(this);
|
||||||
@ -49,13 +57,12 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
// setting default or resetting current drawing settings in the session
|
||||||
//setting default or resetting current drawing settings in the session
|
|
||||||
const { annotationSelected, thicknessSelected, colorSelected, fontSizeSelected } = this.state;
|
const { annotationSelected, thicknessSelected, colorSelected, fontSizeSelected } = this.state;
|
||||||
this.props.actions.setWhiteboardToolbarValues(
|
this.props.actions.setWhiteboardToolbarValues(
|
||||||
annotationSelected.sessionValue,
|
annotationSelected.sessionValue,
|
||||||
thicknessSelected.sessionRadius,
|
thicknessSelected.sessionRadius,
|
||||||
this.HEXToINTColor(colorSelected),
|
WhiteboardToolbar.HEXToINTColor(colorSelected),
|
||||||
fontSizeSelected,
|
fontSizeSelected,
|
||||||
{
|
{
|
||||||
textShapeValue: '',
|
textShapeValue: '',
|
||||||
@ -65,27 +72,27 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
//to let the whiteboard know that the presentation area's size has changed
|
// to let the whiteboard know that the presentation area's size has changed
|
||||||
window.dispatchEvent(new Event('resize'));
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
|
||||||
if(this.state.annotationSelected.sessionValue != "Text") {
|
if (this.state.annotationSelected.sessionValue !== 'Text') {
|
||||||
//trigger initial animation on the thickness circle, otherwise it stays at 0
|
// trigger initial animation on the thickness circle, otherwise it stays at 0
|
||||||
var node = findDOMNode(this.thicknessListIconRadius);
|
const node = findDOMNode(this.thicknessListIconRadius);
|
||||||
node.beginElement();
|
node.beginElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
//to let the whiteboard know that the presentation area's size has changed
|
|
||||||
window.dispatchEvent(new Event('resize'));
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
// if color or thickness were changed
|
// if color or thickness were changed
|
||||||
// we might need to trigger svg animation for Color and Thickness icons
|
// we might need to trigger svg animation for Color and Thickness icons
|
||||||
this.animateSvgIcons(prevState);
|
this.animateSvgIcons(prevState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
// to let the whiteboard know that the presentation area's size has changed
|
||||||
|
window.dispatchEvent(new Event('resize'));
|
||||||
|
}
|
||||||
|
|
||||||
animateSvgIcons(prevState) {
|
animateSvgIcons(prevState) {
|
||||||
/* Animation for the svg icons that we use for thickness (circle) and color (rectangle)
|
/* Animation for the svg icons that we use for thickness (circle) and color (rectangle)
|
||||||
* has to be triggered manually
|
* has to be triggered manually
|
||||||
@ -100,9 +107,9 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// 1st case
|
// 1st case
|
||||||
if(this.state.colorSelected != prevState.colorSelected) {
|
if (this.state.colorSelected !== prevState.colorSelected) {
|
||||||
// 1st case a)
|
// 1st case a)
|
||||||
if(this.state.annotationSelected.sessionValue == "Text") {
|
if (this.state.annotationSelected.sessionValue === 'Text') {
|
||||||
const node = findDOMNode(this.colorListIconColor);
|
const node = findDOMNode(this.colorListIconColor);
|
||||||
node.beginElement();
|
node.beginElement();
|
||||||
// 1st case b)
|
// 1st case b)
|
||||||
@ -113,14 +120,12 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
node2.beginElement();
|
node2.beginElement();
|
||||||
}
|
}
|
||||||
// 2nd case
|
// 2nd case
|
||||||
} else if(this.state.thicknessSelected.iconRadius != prevState.thicknessSelected.iconRadius) {
|
} else if (this.state.thicknessSelected.iconRadius !== prevState.thicknessSelected.iconRadius) {
|
||||||
const node = findDOMNode(this.thicknessListIconRadius);
|
const node = findDOMNode(this.thicknessListIconRadius);
|
||||||
node.beginElement();
|
node.beginElement();
|
||||||
}
|
|
||||||
|
|
||||||
// 3rd case
|
// 3rd case
|
||||||
else if(this.state.annotationSelected.sessionValue != "Text" &&
|
} else if (this.state.annotationSelected.sessionValue !== 'Text' &&
|
||||||
prevState.annotationSelected.sessionValue == "Text") {
|
prevState.annotationSelected.sessionValue === 'Text') {
|
||||||
const node = findDOMNode(this.thicknessListIconRadius);
|
const node = findDOMNode(this.thicknessListIconRadius);
|
||||||
const node2 = findDOMNode(this.thicknessListIconColor);
|
const node2 = findDOMNode(this.thicknessListIconColor);
|
||||||
node.beginElement();
|
node.beginElement();
|
||||||
@ -130,42 +135,44 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
// 4th case, initial animation (just thickness) is triggered in componentDidMount
|
// 4th case, initial animation (just thickness) is triggered in componentDidMount
|
||||||
}
|
}
|
||||||
|
|
||||||
//open a submenu
|
// open a submenu
|
||||||
displaySubMenu(listName) {
|
displaySubMenu(listName) {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentSubmenuOpen: this.state.currentSubmenuOpen == listName ? '' : listName,
|
currentSubmenuOpen: this.state.currentSubmenuOpen === listName ? '' : listName,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//close a current submenu (fires onBlur only, when you click anywhere on the screen)
|
// close a current submenu (fires onBlur only, when you click anywhere on the screen)
|
||||||
closeSubMenu() {
|
closeSubMenu() {
|
||||||
|
|
||||||
// a separate case for the active text shape
|
// a separate case for the active text shape
|
||||||
if(this.state.annotationSelected.sessionValue == "Text" && this.props.textShapeActiveId != '') {
|
if (this.state.annotationSelected.sessionValue === 'Text' && this.props.textShapeActiveId !== '') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.state.onBlurEnabled) {
|
if (this.state.onBlurEnabled) {
|
||||||
this.setState({
|
this.setState({
|
||||||
currentSubmenuOpen: undefined,
|
currentSubmenuOpen: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//undo annotation
|
// undo annotation
|
||||||
handleUndo() {
|
handleUndo() {
|
||||||
this.props.actions.undoAnnotation(this.props.whiteboardId);
|
this.props.actions.undoAnnotation(this.props.whiteboardId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear all annotations
|
// clear all annotations
|
||||||
handleClearAll() {
|
handleClearAll() {
|
||||||
this.props.actions.clearWhiteboard(this.props.whiteboardId);
|
this.props.actions.clearWhiteboard(this.props.whiteboardId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//changes a current selected annotation both in the state and in the session
|
handleSwitchWhiteboardMode() {
|
||||||
//and closes the annotation list
|
this.props.actions.changeWhiteboardMode(!this.props.multiUser);
|
||||||
handleAnnotationChange(annotation) {
|
}
|
||||||
|
|
||||||
|
// changes a current selected annotation both in the state and in the session
|
||||||
|
// and closes the annotation list
|
||||||
|
handleAnnotationChange(annotation) {
|
||||||
const obj = {
|
const obj = {
|
||||||
annotationSelected: annotation,
|
annotationSelected: annotation,
|
||||||
onBlurEnabled: true,
|
onBlurEnabled: true,
|
||||||
@ -173,7 +180,7 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// to animate thickness icon properly when you switch the tool back from Text
|
// to animate thickness icon properly when you switch the tool back from Text
|
||||||
if(annotation.sessionValue == "Text") {
|
if (annotation.sessionValue === 'Text') {
|
||||||
obj.prevIconRadius = 0;
|
obj.prevIconRadius = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +188,8 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
this.setState(obj);
|
this.setState(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
//changes a current selected thickness both in the state and in the session
|
// changes a current selected thickness both in the state and in the session
|
||||||
//and closes the thickness list
|
// and closes the thickness list
|
||||||
handleThicknessChange(thicknessObj) {
|
handleThicknessChange(thicknessObj) {
|
||||||
this.props.actions.setThickness(thicknessObj.sessionRadius);
|
this.props.actions.setThickness(thicknessObj.sessionRadius);
|
||||||
|
|
||||||
@ -204,10 +211,10 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//changes a current selected color both in the state and in the session
|
// changes a current selected color both in the state and in the session
|
||||||
//and closes the color list
|
// and closes the color list
|
||||||
handleColorChange(color) {
|
handleColorChange(color) {
|
||||||
this.props.actions.setColor(this.HEXToINTColor(color));
|
this.props.actions.setColor(WhiteboardToolbar.HEXToINTColor(color));
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
prevColorSelected: this.state.colorSelected,
|
prevColorSelected: this.state.colorSelected,
|
||||||
@ -217,20 +224,14 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
HEXToINTColor(hexColor) {
|
// disabling onBlur flag when mouse is over the items in the lists
|
||||||
var _rrggbb = hexColor.slice(1);
|
|
||||||
var rrggbb = _rrggbb.substr(0, 2) + _rrggbb.substr(2, 2) + _rrggbb.substr(4, 2);
|
|
||||||
return parseInt(rrggbb, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
//disabling onBlur flag when mouse is over the items in the lists
|
|
||||||
disableOnBlur() {
|
disableOnBlur() {
|
||||||
this.setState({
|
this.setState({
|
||||||
onBlurEnabled: false,
|
onBlurEnabled: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//enabling the onBlur flag when the mouse leaving the lists
|
// enabling the onBlur flag when the mouse leaving the lists
|
||||||
enableOnBlur() {
|
enableOnBlur() {
|
||||||
this.setState({
|
this.setState({
|
||||||
onBlurEnabled: true,
|
onBlurEnabled: true,
|
||||||
@ -238,150 +239,158 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderAnnotationList() {
|
renderAnnotationList() {
|
||||||
|
const { annotations } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.annotationList, styles.toolbarList)}>
|
<div className={cx(styles.annotationList, styles.toolbarList)}>
|
||||||
{ this.props.annotations? this.props.annotations.map((annotation, index) =>
|
{ annotations ? annotations.map(annotation =>
|
||||||
<Button
|
(<Button
|
||||||
label="Annotation"
|
label="Annotation"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
color={'default'}
|
color={'default'}
|
||||||
icon={annotation.icon}
|
icon={annotation.icon}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
className={cx(styles.toolbarListButton, this.state.annotationSelected.sessionValue == annotation.sessionRadius ? styles.selectedListButton : '')}
|
className={cx(styles.toolbarListButton, this.state.annotationSelected.sessionValue === annotation.sessionValue ? styles.selectedListButton : '')}
|
||||||
onClick={this.handleAnnotationChange.bind(null, annotation)}
|
onClick={this.handleAnnotationChange.bind(null, annotation)}
|
||||||
onMouseEnter={this.disableOnBlur}
|
onMouseEnter={this.disableOnBlur}
|
||||||
onMouseLeave={this.enableOnBlur}
|
onMouseLeave={this.enableOnBlur}
|
||||||
key={index}
|
key={annotation.sessionValue}
|
||||||
role="button"
|
role="button"
|
||||||
/>
|
/>),
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderFontSizeList() {
|
renderFontSizeList() {
|
||||||
|
const { fontSizes } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.fontSizeList, styles.toolbarList)}>
|
<div className={cx(styles.fontSizeList, styles.toolbarList)}>
|
||||||
{this.props.fontSizes ? this.props.fontSizes.map((fontSizeObj, index) =>
|
{fontSizes ? fontSizes.map(fontSizeObj =>
|
||||||
<Button
|
(<Button
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
label="Radius"
|
label="Radius"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
className={cx(styles.toolbarListButton, styles.fontSizeListButton, this.state.fontSizeSelected == fontSizeObj.fontSize ? styles.selectedListButton : '')}
|
className={cx(styles.toolbarListButton, styles.fontSizeListButton, this.state.fontSizeSelected === fontSizeObj.fontSize ? styles.selectedListButton : '')}
|
||||||
onClick={this.handleFontSizeChange.bind(null, fontSizeObj)}
|
onClick={this.handleFontSizeChange.bind(null, fontSizeObj)}
|
||||||
onMouseEnter={this.disableOnBlur}
|
onMouseEnter={this.disableOnBlur}
|
||||||
onMouseLeave={this.enableOnBlur}
|
onMouseLeave={this.enableOnBlur}
|
||||||
key={index}
|
key={fontSizeObj.fontSize}
|
||||||
customIcon={
|
customIcon={
|
||||||
<p className={styles.textThickness} style={{fontSize: fontSizeObj.fontSize}}>
|
<p className={styles.textThickness} style={{ fontSize: fontSizeObj.fontSize }}>
|
||||||
Aa
|
Aa
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
>
|
/>),
|
||||||
</Button>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderThicknessList() {
|
renderThicknessList() {
|
||||||
|
const { thicknessRadiuses } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.thicknessList, styles.toolbarList)}>
|
<div className={cx(styles.thicknessList, styles.toolbarList)}>
|
||||||
{this.props.thicknessRadiuses ? this.props.thicknessRadiuses.map((thicknessObj, index) =>
|
{thicknessRadiuses ? thicknessRadiuses.map(thicknessObj =>
|
||||||
<Button
|
(<Button
|
||||||
label="Radius"
|
label="Radius"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
color={'default'}
|
color={'default'}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
className={cx(styles.toolbarListButton, this.state.thicknessSelected.sessionRadius == thicknessObj.sessionRadius ? styles.selectedListButton : '')}
|
className={cx(styles.toolbarListButton, this.state.thicknessSelected.sessionRadius === thicknessObj.sessionRadius ? styles.selectedListButton : '')}
|
||||||
onClick={this.handleThicknessChange.bind(null, thicknessObj)}
|
onClick={this.handleThicknessChange.bind(null, thicknessObj)}
|
||||||
onMouseEnter={this.disableOnBlur}
|
onMouseEnter={this.disableOnBlur}
|
||||||
onMouseLeave={this.enableOnBlur}
|
onMouseLeave={this.enableOnBlur}
|
||||||
customIcon={
|
customIcon={
|
||||||
<svg className={styles.customSvgIcon}>
|
<svg className={styles.customSvgIcon}>
|
||||||
<circle cx="50%" cy="50%" r={thicknessObj.iconRadius} fill="#F3F6F9"/>
|
<circle cx="50%" cy="50%" r={thicknessObj.iconRadius} fill="#F3F6F9" />
|
||||||
</svg>
|
</svg>
|
||||||
}
|
}
|
||||||
key={index}
|
key={thicknessObj.sessionRadius}
|
||||||
/>
|
/>),
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderColorList() {
|
renderColorList() {
|
||||||
|
const { colors } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.colorList, styles.toolbarList)}>
|
<div className={cx(styles.colorList, styles.toolbarList)}>
|
||||||
{this.props.colors ? this.props.colors.map((color) =>
|
{colors ? colors.map(color =>
|
||||||
<Button
|
(<Button
|
||||||
label="Color"
|
label="Color"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
color={'default'}
|
color={'default'}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
className={cx(styles.toolbarListButton, this.state.colorSelected == color ? styles.selectedListButton : '')}
|
className={cx(styles.toolbarListButton, this.state.colorSelected === color ? styles.selectedListButton : '')}
|
||||||
onClick={this.handleColorChange.bind(null, color)}
|
onClick={this.handleColorChange.bind(null, color)}
|
||||||
onMouseEnter={this.disableOnBlur}
|
onMouseEnter={this.disableOnBlur}
|
||||||
onMouseLeave={this.enableOnBlur}
|
onMouseLeave={this.enableOnBlur}
|
||||||
customIcon={
|
customIcon={
|
||||||
<svg className={styles.customSvgIcon}>
|
<svg className={styles.customSvgIcon}>
|
||||||
<rect x="20%" y="20%" width="60%" height="60%" fill={color}/>
|
<rect x="20%" y="20%" width="60%" height="60%" fill={color} />
|
||||||
</svg>
|
</svg>
|
||||||
}
|
}
|
||||||
key={color}
|
key={color}
|
||||||
role="button"
|
role="button"
|
||||||
aria-labelledby={`${color}Label`}
|
aria-labelledby={`${color}Label`}
|
||||||
aria-describedby={`${color}Descrip`}
|
aria-describedby={`${color}Descrip`}
|
||||||
/>
|
/>),
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.toolbarContainer} style={{height: this.props.height}}>
|
<div className={styles.toolbarContainer} style={{ height: this.props.height }}>
|
||||||
<div className={styles.toolbarWrapper}>
|
<div className={styles.toolbarWrapper}>
|
||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button
|
<Button
|
||||||
label="Tools"
|
label="Tools"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
role="button"
|
role="button"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
icon={this.state.annotationSelected.icon}
|
icon={this.state.annotationSelected.icon}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
onClick={this.displaySubMenu.bind(null, "annotationList")}
|
onClick={this.displaySubMenu.bind(null, 'annotationList')}
|
||||||
onBlur={this.closeSubMenu}
|
onBlur={this.closeSubMenu}
|
||||||
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen == "annotationList" ? '' : styles.notActive)}
|
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen === 'annotationList' ? '' : styles.notActive)}
|
||||||
/>
|
/>
|
||||||
{this.state.currentSubmenuOpen == "annotationList" ?
|
{this.state.currentSubmenuOpen === 'annotationList' ?
|
||||||
this.renderAnnotationList()
|
this.renderAnnotationList()
|
||||||
: null }
|
: null }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{this.state.annotationSelected.sessionValue == "Text" ?
|
{this.state.annotationSelected.sessionValue === 'Text' ?
|
||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button
|
<Button
|
||||||
label="Thickness List"
|
label="Thickness List"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
role="button"
|
role="button"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
onClick={this.displaySubMenu.bind(null, "fontSizeList")}
|
onClick={this.displaySubMenu.bind(null, 'fontSizeList')}
|
||||||
onBlur={this.closeSubMenu}
|
onBlur={this.closeSubMenu}
|
||||||
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen == "fontSizeList" ? '' : styles.notActive)}
|
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen === 'fontSizeList' ? '' : styles.notActive)}
|
||||||
customIcon={
|
customIcon={
|
||||||
<p className={styles.textThickness} style={{fontSize: this.state.fontSizeSelected, color: this.state.colorSelected}}>
|
<p
|
||||||
|
className={styles.textThickness}
|
||||||
|
style={{
|
||||||
|
fontSize: this.state.fontSizeSelected,
|
||||||
|
color: this.state.colorSelected,
|
||||||
|
}}
|
||||||
|
>
|
||||||
Aa
|
Aa
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{this.state.currentSubmenuOpen == "fontSizeList" ?
|
{this.state.currentSubmenuOpen === 'fontSizeList' ?
|
||||||
this.renderFontSizeList()
|
this.renderFontSizeList()
|
||||||
: null }
|
: null }
|
||||||
</div>
|
</div>
|
||||||
@ -389,13 +398,13 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button
|
<Button
|
||||||
label="Thickness List"
|
label="Thickness List"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
role="button"
|
role="button"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
onClick={this.displaySubMenu.bind(null, "thicknessList")}
|
onClick={this.displaySubMenu.bind(null, 'thicknessList')}
|
||||||
onBlur={this.closeSubMenu}
|
onBlur={this.closeSubMenu}
|
||||||
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen == "thicknessList" ? '' : styles.notActive)}
|
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen === 'thicknessList' ? '' : styles.notActive)}
|
||||||
customIcon={
|
customIcon={
|
||||||
<svg className={styles.customSvgIcon} shapeRendering="geometricPrecision">
|
<svg className={styles.customSvgIcon} shapeRendering="geometricPrecision">
|
||||||
<circle
|
<circle
|
||||||
@ -431,7 +440,7 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
</svg>
|
</svg>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{this.state.currentSubmenuOpen == "thicknessList" ?
|
{this.state.currentSubmenuOpen === 'thicknessList' ?
|
||||||
this.renderThicknessList()
|
this.renderThicknessList()
|
||||||
: null }
|
: null }
|
||||||
</div>
|
</div>
|
||||||
@ -439,13 +448,13 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button
|
<Button
|
||||||
label="Color List"
|
label="Color List"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
role="button"
|
role="button"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
size={'md'}
|
size={'md'}
|
||||||
onClick={this.displaySubMenu.bind(null, "colorList")}
|
onClick={this.displaySubMenu.bind(null, 'colorList')}
|
||||||
onBlur={this.closeSubMenu}
|
onBlur={this.closeSubMenu}
|
||||||
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen == "colorList" ? '' : styles.notActive)}
|
className={cx(styles.toolbarButton, this.state.currentSubmenuOpen === 'colorList' ? '' : styles.notActive)}
|
||||||
customIcon={
|
customIcon={
|
||||||
<svg className={styles.customSvgIcon}>
|
<svg className={styles.customSvgIcon}>
|
||||||
<rect x="25%" y="25%" width="50%" height="50%" stroke="black" strokeWidth="1">
|
<rect x="25%" y="25%" width="50%" height="50%" stroke="black" strokeWidth="1">
|
||||||
@ -464,14 +473,14 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
</svg>
|
</svg>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{this.state.currentSubmenuOpen == "colorList" ?
|
{this.state.currentSubmenuOpen === 'colorList' ?
|
||||||
this.renderColorList()
|
this.renderColorList()
|
||||||
: null }
|
: null }
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button
|
<Button
|
||||||
label="Undo Annotation"
|
label="Undo Annotation"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
role="button"
|
role="button"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
icon={'undo'}
|
icon={'undo'}
|
||||||
@ -483,7 +492,7 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
<div className={styles.buttonWrapper}>
|
<div className={styles.buttonWrapper}>
|
||||||
<Button
|
<Button
|
||||||
label="Clear All Annotations"
|
label="Clear All Annotations"
|
||||||
hideLabel={true}
|
hideLabel
|
||||||
role="button"
|
role="button"
|
||||||
color={'default'}
|
color={'default'}
|
||||||
icon={'circle_close'}
|
icon={'circle_close'}
|
||||||
@ -492,44 +501,89 @@ export default class WhiteboardToolbar extends Component {
|
|||||||
className={cx(styles.toolbarButton, styles.notActive)}
|
className={cx(styles.toolbarButton, styles.notActive)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{this.props.isPresenter ?
|
||||||
|
<div className={styles.buttonWrapper}>
|
||||||
|
<Button
|
||||||
|
label={this.props.multiUser ? 'Turn multi-user mode off' : 'Tuen multi-user mode on'}
|
||||||
|
hideLabel
|
||||||
|
role="button"
|
||||||
|
color={'default'}
|
||||||
|
icon={this.props.multiUser ? 'whiteboard' : 'multi_whiteboard'}
|
||||||
|
size={'md'}
|
||||||
|
onClick={this.handleSwitchWhiteboardMode}
|
||||||
|
className={cx(styles.toolbarButton, styles.notActive)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultProps = {
|
WhiteboardToolbar.defaultProps = {
|
||||||
colors: [
|
colors: [
|
||||||
'#000000', '#FFFFFF', '#FF0000', '#FF8800', '#CCFF00','#00FF00',
|
'#000000', '#FFFFFF', '#FF0000', '#FF8800', '#CCFF00', '#00FF00',
|
||||||
'#00FFFF', '#0088FF', '#0000FF', '#8800FF', '#FF00FF', '#C0C0C0'
|
'#00FFFF', '#0088FF', '#0000FF', '#8800FF', '#FF00FF', '#C0C0C0',
|
||||||
],
|
],
|
||||||
thicknessRadiuses: [
|
thicknessRadiuses: [
|
||||||
{iconRadius: 14, sessionRadius: 30},
|
{ iconRadius: 14, sessionRadius: 30 },
|
||||||
{iconRadius: 12, sessionRadius: 22},
|
{ iconRadius: 12, sessionRadius: 22 },
|
||||||
{iconRadius: 10, sessionRadius: 15},
|
{ iconRadius: 10, sessionRadius: 15 },
|
||||||
{iconRadius: 8, sessionRadius: 10},
|
{ iconRadius: 8, sessionRadius: 10 },
|
||||||
{iconRadius: 6, sessionRadius:6},
|
{ iconRadius: 6, sessionRadius: 6 },
|
||||||
{iconRadius: 4, sessionRadius: 3},
|
{ iconRadius: 4, sessionRadius: 3 },
|
||||||
{iconRadius: 2, sessionRadius: 1}
|
{ iconRadius: 2, sessionRadius: 1 },
|
||||||
],
|
],
|
||||||
annotations: [
|
annotations: [
|
||||||
{icon: 'text_tool', sessionValue: "Text"},
|
{ icon: 'text_tool', sessionValue: 'Text' },
|
||||||
{icon: 'linte_tool', sessionValue:"Line"},
|
{ icon: 'linte_tool', sessionValue: 'Line' },
|
||||||
{icon: 'circle_tool', sessionValue: "Ellipse"},
|
{ icon: 'circle_tool', sessionValue: 'Ellipse' },
|
||||||
{icon: 'triangle_tool', sessionValue: "Triangle"},
|
{ icon: 'triangle_tool', sessionValue: 'Triangle' },
|
||||||
{icon: 'rectangle_tool', sessionValue: "Rectangle"},
|
{ icon: 'rectangle_tool', sessionValue: 'Rectangle' },
|
||||||
{icon: 'pen_tool', sessionValue: "Pencil"},
|
{ icon: 'pen_tool', sessionValue: 'Pencil' },
|
||||||
{icon: 'hand', sessionValue: "Hand"}
|
{ icon: 'hand', sessionValue: 'Hand' },
|
||||||
],
|
],
|
||||||
fontSizes: [
|
fontSizes: [
|
||||||
{fontSize: 36},
|
{ fontSize: 36 },
|
||||||
{fontSize: 32},
|
{ fontSize: 32 },
|
||||||
{fontSize: 28},
|
{ fontSize: 28 },
|
||||||
{fontSize: 24},
|
{ fontSize: 24 },
|
||||||
{fontSize: 20},
|
{ fontSize: 20 },
|
||||||
{fontSize: 16},
|
{ fontSize: 16 },
|
||||||
{fontSize: 12},
|
{ fontSize: 12 },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
WhiteboardToolbar.defaultProps = defaultProps;
|
WhiteboardToolbar.propTypes = {
|
||||||
|
// defines a current mode of the whiteboard, multi/single user
|
||||||
|
multiUser: PropTypes.bool.isRequired,
|
||||||
|
|
||||||
|
// defines whether a current user is a presenter or not
|
||||||
|
isPresenter: PropTypes.bool.isRequired,
|
||||||
|
|
||||||
|
// defines an object of available actions
|
||||||
|
actions: PropTypes.objectOf(PropTypes.func).isRequired,
|
||||||
|
|
||||||
|
// defines the id of the active text shape (if any)
|
||||||
|
// for the separate onBlur case in the closeSubMenu()
|
||||||
|
textShapeActiveId: PropTypes.string.isRequired,
|
||||||
|
|
||||||
|
// defines a current whiteboard id
|
||||||
|
whiteboardId: PropTypes.string.isRequired,
|
||||||
|
|
||||||
|
// defines an array of icons for the toolbar as well as their corresponding session values
|
||||||
|
annotations: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|
||||||
|
// defines an array of font-sizes for the Font-size submenu of the text shape
|
||||||
|
fontSizes: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|
||||||
|
// defines an array of colors for the toolbar (color submenu)
|
||||||
|
colors: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
|
|
||||||
|
// defines an array of thickness values for the toolbar and their corresponding session values
|
||||||
|
thicknessRadiuses: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|
||||||
|
// defines the physical height of the whiteboard
|
||||||
|
height: PropTypes.number.isRequired,
|
||||||
|
};
|
||||||
|
@ -3,19 +3,13 @@ import { createContainer } from 'meteor/react-meteor-data';
|
|||||||
import WhiteboardToolbarService from './service';
|
import WhiteboardToolbarService from './service';
|
||||||
import WhiteboardToolbar from './component';
|
import WhiteboardToolbar from './component';
|
||||||
|
|
||||||
class WhiteboardToolbarContainer extends React.Component {
|
const WhiteboardToolbarContainer = ({ ...props }) => (
|
||||||
constructor(props) {
|
<WhiteboardToolbar {...props} />
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<WhiteboardToolbar {...this.props}/>
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default createContainer(() => ({
|
export default createContainer(() => ({
|
||||||
actions: WhiteboardToolbarService.actions,
|
actions: WhiteboardToolbarService.actions,
|
||||||
textShapeActiveId: WhiteboardToolbarService.getTextShapeActiveId(),
|
textShapeActiveId: WhiteboardToolbarService.getTextShapeActiveId(),
|
||||||
|
multiUser: WhiteboardToolbarService.getMultiUserStatus(),
|
||||||
|
isPresenter: WhiteboardToolbarService.isPresenter(),
|
||||||
}), WhiteboardToolbarContainer);
|
}), WhiteboardToolbarContainer);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { makeCall } from '/imports/ui/services/api';
|
import { makeCall } from '/imports/ui/services/api';
|
||||||
import Storage from '/imports/ui/services/storage/session';
|
import Storage from '/imports/ui/services/storage/session';
|
||||||
|
import Users from '/imports/api/2.0/users';
|
||||||
|
import Auth from '/imports/ui/services/auth';
|
||||||
|
import WhiteboardMultiUser from '/imports/api/2.0/whiteboard-multi-user/';
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
undoAnnotation: (whiteboardId) => {
|
undoAnnotation: (whiteboardId) => {
|
||||||
@ -11,53 +13,56 @@ const actions = {
|
|||||||
makeCall('clearWhiteboard', whiteboardId);
|
makeCall('clearWhiteboard', whiteboardId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
changeWhiteboardMode: (multiUser) => {
|
||||||
|
makeCall('changeWhiteboardAccess', multiUser);
|
||||||
|
},
|
||||||
|
|
||||||
setWhiteboardToolbarValues: (tool, thickness, color, fontSize, textShape) => {
|
setWhiteboardToolbarValues: (tool, thickness, color, fontSize, textShape) => {
|
||||||
let drawSettings = {
|
const drawSettings = {
|
||||||
whiteboardAnnotationTool: tool,
|
whiteboardAnnotationTool: tool,
|
||||||
whiteboardAnnotationThickness: thickness,
|
whiteboardAnnotationThickness: thickness,
|
||||||
whiteboardAnnotationColor: color,
|
whiteboardAnnotationColor: color,
|
||||||
textFontSize: fontSize,
|
textFontSize: fontSize,
|
||||||
textShape: textShape,
|
textShape,
|
||||||
};
|
};
|
||||||
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
||||||
},
|
},
|
||||||
|
|
||||||
setTool: (tool) => {
|
setTool: (tool) => {
|
||||||
let drawSettings = Storage.getItem('drawSettings');
|
const drawSettings = Storage.getItem('drawSettings');
|
||||||
if(drawSettings) {
|
if (drawSettings) {
|
||||||
drawSettings.whiteboardAnnotationTool = tool;
|
drawSettings.whiteboardAnnotationTool = tool;
|
||||||
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setThickness: (thickness) => {
|
setThickness: (thickness) => {
|
||||||
let drawSettings = Storage.getItem('drawSettings');
|
const drawSettings = Storage.getItem('drawSettings');
|
||||||
if(drawSettings) {
|
if (drawSettings) {
|
||||||
drawSettings.whiteboardAnnotationThickness = thickness;
|
drawSettings.whiteboardAnnotationThickness = thickness;
|
||||||
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setColor: (color) => {
|
setColor: (color) => {
|
||||||
let drawSettings = Storage.getItem('drawSettings');
|
const drawSettings = Storage.getItem('drawSettings');
|
||||||
if(drawSettings) {
|
if (drawSettings) {
|
||||||
drawSettings.whiteboardAnnotationColor = color;
|
drawSettings.whiteboardAnnotationColor = color;
|
||||||
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setFontSize: (fontSize) => {
|
setFontSize: (fontSize) => {
|
||||||
let drawSettings = Storage.getItem('drawSettings');
|
const drawSettings = Storage.getItem('drawSettings');
|
||||||
if(drawSettings) {
|
if (drawSettings) {
|
||||||
drawSettings.textFontSize = fontSize;
|
drawSettings.textFontSize = fontSize;
|
||||||
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setTextShapeObject: (textShape) => {
|
setTextShapeObject: (textShape) => {
|
||||||
let drawSettings = Storage.getItem('drawSettings');
|
const drawSettings = Storage.getItem('drawSettings');
|
||||||
if(drawSettings) {
|
if (drawSettings) {
|
||||||
drawSettings.textShape = textShape;
|
drawSettings.textShape = textShape;
|
||||||
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
Storage.setItem('drawSettings', JSON.stringify(drawSettings));
|
||||||
}
|
}
|
||||||
@ -65,13 +70,37 @@ const actions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getTextShapeActiveId = () => {
|
const getTextShapeActiveId = () => {
|
||||||
let drawSettings = Storage.getItem('drawSettings');
|
const drawSettings = Storage.getItem('drawSettings');
|
||||||
if(drawSettings) {
|
if (drawSettings) {
|
||||||
return drawSettings.textShape.textShapeActiveId;
|
return drawSettings.textShape.textShapeActiveId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMultiUserStatus = () => {
|
||||||
|
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID });
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
return data.multiUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPresenter = () => {
|
||||||
|
const currentUser = Users.findOne({ userId: Auth.userID });
|
||||||
|
|
||||||
|
if (currentUser && currentUser.user) {
|
||||||
|
return currentUser.user.presenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
actions,
|
actions,
|
||||||
getTextShapeActiveId,
|
getTextShapeActiveId,
|
||||||
|
getMultiUserStatus,
|
||||||
|
isPresenter,
|
||||||
};
|
};
|
||||||
|
@ -30,11 +30,6 @@ $number-of-vertical-main-toolbar-buttons: 5;
|
|||||||
|
|
||||||
.toolbarWrapper {
|
.toolbarWrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc((
|
|
||||||
#{$toolbar-button-height} +
|
|
||||||
#{$toolbar-button-margin-top} +
|
|
||||||
#{$toolbar-button-margin-bottom}) * #{$number-of-vertical-main-toolbar-buttons}
|
|
||||||
);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -13,6 +13,7 @@ acl:
|
|||||||
- 'captions'
|
- 'captions'
|
||||||
- 'breakouts'
|
- 'breakouts'
|
||||||
- 'voiceUsers'
|
- 'voiceUsers'
|
||||||
|
- 'whiteboard-multi-user'
|
||||||
methods:
|
methods:
|
||||||
- 'listenOnlyToggle'
|
- 'listenOnlyToggle'
|
||||||
- 'userLogout'
|
- 'userLogout'
|
||||||
@ -29,3 +30,4 @@ acl:
|
|||||||
methods:
|
methods:
|
||||||
- 'assignPresenter'
|
- 'assignPresenter'
|
||||||
- 'switchSlide'
|
- 'switchSlide'
|
||||||
|
- 'modifyWhiteboardAccess'
|
||||||
|
@ -24,6 +24,7 @@ import '/imports/api/2.0/breakouts/server';
|
|||||||
import '/imports/api/2.0/chat/server';
|
import '/imports/api/2.0/chat/server';
|
||||||
import '/imports/api/2.0/screenshare/server';
|
import '/imports/api/2.0/screenshare/server';
|
||||||
import '/imports/api/2.0/voice-users/server';
|
import '/imports/api/2.0/voice-users/server';
|
||||||
|
import '/imports/api/2.0/whiteboard-multi-user/server';
|
||||||
|
|
||||||
// Commons
|
// Commons
|
||||||
import '/imports/api/log-client/server';
|
import '/imports/api/log-client/server';
|
||||||
|
Loading…
Reference in New Issue
Block a user