Turn converse-roster
and converse-roster-filter
into Lit elements
This commit is contained in:
parent
8de4671603
commit
d2a35d4ce1
@ -1,10 +1,9 @@
|
||||
import debounce from "lodash-es/debounce";
|
||||
import tpl_roster_filter from "./templates/roster_filter.js";
|
||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||
import { CustomElement } from 'shared/components/element.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { _converse, api } from "@converse/headless/core";
|
||||
import { initStorage } from '@converse/headless/shared/utils.js';
|
||||
import { render } from 'lit';
|
||||
|
||||
export const RosterFilter = Model.extend({
|
||||
initialize () {
|
||||
@ -16,8 +15,12 @@ export const RosterFilter = Model.extend({
|
||||
}
|
||||
});
|
||||
|
||||
export class RosterFilterView extends ElementView {
|
||||
tagName = 'span';
|
||||
export class RosterFilterView extends CustomElement {
|
||||
|
||||
constructor () {
|
||||
super();
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
initialize () {
|
||||
const model = new _converse.RosterFilter();
|
||||
@ -30,24 +33,19 @@ export class RosterFilterView extends ElementView {
|
||||
this.model.save({'filter_text': this.querySelector('.roster-filter').value});
|
||||
}, 250);
|
||||
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
this.listenTo(
|
||||
this.model,
|
||||
'change',
|
||||
() => this.dispatchEvent(new CustomEvent('update', { 'detail': this.model.changed }))
|
||||
);
|
||||
|
||||
this.listenTo(_converse.roster, "add", this.render);
|
||||
this.listenTo(_converse.roster, "destroy", this.render);
|
||||
this.listenTo(_converse.roster, "remove", this.render);
|
||||
_converse.presences.on('change:show', this.render, this);
|
||||
this.listenTo(_converse, 'rosterContactsFetched', this.requestUpdate);
|
||||
this.listenTo(_converse.presences, 'change:show', this.requestUpdate);
|
||||
this.listenTo(_converse.roster, "add", this.requestUpdate);
|
||||
this.listenTo(_converse.roster, "destroy", this.requestUpdate);
|
||||
this.listenTo(_converse.roster, "remove", this.requestUpdate);
|
||||
this.listenTo(this.model, 'change', this.dispatchUpdateEvent);
|
||||
this.listenTo(this.model, 'change', this.requestUpdate);
|
||||
|
||||
this.model.fetch();
|
||||
this.render();
|
||||
}
|
||||
|
||||
render () {
|
||||
render(tpl_roster_filter(
|
||||
return tpl_roster_filter(
|
||||
Object.assign(this.model.toJSON(), {
|
||||
visible: this.shouldBeVisible(),
|
||||
changeChatStateFilter: ev => this.changeChatStateFilter(ev),
|
||||
@ -55,8 +53,11 @@ export class RosterFilterView extends ElementView {
|
||||
clearFilter: ev => this.clearFilter(ev),
|
||||
liveFilter: ev => this.liveFilter(ev),
|
||||
submitFilter: ev => this.submitFilter(ev),
|
||||
})), this);
|
||||
return this;
|
||||
}));
|
||||
}
|
||||
|
||||
dispatchUpdateEvent () {
|
||||
this.dispatchEvent(new CustomEvent('update', { 'detail': this.model.changed }));
|
||||
}
|
||||
|
||||
changeChatStateFilter (ev) {
|
||||
@ -96,7 +97,7 @@ export class RosterFilterView extends ElementView {
|
||||
}
|
||||
|
||||
shouldBeVisible () {
|
||||
return _converse.roster && _converse.roster.length >= 5 || this.isActive();
|
||||
return _converse.roster?.length >= 5 || this.isActive();
|
||||
}
|
||||
|
||||
clearFilter (ev) {
|
||||
|
@ -1,9 +1,7 @@
|
||||
import debounce from 'lodash-es/debounce';
|
||||
import tpl_roster from "./templates/roster.js";
|
||||
import { ElementView } from "@converse/skeletor/src/element";
|
||||
import { CustomElement } from 'shared/components/element.js';
|
||||
import { Model } from '@converse/skeletor/src/model.js';
|
||||
import { _converse, api } from "@converse/headless/core";
|
||||
import { render } from 'lit';
|
||||
|
||||
|
||||
/**
|
||||
@ -11,21 +9,22 @@ import { render } from 'lit';
|
||||
* @namespace _converse.RosterView
|
||||
* @memberOf _converse
|
||||
*/
|
||||
export default class RosterView extends ElementView {
|
||||
export default class RosterView extends CustomElement {
|
||||
|
||||
constructor () {
|
||||
super();
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
async initialize () {
|
||||
await api.waitUntil('rosterInitialized')
|
||||
this.debouncedRender = debounce(this.render, 100);
|
||||
this.listenTo(_converse, 'rosterContactsFetched', this.render);
|
||||
this.listenTo(_converse.roster, "add", this.debouncedRender);
|
||||
this.listenTo(_converse.roster, "destroy", this.debouncedRender);
|
||||
this.listenTo(_converse.roster, "remove", this.debouncedRender);
|
||||
this.listenTo(_converse.roster, 'change', this.renderIfRelevantChange);
|
||||
this.listenTo(_converse.roster.state, "change", this.render);
|
||||
_converse.presences.on('change:show', () => this.debouncedRender());
|
||||
|
||||
this.render();
|
||||
this.listenToRosterFilter();
|
||||
this.listenTo(_converse, 'rosterContactsFetched', this.requestUpdate);
|
||||
this.listenTo(_converse.presences, 'change:show', this.requestUpdate);
|
||||
this.listenTo(_converse.roster, 'add', this.requestUpdate);
|
||||
this.listenTo(_converse.roster, 'destroy', this.requestUpdate);
|
||||
this.listenTo(_converse.roster, 'remove', this.requestUpdate);
|
||||
this.listenTo(_converse.roster, 'change', this.requestUpdate);
|
||||
this.listenTo(_converse.roster.state, 'change', this.requestUpdate);
|
||||
/**
|
||||
* Triggered once the _converse.RosterView instance has been created and initialized.
|
||||
* @event _converse#rosterViewInitialized
|
||||
@ -34,21 +33,17 @@ export default class RosterView extends ElementView {
|
||||
api.trigger('rosterViewInitialized');
|
||||
}
|
||||
|
||||
render () {
|
||||
render(tpl_roster(this), this);
|
||||
firstUpdated () {
|
||||
this.listenToRosterFilter();
|
||||
}
|
||||
|
||||
renderIfRelevantChange (model) {
|
||||
const attrs = ['ask', 'requesting', 'groups', 'num_unread'];
|
||||
const changed = model.changed || {};
|
||||
if (Object.keys(changed).filter(m => attrs.includes(m)).length) {
|
||||
this.render();
|
||||
}
|
||||
render () {
|
||||
return tpl_roster(this);
|
||||
}
|
||||
|
||||
listenToRosterFilter () {
|
||||
this.filter_view = this.querySelector('converse-roster-filter');
|
||||
this.filter_view.addEventListener('update', () => this.render());
|
||||
this.filter_view.addEventListener('update', () => this.requestUpdate());
|
||||
}
|
||||
|
||||
showAddContactModal (ev) { // eslint-disable-line class-methods-use-this
|
||||
@ -58,14 +53,14 @@ export default class RosterView extends ElementView {
|
||||
async syncContacts (ev) { // eslint-disable-line class-methods-use-this
|
||||
ev.preventDefault();
|
||||
this.syncing_contacts = true;
|
||||
this.render();
|
||||
this.requestUpdate();
|
||||
|
||||
_converse.roster.data.save('version', null);
|
||||
await _converse.roster.fetchFromServer();
|
||||
api.user.presence.send();
|
||||
|
||||
this.syncing_contacts = false;
|
||||
this.render();
|
||||
this.requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ describe("The Protocol", function () {
|
||||
stanza = $iq({'type': 'result', 'id': roster_fetch_stanza.getAttribute('id')});
|
||||
_converse.connection._dataRecv(mock.createRequest(stanza));
|
||||
|
||||
await u.waitUntil(() => _converse.roster.create.calls.count());
|
||||
await u.waitUntil(() => _converse.roster.create.calls.count(), 1000);
|
||||
|
||||
// A contact should now have been created
|
||||
expect(_converse.roster.get('contact@example.org') instanceof _converse.RosterContact).toBeTruthy();
|
||||
@ -206,7 +206,7 @@ describe("The Protocol", function () {
|
||||
// contact in the roster.
|
||||
await u.waitUntil(() => {
|
||||
const header = sizzle('a:contains("Pending contacts")', rosterview).pop();
|
||||
const contacts = Array.from(header.parentElement.querySelectorAll('li')).filter(u.isVisible);
|
||||
const contacts = Array.from(header?.parentElement.querySelectorAll('li') ?? []).filter(u.isVisible);
|
||||
return contacts.length;
|
||||
}, 600);
|
||||
|
||||
@ -286,7 +286,8 @@ describe("The Protocol", function () {
|
||||
expect(u.hasClass('to', contacts[0])).toBeTruthy();
|
||||
expect(u.hasClass('both', contacts[0])).toBeFalsy();
|
||||
expect(u.hasClass('current-xmpp-contact', contacts[0])).toBeTruthy();
|
||||
expect(contacts[0].textContent.trim()).toBe('Nicky');
|
||||
|
||||
await u.waitUntil(() => contacts[0].textContent.trim() === 'Nicky');
|
||||
|
||||
expect(contact.presence.get('show')).toBe('offline');
|
||||
|
||||
|
@ -139,7 +139,6 @@ describe("The Contacts Roster", function () {
|
||||
const rosterview = document.querySelector('converse-roster');
|
||||
const filter = rosterview.querySelector('.roster-filter');
|
||||
const roster = rosterview.querySelector('.roster-contacts');
|
||||
rosterview.filter_view.delegateEvents();
|
||||
|
||||
await u.waitUntil(() => (sizzle('li', roster).filter(u.isVisible).length === 17), 800);
|
||||
filter.value = "la";
|
||||
@ -251,7 +250,6 @@ describe("The Contacts Roster", function () {
|
||||
await mock.openControlBox(_converse);
|
||||
await mock.waitForRoster(_converse, 'current');
|
||||
const rosterview = document.querySelector('converse-roster');
|
||||
rosterview.filter_view.delegateEvents();
|
||||
const roster = rosterview.querySelector('.roster-contacts');
|
||||
|
||||
const button = rosterview.querySelector('span[data-type="groups"]');
|
||||
@ -299,7 +297,7 @@ describe("The Contacts Roster", function () {
|
||||
const isHidden = (el) => u.hasClass('hidden', el);
|
||||
await u.waitUntil(() => !isHidden(rosterview.querySelector('.roster-filter-form .clear-input')), 900);
|
||||
rosterview.querySelector('.clear-input').click();
|
||||
expect(document.querySelector('.roster-filter').value).toBe("");
|
||||
await u.waitUntil(() => document.querySelector('.roster-filter').value == '');
|
||||
}));
|
||||
|
||||
// Disabling for now, because since recently this test consistently
|
||||
@ -460,6 +458,7 @@ describe("The Contacts Roster", function () {
|
||||
|
||||
const contact = _converse.roster.get('groupchanger@montague.lit');
|
||||
contact.set({'groups': ['secondgroup']});
|
||||
await u.waitUntil(() => sizzle('.roster-group[data-group="secondgroup"] a.group-toggle', rosterview).length);
|
||||
group_titles = await u.waitUntil(() => {
|
||||
const toggles = sizzle('.roster-group[data-group="secondgroup"] a.group-toggle', rosterview);
|
||||
if (toggles.reduce((result, t) => result && u.isVisible(t), true)) {
|
||||
@ -688,8 +687,12 @@ describe("The Contacts Roster", function () {
|
||||
// Check that they are sorted alphabetically
|
||||
const el = await u.waitUntil(() => rosterview.querySelector(`ul[data-group="Pending contacts"]`));
|
||||
const spans = el.querySelectorAll('.pending-xmpp-contact span');
|
||||
const t = Array.from(spans).reduce((result, value) => result + value.textContent?.trim(), '');
|
||||
expect(t).toEqual(mock.pend_names.slice(0,i+1).sort().join(''));
|
||||
|
||||
await u.waitUntil(
|
||||
() => Array.from(spans).reduce((result, value) => result + value.textContent?.trim(), '') ===
|
||||
mock.pend_names.slice(0,i+1).sort().join('')
|
||||
);
|
||||
expect(true).toBe(true);
|
||||
}));
|
||||
});
|
||||
|
||||
@ -729,8 +732,8 @@ describe("The Contacts Roster", function () {
|
||||
requesting: false,
|
||||
subscription: 'both'
|
||||
});
|
||||
const el = rosterview.querySelector(`ul[data-group="My contacts"]`);
|
||||
expect(u.hasClass('collapsed', el)).toBe(true);
|
||||
await u.waitUntil(() => u.hasClass('collapsed', rosterview.querySelector(`ul[data-group="My contacts"]`)) === true);
|
||||
expect(true).toBe(true);
|
||||
}));
|
||||
|
||||
it("can be added to the roster and they will be sorted alphabetically",
|
||||
|
Loading…
Reference in New Issue
Block a user