JC Brand 2 月之前
父節點
當前提交
187cd63873

+ 53 - 48
src/headless/plugins/chat/model.js

@@ -3,10 +3,10 @@ import { PRIVATE_CHAT_TYPE, INACTIVE } from '../../shared/constants.js';
 import _converse from '../../shared/_converse.js';
 import api from '../../shared/api/index.js';
 import converse from '../../shared/api/public.js';
-import log from "@converse/log";
+import log from '@converse/log';
 import { isUniView } from '../../utils/session.js';
 import { sendChatState, sendMarker } from '../../shared/actions.js';
-import ModelWithMessages from "../../shared/model-with-messages.js";
+import ModelWithMessages from '../../shared/model-with-messages.js';
 import ModelWithVCard from '../../shared/model-with-vcard';
 import ModelWithContact from '../../shared/model-with-contact.js';
 import ColorAwareModel from '../../shared/color.js';
@@ -14,7 +14,6 @@ import ChatBoxBase from '../../shared/chatbox.js';
 
 const { Strophe, u } = converse.env;
 
-
 /**
  * Represents a one-on-one chat conversation.
  */
@@ -26,24 +25,24 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
      * @typedef {import('../../shared/errors').StanzaParseError} StanzaParseError
      */
 
-    defaults () {
+    defaults() {
         return {
             bookmarked: false,
             hidden: isUniView() && !api.settings.get('singleton'),
             message_type: 'chat',
             num_unread: 0,
-            time_opened: this.get('time_opened') || (new Date()).getTime(),
-            time_sent: (new Date(0)).toISOString(),
+            time_opened: this.get('time_opened') || new Date().getTime(),
+            time_sent: new Date(0).toISOString(),
             type: PRIVATE_CHAT_TYPE,
-        }
+        };
     }
 
