瀏覽代碼

Let bookmarks be created/removed via a modal

JC Brand 3 年之前
父節點
當前提交
505416a59e

+ 11 - 2
src/plugins/bookmark-views/form.js

@@ -14,12 +14,14 @@ class MUCBookmarkForm extends CustomElement {
     connectedCallback () {
         super.connectedCallback();
         this.model = _converse.chatboxes.get(this.jid);
+        this.bookmark  = _converse.bookmarks.findWhere({ 'jid': this.model.get('jid') });
     }
 
     render () {
         return tpl_muc_bookmark_form(
             Object.assign(this.model.toJSON(), {
-                'onCancel': ev => this.closeBookmarkForm(ev),
+                'bookmark': this.bookmark,
+                'onCancel': ev => this.removeBookmark(ev),
                 'onSubmit': ev => this.onBookmarkFormSubmitted(ev)
             })
         );
@@ -36,9 +38,16 @@ class MUCBookmarkForm extends CustomElement {
         this.closeBookmarkForm(ev);
     }
 
+    removeBookmark (ev) {
+        this.bookmark?.destroy();
+        this.closeBookmarkForm(ev);
+    }
+
     closeBookmarkForm (ev) {
         ev.preventDefault();
-        this.model.session.save('view', null);
+        const evt = document.createEvent('Event');
+        evt.initEvent('hide.bs.modal', true, true);
+        this.dispatchEvent(evt);
     }
 }
 

+ 5 - 8
src/plugins/bookmark-views/mixins.js

@@ -1,4 +1,5 @@
-import { _converse, converse } from '@converse/headless/core';
+import MUCBookmarkFormModal from './modal.js';
+import { _converse, api, converse } from '@converse/headless/core';
 
 const { u } = converse.env;
 
@@ -30,13 +31,9 @@ export const bookmarkableChatRoomView = {
         u.showElement(this.bookmark_form.el);
     },
 
-    toggleBookmark (ev) {
+    showBookmarkModal(ev) {
         ev?.preventDefault();
-        const models = _converse.bookmarks.where({ 'jid': this.model.get('jid') });
-        if (!models.length) {
-            this.model.session.set('view', converse.MUC.VIEWS.BOOKMARK);
-        } else {
-            models.forEach(model => model.destroy());
-        }
+        const jid = this.model.get('jid');
+        api.modal.show(MUCBookmarkFormModal, { jid }, ev);
     }
 };

+ 19 - 0
src/plugins/bookmark-views/modal.js

@@ -0,0 +1,19 @@
+import './form.js';
+import BaseModal from "plugins/modal/base.js";
+import tpl_modal from './templates/modal.js';
+
+const MUCBookmarkFormModal = BaseModal.extend({
+    id: "converse-bookmark-modal",
+
+    initialize (attrs) {
+        this.jid = attrs.jid;
+        this.affiliation = attrs.affiliation;
+        BaseModal.prototype.initialize.apply(this, arguments);
+    },
+
+    toHTML () {
+        return tpl_modal(this);
+    }
+});
+
+export default MUCBookmarkFormModal;

+ 8 - 6
src/plugins/bookmark-views/templates/form.js

@@ -3,22 +3,24 @@ import { __ } from 'i18n';
 
 
 export default (o) => {
-    const i18n_heading = __('Bookmark this groupchat');
+    const name = o.bookmark?.get('name') ?? o.name;
+    const nick = o.bookmark?.get('nick') ?? o.nick;
+    const i18n_heading = __('Bookmark for "%1$s"', name);
     const i18n_autojoin = __('Would you like this groupchat to be automatically joined upon startup?');
-    const i18n_cancel = __('Cancel');
+    const i18n_remove = __('Remove');
     const i18n_name = __('The name for this bookmark:');
     const i18n_nick = __('What should your nickname for this groupchat be?');
-    const i18n_submit = __('Save');
+    const i18n_submit = o.bookmark ? __('Update') : __('Save');
     return html`
         <form class="converse-form chatroom-form" @submit=${o.onSubmit}>
             <legend>${i18n_heading}</legend>
             <fieldset class="form-group">
                 <label for="converse_muc_bookmark_name">${i18n_name}</label>
-                <input class="form-control" type="text" value="${o.name}" name="name" required="required" id="converse_muc_bookmark_name"/>
+                <input class="form-control" type="text" value="${name}" name="name" required="required" id="converse_muc_bookmark_name"/>
             </fieldset>
             <fieldset class="form-group">
                 <label for="converse_muc_bookmark_nick">${i18n_nick}</label>
-                <input class="form-control" type="text" name="nick" value="${o.nick || ''}" id="converse_muc_bookmark_nick"/>
+                <input class="form-control" type="text" name="nick" value="${nick || ''}" id="converse_muc_bookmark_nick"/>
             </fieldset>
             <fieldset class="form-group form-check">
                 <input class="form-check-input" id="converse_muc_bookmark_autojoin" type="checkbox" name="autojoin"/>
@@ -26,7 +28,7 @@ export default (o) => {
             </fieldset>
             <fieldset class="form-group">
                 <input class="btn btn-primary" type="submit" value="${i18n_submit}">
-                <input class="btn btn-secondary button-cancel" type="button" value="${i18n_cancel}" @click=${o.onCancel}>
+                ${o.bookmark ? html`<input class="btn btn-secondary button-remove" type="button" value="${i18n_remove}" @click=${o.onCancel}>` : '' }
             </fieldset>
         </form>
     `;

+ 19 - 0
src/plugins/bookmark-views/templates/modal.js

@@ -0,0 +1,19 @@
+import { __ } from 'i18n';
+import { html } from "lit";
+import { modal_header_close_button } from "plugins/modal/templates/buttons.js"
+
+export default (o) => {
+    const i18n_moderator_tools = __('Bookmark');
+    return html`
+        <div class="modal-dialog" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title" id="converse-modtools-modal-label">${i18n_moderator_tools}</h5>
+                    ${modal_header_close_button}
+                </div>
+                <div class="modal-body d-flex flex-column">
+                    <converse-muc-bookmark-form class="muc-form-container" jid="${o.jid}"></converse-muc-bookmark-form>
+                </div>
+            </div>
+        </div>`;
+}

+ 21 - 18
src/plugins/bookmark-views/tests/bookmarks.js

@@ -5,8 +5,7 @@ const { Strophe, u, sizzle, $iq } = converse.env;
 
 describe("A chat room", function () {
 
-    it("can be bookmarked", mock.initConverse(
-            ['chatBoxesFetched'], {}, async function (_converse) {
+    it("can be bookmarked", mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
 
         await mock.waitForRoster(_converse, 'current', 0);
         await mock.waitUntilDiscoConfirmed(
@@ -27,20 +26,13 @@ describe("A chat room", function () {
         await mock.returnMemberLists(_converse, muc_jid, [], ['member', 'admin', 'owner']);
 
         await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
+
         const toggle = view.querySelector('.toggle-bookmark');
         expect(toggle.title).toBe('Bookmark this groupchat');
         toggle.click();
 
-        const cancel_button = await u.waitUntil(() => view.querySelector('.button-cancel'));
-        expect(view.model.session.get('view')).toBe('bookmark-form');
-        cancel_button.click();
-
-        await u.waitUntil(() => view.model.session.get('view') === null);
-
-        expect(u.hasClass('on-button', toggle), false);
-        expect(toggle.title).toBe('Bookmark this groupchat');
-
-        toggle.click();
+        const modal = _converse.api.modal.get('converse-bookmark-modal');
+        await u.waitUntil(() => u.isVisible(modal.el), 1000);
 
         /* Client uploads data:
          * --------------------
@@ -74,13 +66,13 @@ describe("A chat room", function () {
          *  </iq>
          */
         expect(view.model.get('bookmarked')).toBeFalsy();
-        const form = await u.waitUntil(() => view.querySelector('.chatroom-form'));
+        const form = await u.waitUntil(() => modal.el.querySelector('.chatroom-form'));
         form.querySelector('input[name="name"]').value = 'Play&apos;s the Thing';
         form.querySelector('input[name="autojoin"]').checked = 'checked';
         form.querySelector('input[name="nick"]').value = 'JC';
 
         const IQ_stanzas = _converse.connection.IQ_stanzas;
-        view.querySelector('converse-muc-bookmark-form .btn-primary').click();
+        modal.el.querySelector('converse-muc-bookmark-form .btn-primary').click();
 
         const sent_stanza = await u.waitUntil(
             () => IQ_stanzas.filter(s => sizzle('iq publish[node="storage:bookmarks"]', s).length).pop());
@@ -227,7 +219,6 @@ describe("A chat room", function () {
         }));
 
         it("can be unbookmarked", mock.initConverse([], {}, async function (_converse) {
-
             const { u, Strophe } = converse.env;
             await mock.waitForRoster(_converse, 'current', 0);
             await mock.waitUntilBookmarksReturned(_converse);
@@ -240,14 +231,14 @@ describe("A chat room", function () {
             const view = _converse.chatboxviews.get(muc_jid);
             await u.waitUntil(() => view.querySelector('.toggle-bookmark'));
 
-            spyOn(view, 'toggleBookmark').and.callThrough();
+            spyOn(view, 'showBookmarkModal').and.callThrough();
             spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
 
             _converse.bookmarks.create({
                 'jid': view.model.get('jid'),
                 'autojoin': false,
                 'name':  'The Play',
-                'nick': ' Othello'
+                'nick': 'Othello'
             });
 
             expect(_converse.bookmarks.length).toBe(1);
@@ -257,7 +248,19 @@ describe("A chat room", function () {
             spyOn(_converse.connection, 'getUniqueId').and.callThrough();
             const bookmark_icon = view.querySelector('.toggle-bookmark');
             bookmark_icon.click();
-            expect(view.toggleBookmark).toHaveBeenCalled();
+            expect(view.showBookmarkModal).toHaveBeenCalled();
+
+            const modal = _converse.api.modal.get('converse-bookmark-modal');
+            await u.waitUntil(() => u.isVisible(modal.el), 1000);
+            const form = await u.waitUntil(() => modal.el.querySelector('.chatroom-form'));
+
+            expect(form.querySelector('input[name="name"]').value).toBe('The Play');
+            expect(form.querySelector('input[name="autojoin"]').checked).toBeFalsy();
+            expect(form.querySelector('input[name="nick"]').value).toBe('Othello');
+
+            // Remove the bookmark
+            modal.el.querySelector('.button-remove').click();
+
             await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') === null);
             expect(_converse.bookmarks.length).toBe(0);
 

+ 6 - 6
src/plugins/bookmark-views/utils.js

@@ -1,8 +1,9 @@
-import { checkBookmarksSupport } from '@converse/headless/plugins/bookmarks/utils';
+import MUCBookmarkFormModal from './modal.js';
 import invokeMap from 'lodash-es/invokeMap';
 import { Model } from '@converse/skeletor/src/model.js';
-import { _converse, api, converse } from '@converse/headless/core';
 import { __ } from 'i18n';
+import { _converse, api, converse } from '@converse/headless/core';
+import { checkBookmarksSupport } from '@converse/headless/plugins/bookmarks/utils';
 
 
 export function getHeadingButtons (view, buttons) {
@@ -11,7 +12,7 @@ export function getHeadingButtons (view, buttons) {
         const data = {
             'i18n_title': bookmarked ? __('Unbookmark this groupchat') : __('Bookmark this groupchat'),
             'i18n_text': bookmarked ? __('Unbookmark') : __('Bookmark'),
-            'handler': ev => view.toggleBookmark(ev),
+            'handler': ev => view.showBookmarkModal(ev),
             'a_class': 'toggle-bookmark',
             'icon_class': 'fa-bookmark',
             'name': 'bookmark'
@@ -33,11 +34,10 @@ export function removeBookmarkViaEvent (ev) {
     }
 }
 
-export async function addBookmarkViaEvent (ev) {
+export function addBookmarkViaEvent (ev) {
     ev.preventDefault();
     const jid = ev.target.getAttribute('data-room-jid');
-    const room = await api.rooms.open(jid, { 'bring_to_foreground': true });
-    room.session.save('view', converse.MUC.VIEWS.BOOKMARK);
+    api.modal.show(MUCBookmarkFormModal, { jid }, ev);
 }
 
 

+ 0 - 1
src/plugins/muc-views/index.js

@@ -14,7 +14,6 @@ import './styles/index.scss';
 
 converse.MUC.VIEWS = {
     CONFIG: 'config-form',
-    BOOKMARK: 'bookmark-form'
 }
 
 converse.plugins.add('converse-muc-views', {

+ 3 - 3
src/plugins/muc-views/modals/moderator-tools.js

@@ -1,15 +1,15 @@
 import '../modtools.js';
-import BootstrapModal from "plugins/modal/base.js";
+import BaseModal from "plugins/modal/base.js";
 import tpl_moderator_tools from './templates/moderator-tools.js';
 
-const ModeratorToolsModal = BootstrapModal.extend({
+const ModeratorToolsModal = BaseModal.extend({
     id: "converse-modtools-modal",
     persistent: true,
 
     initialize (attrs) {
         this.jid = attrs.jid;
         this.affiliation = attrs.affiliation;
-        BootstrapModal.prototype.initialize.apply(this, arguments);
+        BaseModal.prototype.initialize.apply(this, arguments);
     },
 
     toHTML () {

+ 0 - 2
src/plugins/muc-views/utils.js

@@ -124,8 +124,6 @@ export function getChatRoomBodyTemplate (o) {
 
     if (view === converse.MUC.VIEWS.CONFIG) {
         return html`<converse-muc-config-form class="muc-form-container" jid="${jid}"></converse-muc-config-form>`;
-    } else if (view === converse.MUC.VIEWS.BOOKMARK) {
-        return html`<converse-muc-bookmark-form class="muc-form-container" jid="${jid}"></converse-muc-bookmark-form>`;
     } else {
         return html`
             ${ conn_status == RS.PASSWORD_REQUIRED ? html`<converse-muc-password-form class="muc-form-container" jid="${jid}"></converse-muc-password-form>` : '' }

+ 2 - 1
webpack.html

@@ -38,7 +38,8 @@
             muc_domain: 'conference.chat.example.org',
             muc_respect_autojoin: true,
             view_mode: 'fullscreen',
-            websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
+            // websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
+            websocket_url: 'wss://conversejs.org/xmpp-websocket',
             // bosh_service_url: 'http://chat.example.org:5280/http-bind',
             allow_user_defined_connection_url: true,
             muc_show_logs_before_join: true,

+ 1 - 1
webpack/webpack.serve.js

@@ -9,7 +9,7 @@ module.exports = merge(common, {
     devtool: "inline-source-map",
     devServer: {
         static: [ path.resolve(__dirname, '../') ],
-        port: 3003
+        port: 3004
     },
     plugins: [
         new HTMLWebpackPlugin({