converse.js
Version:
Browser based XMPP chat client
161 lines (148 loc) • 4.28 kB
JavaScript
/**
* @copyright The Converse.js contributors
* @license Mozilla Public License (MPLv2)
* @description This is the core utilities module.
*/
import { Model } from '@converse/skeletor';
import log, { LEVELS } from '@converse/log';
import * as array from './array.js';
import * as arraybuffer from './arraybuffer.js';
import * as color from './color.js';
import * as form from './form.js';
import * as html from './html.js';
import * as init from './init.js';
import * as jid from './jid';
import * as object from './object.js';
import * as promise from './promise.js';
import * as session from './session.js';
import * as stanza from './stanza.js';
import * as storage from './storage.js';
import * as text from './text.js';
import * as url from './url.js';
/**
* @typedef {Record<string, Function>} CommonUtils
* @typedef {Record<'muc'|'mam', CommonUtils>} PluginUtils
*
* The utils object
* @namespace u
* @type {CommonUtils & PluginUtils}
*/
const u = {
muc: null,
mam: null,
};
/**
* @param {Event} [event]
*/
export function setLogLevelFromRoute (event) {
if (location.hash.startsWith('#converse?loglevel=')) {
event?.preventDefault();
const level = location.hash.split('=').pop();
if (Object.keys(LEVELS).includes(level)) {
log.setLogLevel(/** @type {keyof LEVELS} */(level));
} else {
log.error(`Could not set loglevel of ${level}`);
}
}
}
export function isEmptyMessage (attrs) {
if (attrs instanceof Model) {
attrs = attrs.attributes;
}
return !attrs['oob_url'] &&
!attrs['file'] &&
!(attrs['is_encrypted'] && attrs['plaintext']) &&
!attrs['message'] &&
!attrs['body'];
}
/**
* Given a message object, return its text with @ chars
* inserted before the mentioned nicknames.
* @param {import('../shared/message').default} message
*/
export function prefixMentions (message) {
let text = message.getMessageText();
(message.get('references') || [])
.sort((a, b) => b.begin - a.begin)
.forEach(ref => {
text = `${text.slice(0, ref.begin)}@${text.slice(ref.begin)}`
});
return text;
}
function shouldCreateMessage (attrs) {
return attrs['retracted'] || // Retraction received *before* the message
!isEmptyMessage(attrs);
}
/**
* Call the callback once all the events have been triggered
* @param { Array } events: An array of objects, with keys `object` and
* `event`, representing the event name and the object it's triggered upon.
* @param { Function } callback: The function to call once all events have
* been triggered.
*/
function onMultipleEvents (events=[], callback) {
let triggered = [];
function handler (result) {
triggered.push(result)
if (events.length === triggered.length) {
callback(triggered);
triggered = [];
}
}
events.forEach(e => e.object.on(e.event, handler));
}
/**
* @param {Element} el
* @param {string} name
* @param {string} [type]
* @param {boolean} [bubbles]
* @param {boolean} [cancelable]
*/
function triggerEvent (el, name, type="Event", bubbles=true, cancelable=true) {
const evt = document.createEvent(type);
evt.initEvent(name, bubbles, cancelable);
el.dispatchEvent(evt);
}
export function getRandomInt (max) {
return (Math.random() * max) | 0;
}
/**
* @param {string} [suffix]
* @return {string}
*/
export function getUniqueId (suffix) {
const uuid = crypto.randomUUID?.() ??
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = getRandomInt(16);
const v = c === 'x' ? r : r & 0x3 | 0x8;
return v.toString(16);
});
if (typeof(suffix) === "string" || typeof(suffix) === "number") {
return uuid + ":" + suffix;
} else {
return uuid;
}
}
export default Object.assign({
...array,
...arraybuffer,
...color,
...form,
...html,
...init,
...jid,
...object,
...promise,
...session,
...stanza,
...storage,
...text,
...url,
getRandomInt,
getUniqueId,
isEmptyMessage,
onMultipleEvents,
prefixMentions,
shouldCreateMessage,
triggerEvent,
}, u);