-    constructor (attrs, options) {
+    constructor(attrs, options) {
         super(attrs, options);
         this.disable_mam = false;
     }
 
-    async initialize () {
+    async initialize() {
         super.initialize();
         this.initialized = getOpenPromise();
 
@@ -54,7 +53,7 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
         this.presence.on('change:show', (item) => this.onPresenceChanged(item));
 
         this.on('change:chat_state', () => sendChatState(this.get('jid'), this.get('chat_state')));
-        this.on('change:hidden', () => (this.get('hidden') && this.setChatState(INACTIVE)));
+        this.on('change:hidden', () => this.get('hidden') && this.setChatState(INACTIVE));
 
         await this.fetchMessages();
         /**
@@ -63,28 +62,28 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
          * @type { ChatBox}
          * @example _converse.api.listen.on('chatBoxInitialized', model => { ... });
          */
-        await api.trigger('chatBoxInitialized', this, {synchronous: true});
+        await api.trigger('chatBoxInitialized', this, { synchronous: true });
         this.initialized.resolve();
     }
 
-
     /**
      * @param {MessageAttributes|StanzaParseError} attrs_or_error
      */
-    async onMessage (attrs_or_error) {
+    async onMessage(attrs_or_error) {
         if (u.isErrorObject(attrs_or_error)) {
-            const { stanza, message } = /** @type {StanzaParseError} */(attrs_or_error);
+            const { stanza, message } = /** @type {StanzaParseError} */ (attrs_or_error);
             if (stanza) log.error(stanza);
             return log.error(message);
         }
 
-        const attrs = /** @type {MessageAttributes} */(attrs_or_error);
+        const attrs = /** @type {MessageAttributes} */ (attrs_or_error);
         const message = this.getDuplicateMessage(attrs);
         if (message) {
             this.updateMessage(message, attrs);
         } else if (
-                !this.handleReceipt(attrs) &&
-                !this.handleChatMarker(attrs) && !(await this.handleRetraction(attrs))
+            !this.handleReceipt(attrs) &&
+            !this.handleChatMarker(attrs) &&
+            !(await this.handleRetraction(attrs))
         ) {
             this.setEditable(attrs, attrs.time);
 
@@ -92,8 +91,8 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
                 this.notifications.set('chat_state', attrs.chat_state);
             }
             if (u.shouldCreateMessage(attrs)) {
-                const msg = await this.handleCorrection(attrs) || await this.createMessage(attrs);
-                this.notifications.set({'chat_state': null});
+                const msg = (await this.handleCorrection(attrs)) || (await this.createMessage(attrs));
+                this.notifications.set({ 'chat_state': null });
                 this.handleUnreadMessage(msg);
             }
         }
@@ -102,7 +101,7 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
     /**
      * @param {import('../roster/presence').default} item
      */
-    onPresenceChanged (item) {
+    onPresenceChanged(item) {
         const { __ } = _converse;
         const show = item.get('show');
         const fullname = this.getDisplayName();
@@ -119,7 +118,7 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
         text && this.createMessage({ message: text, type: 'info', is_ephemeral: true });
     }
 
-    async close () {
+    async close() {
         if (api.connection.connected()) {
             // Immediately sending the chat state, because the
             // model is going to be destroyed afterwards.
@@ -132,7 +131,7 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
     /**
      * @returns {string|null}
      */
-    getDisplayName () {
+    getDisplayName() {
         if (this.contact) {
             const display_name = this.contact.getDisplayName(false);
             if (display_name) return display_name;
@@ -149,33 +148,34 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
      * @param {string} jid1
      * @param {string} jid2
      */
-    isSameUser (jid1, jid2) {
+    isSameUser(jid1, jid2) {
         return u.isSameBareJID(jid1, jid2);
     }
 
     /**
      * @param {MessageAttributes} attrs
      */
-    handleChatMarker (attrs) {
+    handleChatMarker(attrs) {
         const to_bare_jid = Strophe.getBareJidFromJid(attrs.to);
         if (to_bare_jid !== _converse.session.get('bare_jid')) {
             return false;
         }
 
         if (attrs.is_markable) {
-            if (this.contact &&
-                    !['none', 'to', undefined].includes(this.contact.get('subscription')) &&
-                    !attrs.is_archived &&
-                    !attrs.is_carbon) {
+            if (
+                this.contact &&
+                !['none', 'to', undefined].includes(this.contact.get('subscription')) &&
+                !attrs.is_archived &&
+                !attrs.is_carbon
+            ) {
                 sendMarker(attrs.from, attrs.msgid, 'received');
             }
             return false;
-
         } else if (attrs.marker_id) {
-            const message = this.messages.findWhere({'msgid': attrs.marker_id});
+            const message = this.messages.findWhere({ 'msgid': attrs.marker_id });
             const field_name = `marker_${attrs.marker}`;
             if (message && !message.get(field_name)) {
-                message.save({field_name: (new Date()).toISOString()});
+                message.save({ field_name: new Date().toISOString() });
             }
             return true;
         }
@@ -185,26 +185,31 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
      * @param {MessageAttributes} [attrs]
      * @return {Promise<MessageAttributes>}
      */
-    async getOutgoingMessageAttributes (attrs) {
+    async getOutgoingMessageAttributes(attrs) {
         const is_spoiler = !!this.get('composing_spoiler');
         const origin_id = u.getUniqueId();
         const text = attrs?.body;
         const body = text ? u.shortnamesToUnicode(text) : undefined;
-        attrs = Object.assign({}, attrs, {
-            body,
-            from: _converse.session.get('jid'),
-            fullname: _converse.state.xmppstatus.get('fullname'),
-            id: origin_id,
-            is_spoiler,
-            jid: this.get('jid'),
-            message: body,
-            msgid: origin_id,
-            nick: this.get('nickname'),
-            origin_id,
-            sender: 'me',
-            time: (new Date()).toISOString(),
-            type: this.get('message_type'),
-        }, await u.getMediaURLsMetadata(text));
+        attrs = Object.assign(
+            {},
+            attrs,
+            {
+                body,
+                from: _converse.session.get('jid'),
+                fullname: _converse.state.xmppstatus.get('fullname'),
+                id: origin_id,
+                is_spoiler,
+                jid: this.get('jid'),
+                message: body,
+                msgid: origin_id,
+                nick: this.get('nickname'),
+                origin_id,
+                sender: 'me',
+                time: new Date().toISOString(),
+                type: this.get('message_type'),
+            },
+            await u.getMediaURLsMetadata(text)
+        );
 
         /**
          * *Hook* which allows plugins to update the attributes of an outgoing message.
@@ -220,7 +225,7 @@ class ChatBox extends ModelWithVCard(ModelWithMessages(ModelWithContact(ColorAwa
         return attrs;
     }
 
-    canPostMessages () {
+    canPostMessages() {
         return true;
     }
 }

+ 11 - 11
src/headless/shared/api/user.js

@@ -26,7 +26,7 @@ const api = {
          * @returns {string} The current user's full JID (Jabber ID)
          * @example _converse.api.user.jid())
          */
-        jid () {
+        jid() {
             return connection_api.get()?.jid;
         },
 
@@ -47,13 +47,13 @@ const api = {
          *  fails to restore a previous auth'd session.
          *  @returns  { Promise<void> }
          */
-        async login (jid, password, automatic=false) {
+        async login(jid, password, automatic = false) {
             const { api } = _converse;
             jid = jid || api.settings.get('jid');
 
             const connection = connection_api.init(jid);
 
-            if (api.settings.get("connection_options")?.worker && (await connection.restoreWorkerSession())) {
+            if (api.settings.get('connection_options')?.worker && (await connection.restoreWorkerSession())) {
                 return;
             }
             if (jid) {
@@ -85,8 +85,8 @@ const api = {
             const { success } = await _converse.api.hook('login', this, { jid, password, automatic });
             if (success) return;
 
-            password = password || api.settings.get("password");
-            const credentials = (jid && password) ? { jid, password } : null;
+            password = password || api.settings.get('password');
+            const credentials = jid && password ? { jid, password } : null;
             await attemptNonPreboundSession(credentials, automatic);
         },
 
@@ -95,13 +95,13 @@ const api = {
          * @method _converse.api.user.logout
          * @example _converse.api.user.logout();
          */
-        async logout () {
+        async logout() {
             const { api } = _converse;
             /**
              * Triggered before the user is logged out
              * @event _converse#beforeLogout
              */
-            await api.trigger('beforeLogout', {'synchronous': true});
+            await api.trigger('beforeLogout', { 'synchronous': true });
 
             const promise = getOpenPromise();
             const complete = () => {
@@ -118,7 +118,7 @@ const api = {
                  */
                 api.trigger('logout');
                 promise.resolve();
-            }
+            };
 
             const connection = connection_api.get();
 
@@ -130,8 +130,8 @@ const api = {
                 complete();
             }
             return promise;
-        }
-    }
-}
+        },
+    },
+};
 
 export default api;

+ 5 - 5
src/headless/utils/storage.js

@@ -5,20 +5,20 @@ import { getUnloadEvent } from './session.js';
 
 const settings = settings_api;
 
-export function getDefaultStore () {
+export function getDefaultStore() {
     if (_converse.state.config.get('trusted')) {
         const is_non_persistent = settings.get('persistent_store') === 'sessionStorage';
-        return is_non_persistent ? 'session': 'persistent';
+        return is_non_persistent ? 'session' : 'persistent';
     } else {
         return 'session';
     }
 }
 
-function storeUsesIndexedDB (store) {
+function storeUsesIndexedDB(store) {
     return store === 'persistent' && settings.get('persistent_store') === 'IndexedDB';
 }
 
-export function createStore (id, store) {
+export function createStore(id, store) {
     const name = store || getDefaultStore();
     const s = _converse.storage[name];
     if (typeof s === 'undefined') {
@@ -27,7 +27,7 @@ export function createStore (id, store) {
     return new Storage(id, s, storeUsesIndexedDB(store));
 }
 
-export function initStorage (model, id, type) {
+export function initStorage(model, id, type) {
     const store = type || getDefaultStore();
     model.browserStorage = createStore(id, store);
     if (storeUsesIndexedDB(store)) {

+ 14 - 16
src/plugins/chatboxviews/container.js

@@ -1,54 +1,52 @@
-
 class ChatBoxViews {
-
-    constructor () {
+    constructor() {
         this.views = {};
         this.el = null;
     }
 
-    add (key, val) {
+    add(key, val) {
         this.views[key] = val;
     }
 
-    get (key) {
+    get(key) {
         return this.views[key];
     }
 
-    xget (id) {
+    xget(id) {
         return this.keys()
-            .filter(k => (k !== id))
+            .filter((k) => k !== id)
             .reduce((acc, k) => {
-                acc[k] = this.views[k]
+                acc[k] = this.views[k];
                 return acc;
             }, {});
     }
 
-    getAll () {
+    getAll() {
         return Object.values(this.views);
     }
 
-    keys () {
+    keys() {
         return Object.keys(this.views);
     }
 
-    remove (key) {
+    remove(key) {
         delete this.views[key];
     }
 
-    map (f) {
+    map(f) {
         return Object.values(this.views).map(f);
     }
 
-    forEach (f) {
+    forEach(f) {
         return Object.values(this.views).forEach(f);
     }
 
-    filter (f) {
+    filter(f) {
         return Object.values(this.views).filter(f);
     }
 
-    closeAllChatBoxes () {
-        return Promise.all(Object.values(this.views).map(v => v.close({ 'name': 'closeAllChatBoxes' })));
+    closeAllChatBoxes() {
+        return Promise.all(Object.values(this.views).map((v) => v.close({ 'name': 'closeAllChatBoxes' })));
     }
 }
 

+ 20 - 23
src/plugins/chatview/bottom-panel.js

@@ -11,21 +11,19 @@ import './message-form.js';
 
 import './styles/chat-bottom-panel.scss';
 
-
 export default class ChatBottomPanel extends CustomElement {
-
-    constructor () {
+    constructor() {
         super();
         this.model = null;
     }
 
-    static get properties () {
+    static get properties() {
         return {
-            model: { type: Object }
-        }
+            model: { type: Object },
+        };
     }
 
-    async connectedCallback () {
+    async connectedCallback() {
         super.connectedCallback();
         await this.initialize();
         // Don't call in initialize, since the MUCBottomPanel subclasses it
@@ -33,43 +31,42 @@ export default class ChatBottomPanel extends CustomElement {
         this.requestUpdate();
     }
 
-    async initialize () {
+    async initialize() {
         await this.model.initialized;
         this.listenTo(this.model, 'change:num_unread', () => this.requestUpdate());
         this.listenTo(this.model, 'emoji-picker-autocomplete', this.autocompleteInPicker);
 
-        this.addEventListener('click', ev => this.sendButtonClicked(ev));
-        this.addEventListener(
-            'emojipickerblur',
-            () => /** @type {HTMLElement} */(this.querySelector('.chat-textarea')).focus()
+        this.addEventListener('click', (ev) => this.sendButtonClicked(ev));
+        this.addEventListener('emojipickerblur', () =>
+            /** @type {HTMLElement} */ (this.querySelector('.chat-textarea')).focus()
         );
     }
 
-    render () {
+    render() {
         if (!this.model) return '';
         return tplBottomPanel({
             'model': this.model,
-            'viewUnreadMessages': ev => this.viewUnreadMessages(ev)
+            'viewUnreadMessages': (ev) => this.viewUnreadMessages(ev),
         });
     }
 
-    sendButtonClicked (ev) {
+    sendButtonClicked(ev) {
         if (ev.delegateTarget?.dataset.action === 'sendMessage') {
-            const form = /** @type {MessageForm} */(this.querySelector('converse-message-form'));
+            const form = /** @type {MessageForm} */ (this.querySelector('converse-message-form'));
             form?.onFormSubmitted(ev);
         }
     }
 
-    viewUnreadMessages (ev) {
+    viewUnreadMessages(ev) {
         ev?.preventDefault?.();
         this.model.ui.set({ 'scrolled': false });
     }
 
-    onDragOver (ev) {
+    onDragOver(ev) {
         ev.preventDefault();
     }
 
-    clearMessages (ev) {
+    clearMessages(ev) {
         ev?.preventDefault?.();
         clearMessages(this.model);
     }
@@ -80,17 +77,17 @@ export default class ChatBottomPanel extends CustomElement {
      * @property {string} value
      * @param {AutocompleteInPickerEvent} ev
      */
-    async autocompleteInPicker (ev) {
+    async autocompleteInPicker(ev) {
         const { target: input, value } = ev;
         await api.emojis.initialize();
-        const emoji_picker = /** @type {EmojiPicker} */(this.querySelector('converse-emoji-picker'));
+        const emoji_picker = /** @type {EmojiPicker} */ (this.querySelector('converse-emoji-picker'));
         if (emoji_picker) {
             emoji_picker.state.set({
                 ac_position: input.selectionStart,
                 autocompleting: value,
-                query: value
+                query: value,
             });
-            const emoji_dropdown = /** @type {EmojiDropdown} */(this.querySelector('converse-emoji-dropdown'));
+            const emoji_dropdown = /** @type {EmojiDropdown} */ (this.querySelector('converse-emoji-dropdown'));
             emoji_dropdown?.dropdown.show();
         }
     }

+ 12 - 14
src/plugins/controlbox/model.js

@@ -4,7 +4,6 @@ import { _converse, api, converse, constants } from '@converse/headless';
 const { dayjs } = converse.env;
 const { CONTROLBOX_TYPE } = constants;
 
-
 /**
  * The ControlBox is the section of the chat that contains the open groupchats,
  * bookmarks and roster.
@@ -13,21 +12,20 @@ const { CONTROLBOX_TYPE } = constants;
  * `view_mode` it's a left-aligned sidebar.
  */
 class ControlBox extends Model {
-
-    defaults () {
+    defaults() {
         return {
-            'bookmarked': false,
-            'box_id': 'controlbox',
-            'chat_state': undefined,
-            'closed': !api.settings.get('show_controlbox_by_default'),
-            'num_unread': 0,
-            'time_opened': dayjs(0).valueOf(),
-            'type': CONTROLBOX_TYPE,
-            'url': ''
+            bookmarked: false,
+            box_id: 'controlbox',
+            chat_state: undefined,
+            closed: !api.settings.get('show_controlbox_by_default'),
+            num_unread: 0,
+            time_opened: dayjs(0).valueOf(),
+            type: CONTROLBOX_TYPE,
+            url: '',
         };
     }
 
-    validate (attrs) {
+    validate(attrs) {
         if (attrs.type === CONTROLBOX_TYPE) {
             if (api.settings.get('view_mode') === 'embedded' && api.settings.get('singleton')) {
                 return 'Controlbox not relevant in embedded view mode';
@@ -40,7 +38,7 @@ class ControlBox extends Model {
     /**
      * @param {boolean} [force]
      */
-    maybeShow (force) {
+    maybeShow(force) {
         if (!force && this.get('id') === 'controlbox') {
             // Must return the chatbox
             return this;
@@ -48,7 +46,7 @@ class ControlBox extends Model {
         return _converse.state.ChatBox.prototype.maybeShow.call(this, force);
     }
 
-    onReconnection () {
+    onReconnection() {
         this.save('connected', true);
     }
 }

+ 1 - 1
src/plugins/controlbox/templates/loginform.js

@@ -154,7 +154,7 @@ export default (el) => {
         >
             <span class="feedback-message">${conn_feedback_message}</span>
         </div>
-        ${CONNECTION_STATUS[connection_status] === 'CONNECTING'
+        ${['CONNECTING', 'AUTHENTICATING', 'RECONNECTING'].includes(CONNECTION_STATUS[connection_status])
             ? html`<div class="text-center my-3">${tplSpinner()}</div>`
             : tplFormFields()}
     </form>`;