Browse Source

Remove more lodash functions and made some JSDoc improvements

JC Brand 1 year ago
parent
commit
a977eff441

+ 2 - 3
src/headless/plugins/chat/model.js

@@ -1,6 +1,5 @@
 import ModelWithContact from './model-with-contact.js';
 import isMatch from "lodash-es/isMatch";
-import isObject from "lodash-es/isObject";
 import log from '../../log.js';
 import pick from "lodash-es/pick";
 import { Model } from '@converse/skeletor/src/model.js';
@@ -349,7 +348,7 @@ const ChatBox = ModelWithContact.extend({
         if (!attrs.jid) {
             return 'Ignored ChatBox without JID';
         }
-        const room_jids = api.settings.get('auto_join_rooms').map(s => isObject(s) ? s.jid : s);
+        const room_jids = api.settings.get('auto_join_rooms').map(s => (s instanceof Object) ? s.jid : s);
         const auto_join = api.settings.get('auto_join_private_chats').concat(room_jids);
         if (api.settings.get("singleton") && !auto_join.includes(attrs.jid) && !api.settings.get('auto_join_on_invite')) {
             const msg = `${attrs.jid} is not allowed because singleton is true and it's not being auto_joined`;
@@ -601,7 +600,7 @@ const ChatBox = ModelWithContact.extend({
      * passed in attributes map.
      * @private
      * @method _converse.ChatBox#getDuplicateMessage
-     * @param { object } attrs - Attributes representing a received
+     * @param {object} attrs - Attributes representing a received
      *  message, as returned by {@link parseMessage}
      * @returns {Promise<_converse.Message>}
      */

+ 2 - 3
src/headless/plugins/disco/api.js

@@ -1,4 +1,3 @@
-import isObject from "lodash-es/isObject";
 import log from "../../log.js";
 import { _converse, api, converse } from "@converse/headless";
 import { getOpenPromise } from '@converse/openpromise';
@@ -277,7 +276,7 @@ export default {
                     ...api.disco.entities.items(jid).map(i => i.getFeature(feature))
                 ];
                 const result = await Promise.all(promises);
-                return result.filter(isObject);
+                return result.filter(f => (f instanceof Object));
             },
 
             /**
@@ -311,7 +310,7 @@ export default {
                 }
 
                 const result = await Promise.all(api.disco.entities.items(jid).map(i => i.getFeature(feature)));
-                return result.map(isObject).includes(true);
+                return result.map(f => (f instanceof Object)).includes(true);
             }
         },
 

+ 5 - 7
src/headless/plugins/muc/muc.js

@@ -1,5 +1,4 @@
 import debounce from 'lodash-es/debounce';
-import isElement from 'lodash-es/isElement';
 import log from '../../log';
 import p from '../../utils/parse-helpers';
 import pick from 'lodash-es/pick';
@@ -1901,14 +1900,13 @@ const ChatRoomMixin = {
     /**
      * Determines whether the message is from ourselves by checking
      * the `from` attribute. Doesn't check the `type` attribute.
-     * @private
      * @method _converse.ChatRoom#isOwnMessage
-     * @param { Object|Element|_converse.Message } msg
-     * @returns { boolean }
+     * @param {Object|Element|_converse.Message} msg
+     * @returns {boolean}
      */
     isOwnMessage (msg) {
         let from;
-        if (isElement(msg)) {
+        if (msg instanceof Element) {
             from = msg.getAttribute('from');
         } else if (msg instanceof _converse.Message) {
             from = msg.get('from');
@@ -2042,9 +2040,9 @@ const ChatRoomMixin = {
      * Handles message moderation based on the passed in attributes.
      * @private
      * @method _converse.ChatRoom#handleModeration
-     * @param { object } attrs - Attributes representing a received
+     * @param {object} attrs - Attributes representing a received
      *  message, as returned by {@link parseMUCMessage}
-     * @returns { Boolean } Returns `true` or `false` depending on
+     * @returns {Promise<boolean>} Returns `true` or `false` depending on
      *  whether a message was moderated or not.
      */
     async handleModeration (attrs) {

+ 1 - 2
src/headless/plugins/muc/utils.js

@@ -1,4 +1,3 @@
-import isObject from 'lodash-es/isObject';
 import { ROLES } from './constants.js';
 import { _converse, api, converse, log } from '@converse/headless';
 import { safeSave } from '@converse/headless/utils/core.js';
@@ -163,7 +162,7 @@ export async function autoJoinRooms () {
                     return Promise.resolve();
                 }
                 return api.rooms.open(muc);
-            } else if (isObject(muc)) {
+            } else if (muc instanceof Object) {
                 return api.rooms.open(muc.jid, { ...muc });
             } else {
                 log.error('Invalid muc criteria specified for "auto_join_rooms"');

+ 1 - 2
src/headless/plugins/status/status.js

@@ -1,4 +1,3 @@
-import isObject from 'lodash-es/isObject';
 import { Model } from '@converse/skeletor/src/model.js';
 import { _converse, api, converse } from '@converse/headless';
 
@@ -12,7 +11,7 @@ export default class XMPPStatus extends Model {
 
     initialize () {
         this.on('change', item => {
-            if (!isObject(item.changed)) {
+            if (!(item.changed instanceof Object)) {
                 return;
             }
             if ('status' in item.changed || 'status_message' in item.changed) {

+ 16 - 18
src/headless/shared/settings/api.js

@@ -1,4 +1,3 @@
-import isObject from 'lodash-es/isObject';
 import log from '@converse/headless/log.js';
 import {
     clearUserSettings,
@@ -28,10 +27,10 @@ export const settings_api = {
      * called will *not* change the initialization settings provided via
      * `converse.initialize`.
      *
-     * @method _converse.api.settings.extend
+     * @method api.settings.extend
      * @param { object } settings The configuration settings
      * @example
-     * _converse.api.settings.extend({
+     * api.settings.extend({
      *    'enable_foo': true
      * });
      *
@@ -56,7 +55,7 @@ export const settings_api = {
     /**
      * @method _converse.api.settings.get
      * @returns {*} Value of the particular configuration setting.
-     * @example _converse.api.settings.get("play_sounds");
+     * @example api.settings.get("play_sounds");
      */
     get (key) {
         return getAppSetting(key);
@@ -74,9 +73,9 @@ export const settings_api = {
      *  An object containing configuration settings.
      *  Alternatively to passing in an object, you can pass in a key and a value.
      * @param { string } [value]
-     * @example _converse.api.settings.set("play_sounds", true);
+     * @example api.settings.set("play_sounds", true);
      * @example
-     * _converse.api.settings.set({
+     * api.settings.set({
      *     "play_sounds": true,
      *     "hide_offline_users": true
      * });
@@ -101,7 +100,7 @@ export const settings_api = {
          * @param { Function } handler - The event handler function
          * @param { Object } [context] - The context of the `this` attribute of the
          *  handler function.
-         * @example _converse.api.settings.listen.on('change', callback);
+         * @example api.settings.listen.on('change', callback);
          */
         on (name, handler, context) {
             registerListener(name, handler, context);
@@ -112,7 +111,7 @@ export const settings_api = {
          * @method _converse.api.settings.listen.not
          * @param { String } name The event's name
          * @param { Function } handler The callback method that is to no longer be called when the event fires
-         * @example _converse.api.settings.listen.not('change', callback);
+         * @example api.settings.listen.not('change', callback);
          */
         not (name, handler) {
             unregisterListener(name, handler);
@@ -134,7 +133,7 @@ export const user_settings_api = {
      * @async
      * @method _converse.api.user.settings.getModel
      * @returns {Promise<Model>}
-     * @example const settings = await _converse.api.user.settings.getModel();
+     * @example const settings = await api.user.settings.getModel();
      */
     getModel () {
         return getUserSettings();
@@ -143,10 +142,10 @@ export const user_settings_api = {
     /**
      * Get the value of a particular user setting.
      * @method _converse.api.user.settings.get
-     * @param { String } key - The setting name
+     * @param {string} key - The setting name
      * @param {*} [fallback] - An optional fallback value if the user setting is undefined
      * @returns {Promise} Promise which resolves with the value of the particular configuration setting.
-     * @example _converse.api.user.settings.get("foo");
+     * @example api.user.settings.get("foo");
      */
     async get (key, fallback) {
         const user_settings = await getUserSettings();
@@ -157,18 +156,17 @@ export const user_settings_api = {
      * Set one or many user settings.
      * @async
      * @method _converse.api.user.settings.set
-     * @param { Object } [settings] An object containing configuration settings.
-     * @param { string } [key] Alternatively to passing in an object, you can pass in a key and a value.
-     * @param { string } [value]
-     * @example _converse.api.user.settings.set("foo", "bar");
+     * @param {Object|string} key An object containing config settings or alternatively a string key
+     * @param {string} [val] The value, if the previous parameter is a key
+     * @example api.user.settings.set("foo", "bar");
      * @example
-     * _converse.api.user.settings.set({
+     * api.user.settings.set({
      *     "foo": "bar",
      *     "baz": "buz"
      * });
      */
     set (key, val) {
-        if (isObject(key)) {
+        if (key instanceof Object) {
             return updateUserSettings(key, {'promise': true});
         } else {
             const o = {};
@@ -180,7 +178,7 @@ export const user_settings_api = {
     /**
      * Clears all the user settings
      * @async
-     * @method _converse.api.user.settings.clear
+     * @method api.user.settings.clear
      */
     clear () {
         return clearUserSettings();

+ 18 - 7
src/headless/shared/settings/utils.js

@@ -1,7 +1,5 @@
 import { _converse } from '@converse/headless';
-import assignIn from 'lodash-es/assignIn';
 import isEqual from "lodash-es/isEqual.js";
-import isObject from 'lodash-es/isObject';
 import log from '@converse/headless/log';
 import pick from 'lodash-es/pick';
 import u from '@converse/headless/utils/core';
@@ -26,7 +24,7 @@ export function initAppSettings (settings) {
 
     // Allow only whitelisted settings to be overwritten via converse.initialize
     const allowed_settings = pick(settings, Object.keys(DEFAULT_SETTINGS));
-    assignIn(app_settings, DEFAULT_SETTINGS, allowed_settings);
+    Object.assign(app_settings, DEFAULT_SETTINGS, allowed_settings);
 }
 
 export function getInitSettings () {
@@ -43,32 +41,45 @@ export function extendAppSettings (settings) {
     u.merge(DEFAULT_SETTINGS, settings);
     // When updating the settings, we need to avoid overwriting the
     // initialization_settings (i.e. the settings passed in via converse.initialize).
-    const allowed_keys = Object.keys(pick(settings,Object.keys(DEFAULT_SETTINGS)));
+    const allowed_keys = Object.keys(settings).filter(k => k in DEFAULT_SETTINGS);
     const allowed_site_settings = pick(init_settings, allowed_keys);
-    const updated_settings = assignIn(pick(settings, allowed_keys), allowed_site_settings);
+    const updated_settings = Object.assign(pick(settings, allowed_keys), allowed_site_settings);
     u.merge(app_settings, updated_settings);
 }
 
+/**
+ * @param {string} name
+ * @param {Function} func
+ * @param {any} context
+ */
 export function registerListener (name, func, context) {
     app_settings.on(name, func, context)
 }
 
+/**
+ * @param {string} name
+ * @param {Function} func
+ */
 export function unregisterListener (name, func) {
     app_settings.off(name, func);
 }
 
+/**
+ * @param {Object|string} key An object containing config settings or alternatively a string key
+ * @param {string} [val] The value, if the previous parameter is a key
+ */
 export function updateAppSettings (key, val) {
     if (key == null) return this; // eslint-disable-line no-eq-null
 
     let attrs;
-    if (isObject(key)) {
+    if (key instanceof Object) {
         attrs = key;
     } else if (typeof key === 'string') {
         attrs = {};
         attrs[key] = val;
     }
 
-    const allowed_keys = Object.keys(pick(attrs, Object.keys(DEFAULT_SETTINGS)));
+    const allowed_keys = Object.keys(attrs).filter(k => k in DEFAULT_SETTINGS);
     const changed = {};
     allowed_keys.forEach(k => {
         const val = attrs[k];

+ 60 - 44
src/headless/utils/core.js

@@ -5,7 +5,6 @@
  */
 import DOMPurify from 'dompurify';
 import _converse from '@converse/headless/shared/_converse.js';
-import isObject from "lodash-es/isObject";
 import log from '../log.js';
 import sizzle from "sizzle";
 import { Model } from '@converse/skeletor/src/model.js';
@@ -257,15 +256,15 @@ u.isServiceUnavailableError = function (stanza) {
 /**
  * Merge the second object into the first one.
  * @method u#merge
- * @param { Object } dst
- * @param { Object } src
+ * @param {Object} dst
+ * @param {Object} src
  */
 export function merge (dst, src) {
     for (const k in src) {
         if (!Object.prototype.hasOwnProperty.call(src, k)) continue;
         if (k === "__proto__" || k === "constructor") continue;
 
-        if (isObject(dst[k])) {
+        if (dst[k] instanceof Object) {
             merge(dst[k], src[k]);
         } else {
             dst[k] = src[k];
@@ -273,60 +272,57 @@ export function merge (dst, src) {
     }
 }
 
-u.getOuterWidth = function (el, include_margin=false) {
+/**
+ * @param {HTMLElement} el
+ * @param {boolean} include_margin
+ */
+function getOuterWidth (el, include_margin=false) {
     let width = el.offsetWidth;
     if (!include_margin) {
         return width;
     }
     const style = window.getComputedStyle(el);
-    width += parseInt(style.marginLeft ? style.marginLeft : 0, 10) +
-             parseInt(style.marginRight ? style.marginRight : 0, 10);
+    width += parseInt(style.marginLeft ? style.marginLeft : '0', 10) +
+             parseInt(style.marginRight ? style.marginRight : '0', 10);
     return width;
-};
+}
 
 /**
  * Converts an HTML string into a DOM element.
  * Expects that the HTML string has only one top-level element,
  * i.e. not multiple ones.
- * @private
  * @method u#stringToElement
- * @param { String } s - The HTML string
+ * @param {string} s - The HTML string
  */
-u.stringToElement = function (s) {
+function stringToElement (s) {
     var div = document.createElement('div');
     div.innerHTML = s;
     return div.firstElementChild;
-};
+}
 
 /**
  * Checks whether the DOM element matches the given selector.
- * @private
  * @method u#matchesSelector
- * @param { Element } el - The DOM element
- * @param { String } selector - The selector
+ * @param {HTMLElement} el - The DOM element
+ * @param {string} selector - The selector
  */
-u.matchesSelector = function (el, selector) {
+function matchesSelector (el, selector) {
     const match = (
         el.matches ||
-        el.matchesSelector ||
-        el.msMatchesSelector ||
-        el.mozMatchesSelector ||
-        el.webkitMatchesSelector ||
-        el.oMatchesSelector
+        el.webkitMatchesSelector
     );
     return match ? match.call(el, selector) : false;
-};
+}
 
 /**
  * Returns a list of children of the DOM element that match the selector.
- * @private
  * @method u#queryChildren
- * @param { Element } el - the DOM element
- * @param { String } selector - the selector they should be matched against
+ * @param {HTMLElement} el - the DOM element
+ * @param {string} selector - the selector they should be matched against
  */
-u.queryChildren = function (el, selector) {
+function queryChildren  (el, selector) {
     return Array.from(el.childNodes).filter(el => u.matchesSelector(el, selector));
-};
+}
 
 u.contains = function (attr, query) {
     const checker = (item, key) => item.get(key).toLowerCase().includes(query.toLowerCase());
@@ -429,7 +425,6 @@ export function safeSave (model, attributes, options) {
     }
 }
 
-u.safeSave = safeSave;
 
 u.siblingIndex = function (el) {
     /* eslint-disable no-cond-assign */
@@ -440,14 +435,14 @@ u.siblingIndex = function (el) {
 /**
  * Returns the current word being written in the input element
  * @method u#getCurrentWord
- * @param { HTMLElement } input - The HTMLElement in which text is being entered
- * @param { number } [index] - An optional rightmost boundary index. If given, the text
+ * @param {HTMLInputElement} input - The HTMLElement in which text is being entered
+ * @param {number} [index] - An optional rightmost boundary index. If given, the text
  *  value of the input element will only be considered up until this index.
- * @param { string } [delineator] - An optional string delineator to
+ * @param {string} [delineator] - An optional string delineator to
  *  differentiate between words.
  * @private
  */
-u.getCurrentWord = function (input, index, delineator) {
+function getCurrentWord (input, index, delineator) {
     if (!index) {
         index = input.selectionEnd || undefined;
     }
@@ -456,7 +451,7 @@ u.getCurrentWord = function (input, index, delineator) {
         [word] = word.split(delineator).slice(-1);
     }
     return word;
-};
+}
 
 u.isMentionBoundary = (s) => s !== '@' && RegExp(`(\\p{Z}|\\p{P})`, 'u').test(s);
 
@@ -470,17 +465,27 @@ u.replaceCurrentWord = function (input, new_value) {
     input.selectionEnd = mention_boundary ? selection_end + 1 : selection_end;
 };
 
-u.triggerEvent = function (el, name, type="Event", bubbles=true, cancelable=true) {
+/**
+ * @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;
 }
 
-u.placeCaretAtEnd = function (textarea) {
+/**
+ * @param {HTMLTextAreaElement} textarea
+ */
+function placeCaretAtEnd (textarea) {
     if (textarea !== document.activeElement) {
         textarea.focus();
     }
@@ -490,9 +495,13 @@ u.placeCaretAtEnd = function (textarea) {
     setTimeout(() => textarea.setSelectionRange(len, len), 1);
     // Scroll to the bottom, in case we're in a tall textarea
     // (Necessary for Firefox and Chrome)
-    this.scrollTop = 999999;
-};
+    textarea.scrollTop = 999999;
+}
 
+/**
+ * @param {string} suffix
+ * @return {string}
+ */
 export function getUniqueId (suffix) {
     const uuid = crypto.randomUUID?.() ??
         'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
@@ -511,9 +520,8 @@ export function getUniqueId (suffix) {
 /**
  * Clears the specified timeout and interval.
  * @method u#clearTimers
- * @param { number } timeout - Id if the timeout to clear.
- * @param { number } interval - Id of the interval to clear.
- * @private
+ * @param {ReturnType<typeof setTimeout>} timeout - Id if the timeout to clear.
+ * @param {ReturnType<typeof setInterval>} interval - Id of the interval to clear.
  * @copyright Simen Bekkhus 2016
  * @license MIT
  */
@@ -654,17 +662,25 @@ export function saveWindowState (ev) {
 
 
 export default Object.assign({
-    shouldClearCache,
-    waitUntil, // TODO: remove. Only the API should be used
-    isErrorObject,
+    getCurrentWord,
+    getOuterWidth,
     getRandomInt,
     getUniqueId,
     isElement,
     isEmptyMessage,
+    isErrorObject,
     isValidJID,
+    matchesSelector,
     merge,
+    placeCaretAtEnd,
     prefixMentions,
+    queryChildren,
+    safeSave,
     saveWindowState,
+    shouldClearCache,
+    stringToElement,
     stx,
     toStanza,
+    triggerEvent,
+    waitUntil, // TODO: remove. Only the API should be used
 }, u);

+ 3 - 2
src/plugins/omemo/store.js

@@ -1,6 +1,5 @@
 /* global libsignal */
 import range from 'lodash-es/range';
-import omit from 'lodash-es/omit';
 import { Model } from '@converse/skeletor/src/model.js';
 import { generateDeviceID } from './utils.js';
 import { _converse, api, converse, log } from '@converse/headless';
@@ -92,7 +91,9 @@ class OMEMOStore extends Model {
     }
 
     removePreKey (key_id) {
-        this.save('prekeys', omit(this.getPreKeys(), key_id));
+        const prekeys = { ...this.getPreKeys() };
+        delete prekeys[key_id];
+        this.save('prekeys', prekeys);
         return Promise.resolve();
     }