Let bookmarks be created/removed via a modal
This commit is contained in:
parent
9d250c3cbf
commit
505416a59e
@ -14,12 +14,14 @@ class MUCBookmarkForm extends CustomElement {
|
|||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this.model = _converse.chatboxes.get(this.jid);
|
this.model = _converse.chatboxes.get(this.jid);
|
||||||
|
this.bookmark = _converse.bookmarks.findWhere({ 'jid': this.model.get('jid') });
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return tpl_muc_bookmark_form(
|
return tpl_muc_bookmark_form(
|
||||||
Object.assign(this.model.toJSON(), {
|
Object.assign(this.model.toJSON(), {
|
||||||
'onCancel': ev => this.closeBookmarkForm(ev),
|
'bookmark': this.bookmark,
|
||||||
|
'onCancel': ev => this.removeBookmark(ev),
|
||||||
'onSubmit': ev => this.onBookmarkFormSubmitted(ev)
|
'onSubmit': ev => this.onBookmarkFormSubmitted(ev)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -36,9 +38,16 @@ class MUCBookmarkForm extends CustomElement {
|
|||||||
this.closeBookmarkForm(ev);
|
this.closeBookmarkForm(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeBookmark (ev) {
|
||||||
|
this.bookmark?.destroy();
|
||||||
|
this.closeBookmarkForm(ev);
|
||||||
|
}
|
||||||
|
|
||||||
closeBookmarkForm (ev) {
|
closeBookmarkForm (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.model.session.save('view', null);
|
const evt = document.createEvent('Event');
|
||||||
|
evt.initEvent('hide.bs.modal', true, true);
|
||||||
|
this.dispatchEvent(evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
const { u } = converse.env;
|
||||||
|
|
||||||
@ -30,13 +31,9 @@ export const bookmarkableChatRoomView = {
|
|||||||
u.showElement(this.bookmark_form.el);
|
u.showElement(this.bookmark_form.el);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleBookmark (ev) {
|
showBookmarkModal(ev) {
|
||||||
ev?.preventDefault();
|
ev?.preventDefault();
|
||||||
const models = _converse.bookmarks.where({ 'jid': this.model.get('jid') });
|
const jid = this.model.get('jid');
|
||||||
if (!models.length) {
|
api.modal.show(MUCBookmarkFormModal, { jid }, ev);
|
||||||
this.model.session.set('view', converse.MUC.VIEWS.BOOKMARK);
|
|
||||||
} else {
|
|
||||||
models.forEach(model => model.destroy());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
19
src/plugins/bookmark-views/modal.js
Normal file
19
src/plugins/bookmark-views/modal.js
Normal file
@ -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;
|
@ -3,22 +3,24 @@ import { __ } from 'i18n';
|
|||||||
|
|
||||||
|
|
||||||
export default (o) => {
|
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_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_name = __('The name for this bookmark:');
|
||||||
const i18n_nick = __('What should your nickname for this groupchat be?');
|
const i18n_nick = __('What should your nickname for this groupchat be?');
|
||||||
const i18n_submit = __('Save');
|
const i18n_submit = o.bookmark ? __('Update') : __('Save');
|
||||||
return html`
|
return html`
|
||||||
<form class="converse-form chatroom-form" @submit=${o.onSubmit}>
|
<form class="converse-form chatroom-form" @submit=${o.onSubmit}>
|
||||||
<legend>${i18n_heading}</legend>
|
<legend>${i18n_heading}</legend>
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<label for="converse_muc_bookmark_name">${i18n_name}</label>
|
<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>
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<label for="converse_muc_bookmark_nick">${i18n_nick}</label>
|
<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>
|
||||||
<fieldset class="form-group form-check">
|
<fieldset class="form-group form-check">
|
||||||
<input class="form-check-input" id="converse_muc_bookmark_autojoin" type="checkbox" name="autojoin"/>
|
<input class="form-check-input" id="converse_muc_bookmark_autojoin" type="checkbox" name="autojoin"/>
|
||||||
@ -26,7 +28,7 @@ export default (o) => {
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<input class="btn btn-primary" type="submit" value="${i18n_submit}">
|
<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>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
`;
|
`;
|
||||||
|
19
src/plugins/bookmark-views/templates/modal.js
Normal file
19
src/plugins/bookmark-views/templates/modal.js
Normal file
@ -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>`;
|
||||||
|
}
|
@ -5,8 +5,7 @@ const { Strophe, u, sizzle, $iq } = converse.env;
|
|||||||
|
|
||||||
describe("A chat room", function () {
|
describe("A chat room", function () {
|
||||||
|
|
||||||
it("can be bookmarked", mock.initConverse(
|
it("can be bookmarked", mock.initConverse(['chatBoxesFetched'], {}, async (_converse) => {
|
||||||
['chatBoxesFetched'], {}, async function (_converse) {
|
|
||||||
|
|
||||||
await mock.waitForRoster(_converse, 'current', 0);
|
await mock.waitForRoster(_converse, 'current', 0);
|
||||||
await mock.waitUntilDiscoConfirmed(
|
await mock.waitUntilDiscoConfirmed(
|
||||||
@ -27,20 +26,13 @@ describe("A chat room", function () {
|
|||||||
await mock.returnMemberLists(_converse, muc_jid, [], ['member', 'admin', 'owner']);
|
await mock.returnMemberLists(_converse, muc_jid, [], ['member', 'admin', 'owner']);
|
||||||
|
|
||||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
|
await u.waitUntil(() => view.querySelector('.toggle-bookmark') !== null);
|
||||||
|
|
||||||
const toggle = view.querySelector('.toggle-bookmark');
|
const toggle = view.querySelector('.toggle-bookmark');
|
||||||
expect(toggle.title).toBe('Bookmark this groupchat');
|
expect(toggle.title).toBe('Bookmark this groupchat');
|
||||||
toggle.click();
|
toggle.click();
|
||||||
|
|
||||||
const cancel_button = await u.waitUntil(() => view.querySelector('.button-cancel'));
|
const modal = _converse.api.modal.get('converse-bookmark-modal');
|
||||||
expect(view.model.session.get('view')).toBe('bookmark-form');
|
await u.waitUntil(() => u.isVisible(modal.el), 1000);
|
||||||
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();
|
|
||||||
|
|
||||||
/* Client uploads data:
|
/* Client uploads data:
|
||||||
* --------------------
|
* --------------------
|
||||||
@ -74,13 +66,13 @@ describe("A chat room", function () {
|
|||||||
* </iq>
|
* </iq>
|
||||||
*/
|
*/
|
||||||
expect(view.model.get('bookmarked')).toBeFalsy();
|
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's the Thing';
|
form.querySelector('input[name="name"]').value = 'Play's the Thing';
|
||||||
form.querySelector('input[name="autojoin"]').checked = 'checked';
|
form.querySelector('input[name="autojoin"]').checked = 'checked';
|
||||||
form.querySelector('input[name="nick"]').value = 'JC';
|
form.querySelector('input[name="nick"]').value = 'JC';
|
||||||
|
|
||||||
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
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(
|
const sent_stanza = await u.waitUntil(
|
||||||
() => IQ_stanzas.filter(s => sizzle('iq publish[node="storage:bookmarks"]', s).length).pop());
|
() => 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) {
|
it("can be unbookmarked", mock.initConverse([], {}, async function (_converse) {
|
||||||
|
|
||||||
const { u, Strophe } = converse.env;
|
const { u, Strophe } = converse.env;
|
||||||
await mock.waitForRoster(_converse, 'current', 0);
|
await mock.waitForRoster(_converse, 'current', 0);
|
||||||
await mock.waitUntilBookmarksReturned(_converse);
|
await mock.waitUntilBookmarksReturned(_converse);
|
||||||
@ -240,14 +231,14 @@ describe("A chat room", function () {
|
|||||||
const view = _converse.chatboxviews.get(muc_jid);
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
await u.waitUntil(() => view.querySelector('.toggle-bookmark'));
|
await u.waitUntil(() => view.querySelector('.toggle-bookmark'));
|
||||||
|
|
||||||
spyOn(view, 'toggleBookmark').and.callThrough();
|
spyOn(view, 'showBookmarkModal').and.callThrough();
|
||||||
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
|
spyOn(_converse.bookmarks, 'sendBookmarkStanza').and.callThrough();
|
||||||
|
|
||||||
_converse.bookmarks.create({
|
_converse.bookmarks.create({
|
||||||
'jid': view.model.get('jid'),
|
'jid': view.model.get('jid'),
|
||||||
'autojoin': false,
|
'autojoin': false,
|
||||||
'name': 'The Play',
|
'name': 'The Play',
|
||||||
'nick': ' Othello'
|
'nick': 'Othello'
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(_converse.bookmarks.length).toBe(1);
|
expect(_converse.bookmarks.length).toBe(1);
|
||||||
@ -257,7 +248,19 @@ describe("A chat room", function () {
|
|||||||
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
|
spyOn(_converse.connection, 'getUniqueId').and.callThrough();
|
||||||
const bookmark_icon = view.querySelector('.toggle-bookmark');
|
const bookmark_icon = view.querySelector('.toggle-bookmark');
|
||||||
bookmark_icon.click();
|
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);
|
await u.waitUntil(() => view.querySelector('.chatbox-title__text .fa-bookmark') === null);
|
||||||
expect(_converse.bookmarks.length).toBe(0);
|
expect(_converse.bookmarks.length).toBe(0);
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { checkBookmarksSupport } from '@converse/headless/plugins/bookmarks/utils';
|
import MUCBookmarkFormModal from './modal.js';
|
||||||
import invokeMap from 'lodash-es/invokeMap';
|
import invokeMap from 'lodash-es/invokeMap';
|
||||||
import { Model } from '@converse/skeletor/src/model.js';
|
import { Model } from '@converse/skeletor/src/model.js';
|
||||||
import { _converse, api, converse } from '@converse/headless/core';
|
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
|
import { _converse, api, converse } from '@converse/headless/core';
|
||||||
|
import { checkBookmarksSupport } from '@converse/headless/plugins/bookmarks/utils';
|
||||||
|
|
||||||
|
|
||||||
export function getHeadingButtons (view, buttons) {
|
export function getHeadingButtons (view, buttons) {
|
||||||
@ -11,7 +12,7 @@ export function getHeadingButtons (view, buttons) {
|
|||||||
const data = {
|
const data = {
|
||||||
'i18n_title': bookmarked ? __('Unbookmark this groupchat') : __('Bookmark this groupchat'),
|
'i18n_title': bookmarked ? __('Unbookmark this groupchat') : __('Bookmark this groupchat'),
|
||||||
'i18n_text': bookmarked ? __('Unbookmark') : __('Bookmark'),
|
'i18n_text': bookmarked ? __('Unbookmark') : __('Bookmark'),
|
||||||
'handler': ev => view.toggleBookmark(ev),
|
'handler': ev => view.showBookmarkModal(ev),
|
||||||
'a_class': 'toggle-bookmark',
|
'a_class': 'toggle-bookmark',
|
||||||
'icon_class': 'fa-bookmark',
|
'icon_class': 'fa-bookmark',
|
||||||
'name': 'bookmark'
|
'name': 'bookmark'
|
||||||
@ -33,11 +34,10 @@ export function removeBookmarkViaEvent (ev) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addBookmarkViaEvent (ev) {
|
export function addBookmarkViaEvent (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
const jid = ev.target.getAttribute('data-room-jid');
|
const jid = ev.target.getAttribute('data-room-jid');
|
||||||
const room = await api.rooms.open(jid, { 'bring_to_foreground': true });
|
api.modal.show(MUCBookmarkFormModal, { jid }, ev);
|
||||||
room.session.save('view', converse.MUC.VIEWS.BOOKMARK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import './styles/index.scss';
|
|||||||
|
|
||||||
converse.MUC.VIEWS = {
|
converse.MUC.VIEWS = {
|
||||||
CONFIG: 'config-form',
|
CONFIG: 'config-form',
|
||||||
BOOKMARK: 'bookmark-form'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
converse.plugins.add('converse-muc-views', {
|
converse.plugins.add('converse-muc-views', {
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import '../modtools.js';
|
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';
|
import tpl_moderator_tools from './templates/moderator-tools.js';
|
||||||
|
|
||||||
const ModeratorToolsModal = BootstrapModal.extend({
|
const ModeratorToolsModal = BaseModal.extend({
|
||||||
id: "converse-modtools-modal",
|
id: "converse-modtools-modal",
|
||||||
persistent: true,
|
persistent: true,
|
||||||
|
|
||||||
initialize (attrs) {
|
initialize (attrs) {
|
||||||
this.jid = attrs.jid;
|
this.jid = attrs.jid;
|
||||||
this.affiliation = attrs.affiliation;
|
this.affiliation = attrs.affiliation;
|
||||||
BootstrapModal.prototype.initialize.apply(this, arguments);
|
BaseModal.prototype.initialize.apply(this, arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
toHTML () {
|
toHTML () {
|
||||||
|
@ -124,8 +124,6 @@ export function getChatRoomBodyTemplate (o) {
|
|||||||
|
|
||||||
if (view === converse.MUC.VIEWS.CONFIG) {
|
if (view === converse.MUC.VIEWS.CONFIG) {
|
||||||
return html`<converse-muc-config-form class="muc-form-container" jid="${jid}"></converse-muc-config-form>`;
|
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 {
|
} else {
|
||||||
return html`
|
return html`
|
||||||
${ conn_status == RS.PASSWORD_REQUIRED ? html`<converse-muc-password-form class="muc-form-container" jid="${jid}"></converse-muc-password-form>` : '' }
|
${ conn_status == RS.PASSWORD_REQUIRED ? html`<converse-muc-password-form class="muc-form-container" jid="${jid}"></converse-muc-password-form>` : '' }
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
muc_domain: 'conference.chat.example.org',
|
muc_domain: 'conference.chat.example.org',
|
||||||
muc_respect_autojoin: true,
|
muc_respect_autojoin: true,
|
||||||
view_mode: 'fullscreen',
|
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',
|
// bosh_service_url: 'http://chat.example.org:5280/http-bind',
|
||||||
allow_user_defined_connection_url: true,
|
allow_user_defined_connection_url: true,
|
||||||
muc_show_logs_before_join: true,
|
muc_show_logs_before_join: true,
|
||||||
|
@ -9,7 +9,7 @@ module.exports = merge(common, {
|
|||||||
devtool: "inline-source-map",
|
devtool: "inline-source-map",
|
||||||
devServer: {
|
devServer: {
|
||||||
static: [ path.resolve(__dirname, '../') ],
|
static: [ path.resolve(__dirname, '../') ],
|
||||||
port: 3003
|
port: 3004
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new HTMLWebpackPlugin({
|
new HTMLWebpackPlugin({
|
||||||
|
Loading…
Reference in New Issue
Block a user