diff --git a/package-lock.json b/package-lock.json index ab67d2d1e..2bf36f649 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13380,9 +13380,9 @@ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash-es": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", - "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.20.tgz", + "integrity": "sha512-JD1COMZsq8maT6mnuz1UMV0jvYD0E0aUsSOdrr1/nAG3dhqQXwRRgeW0cSqH1U43INKcqxaiVIQNOUDld7gRDA==" }, "lodash-template-webpack-loader": { "version": "github:jcbrand/lodash-template-webpack-loader#258c095ab22130dfde454fa59ee0986f302bb733", diff --git a/package.json b/package.json index 718a31337..5736bcb84 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "devDependencies": { "@babel/cli": "^7.10.3", "@babel/core": "^7.10.5", + "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1", "@babel/plugin-proposal-optional-chaining": "^7.12.1", "@babel/plugin-syntax-dynamic-import": "^7.2.0", diff --git a/src/plugins/rosterview/filterview.js b/src/plugins/rosterview/filterview.js index a0f830845..b7c7af44b 100644 --- a/src/plugins/rosterview/filterview.js +++ b/src/plugins/rosterview/filterview.js @@ -1,9 +1,9 @@ import tpl_roster_filter from "./templates/roster_filter.js"; +import { ElementView } from '@converse/skeletor/src/element.js'; import { Model } from '@converse/skeletor/src/model.js'; -import { View } from '@converse/skeletor/src/view.js'; -import { __ } from 'i18n'; -import { _converse } from "@converse/headless/core"; +import { _converse, api } from "@converse/headless/core"; import { debounce } from "lodash-es"; +import { render } from 'lit-html'; export const RosterFilter = Model.extend({ @@ -17,42 +17,49 @@ export const RosterFilter = Model.extend({ }); -export const RosterFilterView = View.extend({ - tagName: 'span', +export class RosterFilterView extends ElementView { + tagName = 'span'; initialize () { + const model = new _converse.RosterFilter(); + model.id = `_converse.rosterfilter-${_converse.bare_jid}`; + model.browserStorage = _converse.createStore(model.id); + this.model = model; + + this.liveFilter = debounce(() => { + this.model.save({'filter_text': this.querySelector('.roster-filter').value}); + }, 250); + this.listenTo(this.model, 'change:filter_type', this.render); this.listenTo(this.model, 'change:filter_text', this.render); - }, - toHTML () { - return tpl_roster_filter( + 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); + api.listen.on('rosterContactsFetchedAndProcessed', () => this.render()); + + this.model.fetch(); + this.render(); + } + + render () { + render(tpl_roster_filter( Object.assign(this.model.toJSON(), { visible: this.shouldBeVisible(), - placeholder: __('Filter'), - title_contact_filter: __('Filter by contact name'), - title_group_filter: __('Filter by group name'), - title_status_filter: __('Filter by status'), - label_any: __('Any'), - label_unread_messages: __('Unread'), - label_online: __('Online'), - label_chatty: __('Chatty'), - label_busy: __('Busy'), - label_away: __('Away'), - label_xa: __('Extended Away'), - label_offline: __('Offline'), changeChatStateFilter: ev => this.changeChatStateFilter(ev), changeTypeFilter: ev => this.changeTypeFilter(ev), clearFilter: ev => this.clearFilter(ev), liveFilter: ev => this.liveFilter(ev), submitFilter: ev => this.submitFilter(ev), - })); - }, + })), this); + return this; + } changeChatStateFilter (ev) { ev && ev.preventDefault(); - this.model.save({'chat_state': this.el.querySelector('.state-type').value}); - }, + this.model.save({'chat_state': this.querySelector('.state-type').value}); + } changeTypeFilter (ev) { ev && ev.preventDefault(); @@ -60,24 +67,20 @@ export const RosterFilterView = View.extend({ if (type === 'state') { this.model.save({ 'filter_type': type, - 'chat_state': this.el.querySelector('.state-type').value + 'chat_state': this.querySelector('.state-type').value }); } else { this.model.save({ 'filter_type': type, - 'filter_text': this.el.querySelector('.roster-filter').value + 'filter_text': this.querySelector('.roster-filter').value }); } - }, - - liveFilter: debounce(function () { - this.model.save({'filter_text': this.el.querySelector('.roster-filter').value}); - }, 250), + } submitFilter (ev) { ev && ev.preventDefault(); this.liveFilter(); - }, + } /** * Returns true if the filter is enabled (i.e. if the user @@ -87,14 +90,17 @@ export const RosterFilterView = View.extend({ */ isActive () { return (this.model.get('filter_type') === 'state' || this.model.get('filter_text')); - }, + } shouldBeVisible () { return _converse.roster && _converse.roster.length >= 5 || this.isActive(); - }, + } clearFilter (ev) { ev && ev.preventDefault(); this.model.save({'filter_text': ''}); } -}); +} + + +api.elements.define('converse-roster-filter', RosterFilterView); diff --git a/src/plugins/rosterview/groupview.js b/src/plugins/rosterview/groupview.js index e3e3be27d..0f5b89193 100644 --- a/src/plugins/rosterview/groupview.js +++ b/src/plugins/rosterview/groupview.js @@ -1,7 +1,7 @@ import RosterContactView from './contactview.js'; import tpl_group_header from "./templates/group_header.html"; import { OrderedListView } from "@converse/skeletor/src/overview"; -import { _converse, converse } from "@converse/headless/core"; +import { _converse, api, converse } from "@converse/headless/core"; const u = converse.env.utils; @@ -49,10 +49,7 @@ const RosterGroupView = OrderedListView.extend({ // just this group's) have been fetched from browser // storage or the XMPP server and once they've been // assigned to their various groups. - _converse.rosterview.on( - 'rosterContactsFetchedAndProcessed', - () => this.sortAndPositionAllItems() - ); + api.listen.on('rosterContactsFetchedAndProcessed', () => this.sortAndPositionAllItems()); }, render () { diff --git a/src/plugins/rosterview/index.js b/src/plugins/rosterview/index.js index 9c91d900f..fb5580542 100644 --- a/src/plugins/rosterview/index.js +++ b/src/plugins/rosterview/index.js @@ -10,7 +10,7 @@ import "modals/add-contact.js"; import RosterContactView from './contactview.js'; import RosterGroupView from './groupview.js'; import RosterView from './rosterview.js'; -import log from "@converse/headless/log"; +import { initRosterView, highlightRosterItem, insertRoster } from './utils.js'; import { RosterFilter, RosterFilterView } from './filterview.js'; import { _converse, api, converse } from "@converse/headless/core"; @@ -20,10 +20,6 @@ converse.plugins.add('converse-rosterview', { dependencies: ["converse-roster", "converse-modal", "converse-chatboxviews"], initialize () { - /* The initialize function gets called as soon as the plugin is - * loaded by converse.js's plugin machinery. - */ - api.settings.extend({ 'autocomplete_add_contact': true, 'allow_chat_pending_contacts': true, @@ -42,50 +38,15 @@ converse.plugins.add('converse-rosterview', { /* -------- Event Handlers ----------- */ api.listen.on('chatBoxesInitialized', () => { - function highlightRosterItem (chatbox) { - const contact = _converse.roster && _converse.roster.findWhere({'jid': chatbox.get('jid')}); - if (contact !== undefined) { - contact.trigger('highlight'); - } - } _converse.chatboxes.on('destroy', chatbox => highlightRosterItem(chatbox)); _converse.chatboxes.on('change:hidden', chatbox => highlightRosterItem(chatbox)); }); - api.listen.on('controlBoxInitialized', (view) => { - function insertRoster () { - if (!view.model.get('connected') || api.settings.get("authentication") === _converse.ANONYMOUS) { - return; - } - /* Place the rosterview inside the "Contacts" panel. */ - api.waitUntil('rosterViewInitialized') - .then(() => view.controlbox_pane.el.insertAdjacentElement('beforeEnd', _converse.rosterview.el)) - .catch(e => log.fatal(e)); - } - insertRoster(); - view.model.on('change:connected', insertRoster); + insertRoster(view); + view.model.on('change:connected', () => insertRoster(view)); }); - - function initRosterView () { - /* Create an instance of RosterView once the RosterGroups - * collection has been created (in @converse/headless/core.js) - */ - if (api.settings.get("authentication") === _converse.ANONYMOUS) { - return; - } - _converse.rosterview = new _converse.RosterView({ - 'model': _converse.rostergroups - }); - _converse.rosterview.render(); - /** - * Triggered once the _converse.RosterView instance has been created and initialized. - * @event _converse#rosterViewInitialized - * @example _converse.api.listen.on('rosterViewInitialized', () => { ... }); - */ - api.trigger('rosterViewInitialized'); - } api.listen.on('rosterInitialized', initRosterView); api.listen.on('rosterReadyAfterReconnection', initRosterView); diff --git a/src/plugins/rosterview/rosterview.js b/src/plugins/rosterview/rosterview.js index a1596fa37..56a6f84f9 100644 --- a/src/plugins/rosterview/rosterview.js +++ b/src/plugins/rosterview/rosterview.js @@ -1,11 +1,12 @@ import RosterGroupView from './groupview.js'; import log from "@converse/headless/log"; -import tpl_roster from "./templates/roster.html"; +import tpl_roster from "./templates/roster.js"; import { Model } from '@converse/skeletor/src/model.js'; import { OrderedListView } from "@converse/skeletor/src/overview"; import { __ } from 'i18n'; import { _converse, api, converse } from "@converse/headless/core"; import { debounce, has } from "lodash-es"; +import { render } from 'lit-html'; const u = converse.env.utils; @@ -57,20 +58,18 @@ const RosterView = OrderedListView.extend({ _converse.roster.each(contact => this.addRosterContact(contact, {'silent': true})); this.update(); this.updateFilter(); - this.trigger('rosterContactsFetchedAndProcessed'); + api.trigger('rosterContactsFetchedAndProcessed'); }); - this.createRosterFilter(); + this.render(); + this.listenToRosterFilter(); }, render () { - this.el.innerHTML = tpl_roster({ - 'allow_contact_requests': _converse.allow_contact_requests, + render(tpl_roster({ 'heading_contacts': __('Contacts'), 'title_add_contact': __('Add a contact'), 'title_sync_contacts': __('Re-sync your contacts') - }); - const form = this.el.querySelector('.roster-filter-form'); - this.el.replaceChild(this.filter_view.render().el, form); + }), this.el); this.roster_el = this.el.querySelector('.roster-contacts'); return this; }, @@ -79,14 +78,9 @@ const RosterView = OrderedListView.extend({ api.modal.show(_converse.AddContactModal, {'model': new Model()}, ev); }, - createRosterFilter () { - // Create a model on which we can store filter properties - const model = new _converse.RosterFilter(); - model.id = `_converse.rosterfilter-${_converse.bare_jid}`; - model.browserStorage = _converse.createStore(model.id); - this.filter_view = new _converse.RosterFilterView({model}); + listenToRosterFilter () { + this.filter_view = this.el.querySelector('converse-roster-filter'); this.listenTo(this.filter_view.model, 'change', this.updateFilter); - this.filter_view.model.fetch(); }, /** @@ -109,7 +103,7 @@ const RosterView = OrderedListView.extend({ if (!u.isVisible(this.roster_el)) { u.showElement(this.roster_el); } - this.filter_view.render(); + // this.filter_view.render(); return this; }, @@ -217,7 +211,7 @@ const RosterView = OrderedListView.extend({ if (contact.get('subscription') === 'both' || contact.get('subscription') === 'to' || this.isSelf(jid)) { this.addExistingContact(contact, options); } else { - if (!_converse.allow_contact_requests) { + if (!api.settings.get('allow_contact_requests')) { log.debug( `Not adding requesting or pending contact ${jid} `+ `because allow_contact_requests is false` diff --git a/src/plugins/rosterview/templates/roster.html b/src/plugins/rosterview/templates/roster.html deleted file mode 100644 index 730418848..000000000 --- a/src/plugins/rosterview/templates/roster.html +++ /dev/null @@ -1,14 +0,0 @@ -
- - - - diff --git a/src/plugins/rosterview/templates/roster.js b/src/plugins/rosterview/templates/roster.js new file mode 100644 index 000000000..34c45a0c0 --- /dev/null +++ b/src/plugins/rosterview/templates/roster.js @@ -0,0 +1,16 @@ +import { html } from "lit-html"; +import { api } from "@converse/headless/core"; + +export default (o) => html` + +