jiti-meet/react/features/base/util/helpers.js

188 lines
4.4 KiB
JavaScript

// @flow
import clipboardCopy from 'clipboard-copy';
/**
* A helper function that behaves similar to Object.assign, but only reassigns a
* property in target if it's defined in source.
*
* @param {Object} target - The target object to assign the values into.
* @param {Object} source - The source object.
* @returns {Object}
*/
export function assignIfDefined(target: Object, source: Object) {
const to = Object(target);
for (const nextKey in source) {
if (source.hasOwnProperty(nextKey)) {
const value = source[nextKey];
if (typeof value !== 'undefined') {
to[nextKey] = value;
}
}
}
return to;
}
/**
* Tries to copy a given text to the clipboard.
* Returns true if the action succeeds.
*
* @param {string} textToCopy - Text to be copied.
* @returns {Promise<boolean>}
*/
export async function copyText(textToCopy: string) {
try {
await clipboardCopy(textToCopy);
return true;
} catch (e) {
return false;
}
}
/**
* Creates a deferred object.
*
* @returns {{promise, resolve, reject}}
*/
export function createDeferred(): Object {
const deferred = {};
deferred.promise = new Promise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}
const MATCH_OPERATOR_REGEXP = /[|\\{}()[\]^$+*?.-]/g;
/**
* Escape RegExp special characters.
*
* Based on https://github.com/sindresorhus/escape-string-regexp.
*
* @param {string} s - The regexp string to escape.
* @returns {string}
*/
export function escapeRegexp(s: string) {
if (typeof s !== 'string') {
throw new TypeError('Expected a string');
}
return s.replace(MATCH_OPERATOR_REGEXP, '\\$&');
}
/**
* Returns the base URL of the app.
*
* @param {Object} w - Window object to use instead of the built in one.
* @returns {string}
*/
export function getBaseUrl(w: Object = window) {
const doc = w.document;
const base = doc.querySelector('base');
if (base && base.href) {
return base.href;
}
const { protocol, host } = w.location;
return `${protocol}//${host}`;
}
/**
* Returns the namespace for all global variables, functions, etc that we need.
*
* @returns {Object} The namespace.
*
* NOTE: After React-ifying everything this should be the only global.
*/
export function getJitsiMeetGlobalNS() {
if (!window.JitsiMeetJS) {
window.JitsiMeetJS = {};
}
if (!window.JitsiMeetJS.app) {
window.JitsiMeetJS.app = {};
}
return window.JitsiMeetJS.app;
}
/**
* Prints the error and reports it to the global error handler.
*
* @param {Error} e - The error object.
* @param {string} msg - A custom message to print in addition to the error.
* @returns {void}
*/
export function reportError(e: Object, msg: string = '') {
console.error(msg, e);
window.onerror && window.onerror(msg, null, null, null, e);
}
/**
* Adds alpha to a color css string.
*
* @param {string} color - The color string either in rgb... Or #... Format.
* @param {number} opacity -The opacity(alpha) to apply to the color. Can take a value between 0 and 1, including.
* @returns {string} - The color with applied alpha.
*/
export function setColorAlpha(color: string, opacity: number) {
if (!color) {
return `rgba(0, 0, 0, ${opacity})`;
}
let b, g, r;
try {
if (color.startsWith('rgb')) {
[ r, g, b ] = color.split('(')[1].split(')')[0].split(',').map(c => c.trim());
} else if (color.startsWith('#')) {
if (color.length === 4) {
[ r, g, b ] = parseShorthandColor(color);
} else {
r = parseInt(color.substring(1, 3), 16);
g = parseInt(color.substring(3, 5), 16);
b = parseInt(color.substring(5, 7), 16);
}
} else {
return color;
}
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
} catch {
return color;
}
}
/**
* Gets the hexa rgb values for a shorthand css color.
*
* @param {string} color -
* @returns {Array<number>} - Array containing parsed r, g, b values of the color.
*/
function parseShorthandColor(color) {
let b, g, r;
r = color.substring(1, 2);
r += r;
r = parseInt(r, 16);
g = color.substring(2, 3);
g += g;
g = parseInt(g, 16);
b = color.substring(3, 4);
b += b;
b = parseInt(b, 16);
return [ r, g, b ];
}