浏览代码

Add the ability to show/hide unfurls

JC Brand 4 年之前
父节点
当前提交
68d461bd42
共有 6 个文件被更改,包括 103 次插入9 次删除
  1. 1 0
      README.md
  2. 1 1
      sass/_core.scss
  3. 42 0
      spec/unfurls.js
  4. 42 4
      src/components/message-actions.js
  5. 11 2
      src/shared/chat/message.js
  6. 6 2
      src/shared/chat/templates/message.js

+ 1 - 0
README.md

@@ -61,6 +61,7 @@ In embedded mode, Converse can be embedded into an element in the DOM.
 -   A [plugin architecture](https://conversejs.org/docs/html/plugin_development.html) based on [pluggable.js](https://conversejs.github.io/pluggable.js/)
 -   Chat statuses (online, busy, away, offline)
 -   Anonymous logins, see the [anonymous login demo](https://conversejs.org/demo/anonymous.html)
+-   URL Previews (requires server support, for example [mod_ogp](https://modules.prosody.im/mod_ogp.html)
 -   Translated into over 30 languages
 
 ### Supported XMPP Extensions

+ 1 - 1
sass/_core.scss

@@ -2,7 +2,7 @@
     opacity: 0;  /* make things invisible upon start */
     animation-name: fadein;
     animation-fill-mode: forwards;
-    animation-duration: 0.75s;
+    animation-duration: 0.5s;
     animation-timing-function: ease;
 }
 

+ 42 - 0
spec/unfurls.js

@@ -261,4 +261,46 @@ describe("A Groupchat Message", function () {
         done();
     }));
 
+    it("lets the user hide an unfurl",
+            mock.initConverse(['chatBoxesFetched'],
+            {'show_images_inline': []},
+            async function (done, _converse) {
+
+        const nick = 'romeo';
+        const muc_jid = 'lounge@montague.lit';
+        await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
+        const view = _converse.api.chatviews.get(muc_jid);
+
+        const message_stanza = u.toStanza(`
+            <message xmlns="jabber:client" type="groupchat" from="${muc_jid}/arzu" xml:lang="en" to="${_converse.jid}" id="eda6c790-b4f3-4c07-b5e2-13fff99e6c04">
+                <body>https://www.youtube.com/watch?v=dQw4w9WgXcQ</body>
+                <active xmlns="http://jabber.org/protocol/chatstates"/>
+                <origin-id xmlns="urn:xmpp:sid:0" id="eda6c790-b4f3-4c07-b5e2-13fff99e6c04"/>
+                <stanza-id xmlns="urn:xmpp:sid:0" by="${muc_jid}" id="8f7613cc-27d4-40ca-9488-da25c4baf92a"/>
+                <markable xmlns="urn:xmpp:chat-markers:0"/>
+            </message>`);
+        _converse.connection._dataRecv(mock.createRequest(message_stanza));
+        const el = await u.waitUntil(() => view.querySelector('.chat-msg__text'));
+        expect(el.textContent).toBe('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
+
+        const metadata_stanza = u.toStanza(`
+            <message xmlns="jabber:client" from="${muc_jid}" to="${_converse.jid}" type="groupchat">
+                <apply-to xmlns="urn:xmpp:fasten:0" id="eda6c790-b4f3-4c07-b5e2-13fff99e6c04">
+                    <meta xmlns="http://www.w3.org/1999/xhtml" property="og:url" content="https://www.youtube.com/watch?v=dQw4w9WgXcQ" />
+                    <meta xmlns="http://www.w3.org/1999/xhtml" property="og:title" content="Rick Astley - Never Gonna Give You Up (Video)" />
+                    <meta xmlns="http://www.w3.org/1999/xhtml" property="og:image" content="https://i.ytimg.com/vi/dQw4w9WgXcQ/maxresdefault.jpg" />
+                    <meta xmlns="http://www.w3.org/1999/xhtml" property="og:description" content="Rick Astley&amp;#39;s official music video for &quot;Never Gonna Give You Up&quot; Listen to Rick Astley: https://RickAstley.lnk.to/_listenYD Subscribe to the official Rick Ast..." />
+                    <meta xmlns="http://www.w3.org/1999/xhtml" property="og:type" content="video.other" />
+                </apply-to>
+            </message>`);
+        _converse.connection._dataRecv(mock.createRequest(metadata_stanza));
+
+        await u.waitUntil(() => view.querySelector('converse-message-unfurl'));
+        const button = await u.waitUntil(() => view.querySelector('.chat-msg__content .chat-msg__action-hide-previews'));
+        button.click();
+        await u.waitUntil(() => view.querySelector('converse-message-unfurl') === null, 750);
+        button.click();
+        await u.waitUntil(() => view.querySelector('converse-message-unfurl'), 750);
+        done();
+    }));
 });

+ 42 - 4
src/components/message-actions.js

@@ -12,11 +12,13 @@ class MessageActions extends CustomElement {
 
     static get properties () {
         return {
-            model: { type: Object },
-            editable: { type: Boolean },
             correcting: { type: Boolean },
-            message_type: { type: String },
+            editable: { type: Boolean },
+            hide_url_previews: { type: Boolean },
             is_retracted: { type: Boolean },
+            message_type: { type: String },
+            model: { type: Object },
+            unfurls: { type: Number }
         }
     }
 
@@ -147,7 +149,7 @@ class MessageActions extends CustomElement {
     }
 
     onMessageRetractButtonClicked (ev) {
-        ev.preventDefault();
+        ev?.preventDefault?.();
         const chatbox = this.model.collection.chatbox;
         if (chatbox.get('type') === _converse.CHATROOMS_TYPE) {
             this.onMUCMessageRetractButtonClicked();
@@ -156,6 +158,19 @@ class MessageActions extends CustomElement {
         }
     }
 
+    onHidePreviewsButtonClicked (ev) {
+        ev?.preventDefault?.();
+        if (this.hide_url_previews) {
+            this.model.save({
+                'hide_url_previews': false,
+                'url_preview_transition': 'fade-in'
+            });
+        } else {
+            this.model.set('url_preview_transition', 'fade-out');
+        }
+
+    }
+
     async getActionButtons () {
         const buttons = [];
         if (this.editable) {
@@ -178,6 +193,29 @@ class MessageActions extends CustomElement {
                 'name': 'retract'
             });
         }
+
+        const ogp_metadata = this.model.get('ogp_metadata') || [];
+        const chatbox = this.model.collection.chatbox;
+        if (chatbox.get('type') === _converse.CHATROOMS_TYPE &&
+                api.settings.get('muc_show_ogp_unfurls') &&
+                ogp_metadata.length) {
+
+            let title;
+            const hidden_preview = this.hide_url_previews;
+            if (ogp_metadata.length > 1) {
+                title = hidden_preview ? __('Show URL previews') : __('Hide URL previews');
+            } else {
+                title = hidden_preview ? __('Show URL preview') : __('Hide URL preview');
+            }
+            buttons.push({
+                'i18n_text': title,
+                'handler': ev => this.onHidePreviewsButtonClicked(ev),
+                'button_class': 'chat-msg__action-hide-previews',
+                'icon_class': this.hide_url_previews ? 'fas fa-eye' : 'fas fa-eye-slash',
+                'name': 'hide'
+            });
+        }
+
         /**
          * *Hook* which allows plugins to add more message action buttons
          * @event _converse#getMessageActionButtons

+ 11 - 2
src/shared/chat/message.js

@@ -7,7 +7,7 @@ import OccupantModal from 'modals/occupant.js';
 import UserDetailsModal from 'modals/user-details.js';
 import dayjs from 'dayjs';
 import filesize from 'filesize';
-import tpl_chat_message from './templates/message.js';
+import tpl_message from './templates/message.js';
 import tpl_spinner from 'templates/spinner.js';
 import { CustomElement } from 'components/element.js';
 import { __ } from 'i18n';
@@ -126,7 +126,7 @@ export default class Message extends CustomElement {
     }
 
     renderChatMessage () {
-        return tpl_chat_message(this);
+        return tpl_message(this);
     }
 
     shouldShowAvatar () {
@@ -145,6 +145,15 @@ export default class Message extends CustomElement {
         };
     }
 
+    onUnfurlAnimationEnd () {
+        if (this.model.get('url_preview_transition') === 'fade-out') {
+            this.model.save({
+                'hide_url_previews': !this.model.get('hide_url_previews'),
+                'url_preview_transition': 'fade-in'
+            });
+        }
+    }
+
     async onRetryClicked () {
         this.show_spinner = true;
         await api.trigger(this.retry_event_id, {'synchronous': true});

+ 6 - 2
src/shared/chat/templates/message.js

@@ -38,16 +38,20 @@ export default (o) => {
                         ?correcting="${o.correcting}"
                         ?editable="${o.editable}"
                         ?is_retracted="${o.is_retracted}"
+                        ?hide_url_previews="${o.model.get('hide_url_previews')}"
+                        unfurls="${o.model.get('ogp_metadata')?.length}"
                         message_type="${o.message_type}"></converse-message-actions>
                 </div>
 
-                ${ o.model.get('ogp_metadata')?.map(m =>
+                ${ !o.model.get('hide_url_previews') ? o.model.get('ogp_metadata')?.map(m =>
                     html`<converse-message-unfurl
+                        @animationend="${o.onUnfurlAnimationEnd}"
+                        class="${o.model.get('url_preview_transition')}"
                         jid="${o.model.collection.chatbox?.get('jid')}"
                         description="${m['og:description'] || ''}"
                         title="${m['og:title'] || ''}"
                         image="${m['og:image'] || ''}"
-                        url="${m['og:url'] || ''}"></converse-message-unfurl>`) }
+                        url="${m['og:url'] || ''}"></converse-message-unfurl>`) : '' }
             </div>
         </div>`;
 }