bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/whiteboard/utils.js

167 lines
4.7 KiB
JavaScript
Raw Normal View History

import React from 'react';
const WHITEBOARD_CONFIG = Meteor.settings.public.whiteboard;
2023-06-06 04:02:06 +08:00
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
const usePrevious = (value) => {
const ref = React.useRef();
React.useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
};
const findRemoved = (A, B) => A.filter((a) => !B.includes(a));
const filterInvalidShapes = (shapes, curPageId, tldrawAPI) => {
const retShapes = shapes;
const keys = Object.keys(shapes);
const removedChildren = [];
const removedParents = [];
keys.forEach((shape) => {
if (shapes[shape].parentId !== curPageId) {
if (!keys.includes(shapes[shape].parentId)) {
delete retShapes[shape];
}
} else if (shapes[shape].type === 'group') {
const groupChildren = shapes[shape].children;
groupChildren.forEach((child) => {
if (!keys.includes(child)) {
removedChildren.push(child);
}
});
retShapes[shape].children = groupChildren.filter((child) => !removedChildren.includes(child));
if (shapes[shape].children.length < 2) {
removedParents.push(shape);
delete retShapes[shape];
}
}
});
// remove orphaned children
Object.keys(shapes).forEach((shape) => {
if (shapes[shape] && shapes[shape].parentId !== curPageId) {
if (removedParents.includes(shapes[shape].parentId)) {
delete retShapes[shape];
}
}
// remove orphaned bindings
if (shapes[shape] && shapes[shape].type === 'arrow'
&& (shapes[shape].handles.start.bindingId || shapes[shape].handles.end.bindingId)) {
const startBinding = shapes[shape].handles.start.bindingId;
const endBinding = shapes[shape].handles.end.bindingId;
const startBindingData = tldrawAPI?.getBinding(startBinding);
const endBindingData = tldrawAPI?.getBinding(endBinding);
if (startBinding && (!startBindingData && (
removedParents.includes(startBindingData?.fromId)
|| removedParents.includes(startBindingData?.toId)
|| !keys.includes(startBindingData?.fromId)
|| !keys.includes(startBindingData?.toId)
))) {
delete retShapes[shape].handles.start.bindingId;
}
if (endBinding && (!endBindingData && (
removedParents.includes(endBindingData?.fromId)
|| removedParents.includes(endBindingData?.toId)
|| !keys.includes(endBindingData?.fromId)
|| !keys.includes(endBindingData?.toId)
))) {
delete retShapes[shape].handles.end.bindingId;
}
}
});
return retShapes;
};
const isValidShapeType = (shape) => {
const invalidTypes = ['image', 'video'];
return !invalidTypes.includes(shape?.type);
};
// map different localeCodes from bbb to tldraw
const mapLanguage = (language) => {
// bbb has xx-xx but in tldraw it's only xx
if (['es', 'fa', 'it', 'pl', 'sv', 'uk'].some((lang) => language.startsWith(lang))) {
return language.substring(0, 2);
}
// exceptions
switch (language) {
case 'nb-no':
return 'no';
case 'zh-cn':
return 'zh-ch';
default:
return language;
}
};
2023-03-17 19:40:24 +08:00
/* getFontStyle adapted from tldraw source code
https://github.com/tldraw/tldraw/blob/55a8831a6b036faae0dfd77d6733a8f585f5ae23/packages/tldraw/src/state/shapes/shared/shape-styles.ts#L123 */
2023-03-17 02:55:56 +08:00
const getFontStyle = (style) => {
const fontSizes = {
small: 28,
medium: 48,
large: 96,
auto: 'auto',
};
const fontFaces = {
script: '"Caveat Brush"',
sans: '"Source Sans Pro"',
serif: '"Crimson Pro"',
mono: '"Source Code Pro"',
}
const fontSize = fontSizes[style.size];
const fontFace = fontFaces[style.font];
const { scale = 1 } = style;
return `${fontSize * scale}px/1 ${fontFace}`;
}
2023-03-17 19:40:24 +08:00
/* getMeasurementDiv and getTextSize adapted from tldraw source code
https://github.com/tldraw/tldraw/blob/55a8831a6b036faae0dfd77d6733a8f585f5ae23/packages/tldraw/src/state/shapes/shared/getTextSize.ts */
2023-03-17 02:55:56 +08:00
const getMeasurementDiv = (font) => {
// A div used for measurement
2023-03-18 01:51:39 +08:00
const pre = document.getElementById('text-measure');
pre.style.font = font;
2023-03-17 02:55:56 +08:00
return pre;
}
const getTextSize = (text, style, padding) => {
const font = getFontStyle(style);
if (!text) {
return [16, 32];
}
const melm = getMeasurementDiv(font);
2023-03-18 01:51:39 +08:00
melm.textContent = text;
2023-03-17 02:55:56 +08:00
if (!melm) {
// We're in SSR
return [10, 10];
}
// In tests, offsetWidth and offsetHeight will be 0
const width = melm.offsetWidth || 1;
const height = melm.offsetHeight || 1;
return [width + padding, height + padding];
};
const Utils = {
2024-01-23 22:31:39 +08:00
usePrevious, findRemoved, filterInvalidShapes, mapLanguage, getTextSize,
};
export default Utils;
export {
2024-01-23 22:31:39 +08:00
usePrevious, findRemoved, filterInvalidShapes, mapLanguage, getTextSize,
};