Replace roster filter VDOMView with HTMLView

This commit is contained in:
JC Brand 2020-01-30 12:03:28 +01:00
parent 39f189b1d1
commit 8b5227761e
3 changed files with 60 additions and 96 deletions

View File

@ -3,12 +3,12 @@
* @copyright 2020, the Converse.js contributors * @copyright 2020, the Converse.js contributors
* @license Mozilla Public License (MPLv2) * @license Mozilla Public License (MPLv2)
*/ */
import "backbone.vdomview";
import "@converse/headless/converse-chatboxes"; import "@converse/headless/converse-chatboxes";
import "@converse/headless/converse-roster"; import "@converse/headless/converse-roster";
import "converse-modal"; import "converse-modal";
import "formdata-polyfill"; import "formdata-polyfill";
import { compact, debounce, has, isString, uniq, without } from "lodash"; import { compact, debounce, has, isString, uniq, without } from "lodash";
import { HTMLView } from 'skeletor.js/src/htmlview.js';
import { Model } from 'skeletor.js/src/model.js'; import { Model } from 'skeletor.js/src/model.js';
import { OrderedListView } from "skeletor.js/src/overview"; import { OrderedListView } from "skeletor.js/src/overview";
import SHA1 from 'strophe.js/src/sha1'; import SHA1 from 'strophe.js/src/sha1';
@ -19,10 +19,10 @@ import tpl_group_header from "templates/group_header.html";
import tpl_pending_contact from "templates/pending_contact.html"; import tpl_pending_contact from "templates/pending_contact.html";
import tpl_requesting_contact from "templates/requesting_contact.html"; import tpl_requesting_contact from "templates/requesting_contact.html";
import tpl_roster from "templates/roster.html"; import tpl_roster from "templates/roster.html";
import tpl_roster_filter from "templates/roster_filter.html"; import tpl_roster_filter from "templates/roster_filter.js";
import tpl_roster_item from "templates/roster_item.html"; import tpl_roster_item from "templates/roster_item.html";
const { Backbone, Strophe } = converse.env; const { Strophe } = converse.env;
const u = converse.env.utils; const u = converse.env.utils;
@ -201,16 +201,8 @@ converse.plugins.add('converse-rosterview', {
}, },
}); });
_converse.RosterFilterView = Backbone.VDOMView.extend({ _converse.RosterFilterView = HTMLView.extend({
tagName: 'form', tagName: 'span',
className: 'roster-filter-form',
events: {
"keydown .roster-filter": "liveFilter",
"submit": "submitFilter",
"click .clear-input": "clearFilter",
"click .filter-by span": "changeTypeFilter",
"change .state-type": "changeChatStateFilter"
},
initialize () { initialize () {
this.listenTo(this.model, 'change:filter_type', this.render); this.listenTo(this.model, 'change:filter_type', this.render);
@ -232,17 +224,22 @@ converse.plugins.add('converse-rosterview', {
label_busy: __('Busy'), label_busy: __('Busy'),
label_away: __('Away'), label_away: __('Away'),
label_xa: __('Extended Away'), label_xa: __('Extended Away'),
label_offline: __('Offline') 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),
})); }));
}, },
changeChatStateFilter (ev) { changeChatStateFilter (ev) {
if (ev && ev.preventDefault) { ev.preventDefault(); } ev && ev.preventDefault();
this.model.save({'chat_state': this.el.querySelector('.state-type').value}); this.model.save({'chat_state': this.el.querySelector('.state-type').value});
}, },
changeTypeFilter (ev) { changeTypeFilter (ev) {
if (ev && ev.preventDefault) { ev.preventDefault(); } ev && ev.preventDefault();
const type = ev.target.dataset.type; const type = ev.target.dataset.type;
if (type === 'state') { if (type === 'state') {
this.model.save({ this.model.save({
@ -258,64 +255,30 @@ converse.plugins.add('converse-rosterview', {
}, },
liveFilter: debounce(function () { liveFilter: debounce(function () {
this.model.save({ this.model.save({'filter_text': this.el.querySelector('.roster-filter').value});
'filter_text': this.el.querySelector('.roster-filter').value
});
}, 250), }, 250),
submitFilter (ev) { submitFilter (ev) {
if (ev && ev.preventDefault) { ev.preventDefault(); } ev && ev.preventDefault();
this.liveFilter(); this.liveFilter();
this.render();
}, },
/**
* Returns true if the filter is enabled (i.e. if the user
* has added values to the filter).
* @private
* @method _converse.RosterFilterView#isActive
*/
isActive () { isActive () {
/* Returns true if the filter is enabled (i.e. if the user return (this.model.get('filter_type') === 'state' || this.model.get('filter_text'));
* has added values to the filter).
*/
if (this.model.get('filter_type') === 'state' ||
this.model.get('filter_text')) {
return true;
}
return false;
}, },
shouldBeVisible () { shouldBeVisible () {
return _converse.roster && _converse.roster.length >= 5 || this.isActive(); return _converse.roster && _converse.roster.length >= 5 || this.isActive();
}, },
showOrHide () {
if (this.shouldBeVisible()) {
this.show();
} else {
this.hide();
}
},
show () {
if (u.isVisible(this.el)) { return this; }
this.el.classList.add('fade-in');
this.el.classList.remove('hidden');
return this;
},
hide () {
if (!u.isVisible(this.el)) { return this; }
this.model.save({
'filter_text': '',
'chat_state': 'online'
});
this.el.classList.add('hidden');
return this;
},
clearFilter (ev) { clearFilter (ev) {
if (ev && ev.preventDefault) { ev && ev.preventDefault();
ev.preventDefault();
u.hideElement(this.el.querySelector('.clear-input'));
}
const roster_filter = this.el.querySelector('.roster-filter');
roster_filter.value = '';
this.model.save({'filter_text': ''}); this.model.save({'filter_text': ''});
} }
}); });
@ -819,7 +782,7 @@ converse.plugins.add('converse-rosterview', {
const model = new _converse.RosterFilter(); const model = new _converse.RosterFilter();
model.id = `_converse.rosterfilter-${_converse.bare_jid}`; model.id = `_converse.rosterfilter-${_converse.bare_jid}`;
model.browserStorage = _converse.createStore(model.id); model.browserStorage = _converse.createStore(model.id);
this.filter_view = new _converse.RosterFilterView({'model': model}); this.filter_view = new _converse.RosterFilterView({model});
this.listenTo(this.filter_view.model, 'change', this.updateFilter); this.listenTo(this.filter_view.model, 'change', this.updateFilter);
this.filter_view.model.fetch(); this.filter_view.model.fetch();
}, },
@ -844,7 +807,7 @@ converse.plugins.add('converse-rosterview', {
if (!u.isVisible(this.roster_el)) { if (!u.isVisible(this.roster_el)) {
u.showElement(this.roster_el); u.showElement(this.roster_el);
} }
this.filter_view.showOrHide(); this.filter_view.render();
return this; return this;
}, },

View File

@ -1,34 +0,0 @@
<form class="controlbox-padded roster-filter-form input-button-group {[ if (!o.visible) { ]} hidden {[ } ]}">
<div class="form-inline flex-nowrap">
<div class="filter-by d-flex flex-nowrap">
<span class="fa fa-user {[ if (o.filter_type === 'contacts') { ]} selected {[ } ]}" data-type="contacts" title="{{{o.title_contact_filter}}}"></span>
<span class="fa fa-users {[ if (o.filter_type === 'groups') { ]} selected {[ } ]}" data-type="groups" title="{{{o.title_group_filter}}}"></span>
<span class="fa fa-circle {[ if (o.filter_type === 'state') { ]} selected {[ } ]}" data-type="state" title="{{{o.title_status_filter}}}"></span>
</div>
<div class="btn-group">
<input {[ if (o.filter_text) { ]} value="{{{o.filter_text}}}" {[ } ]}
class="roster-filter form-control {[ if (o.filter_type === 'state') { ]} hidden {[ } ]}"
placeholder="{{{o.placeholder}}}"/>
<span class="clear-input fa fa-times {[ if (!o.filter_text || o.filter_type === 'state') { ]} hidden {[ } ]}"></span>
</div>
<select class="form-control state-type {[ if (o.filter_type !== 'state') { ]} hidden {[ } ]}">
<option value="">{{{o.label_any}}}</option>
<option {[ if (o.chat_state === 'unread_messages') { ]} selected="selected" {[ } ]}
value="unread_messages">{{{o.label_unread_messages}}}</option>
<option {[ if (o.chat_state === 'online') { ]} selected="selected" {[ } ]}
value="online">{{{o.label_online}}}</option>
<option {[ if (o.chat_state === 'chat') { ]} selected="selected" {[ } ]}
value="chat">{{{o.label_chatty}}}</option>
<option {[ if (o.chat_state === 'dnd') { ]} selected="selected" {[ } ]}
value="dnd">{{{o.label_busy}}}</option>
<option {[ if (o.chat_state === 'away') { ]} selected="selected" {[ } ]}
value="away">{{{o.label_away}}}</option>
<option {[ if (o.chat_state === 'xa') { ]} selected="selected" {[ } ]}
value="xa">{{{o.label_xa}}}</option>
<option {[ if (o.chat_state === 'offline') { ]} selected="selected" {[ } ]}
value="offline">{{{o.label_offline}}}</option>
</select>
</div>
</form>

View File

@ -0,0 +1,35 @@
import { html } from "lit-html";
export default (o) => html`
<form class="controlbox-padded roster-filter-form input-button-group ${ (!o.visible) ? 'hidden' : 'fade-in' }"
@submit=${o.submitFilter}>
<div class="form-inline flex-nowrap">
<div class="filter-by d-flex flex-nowrap">
<span @click=${o.changeTypeFilter} class="fa fa-user ${ (o.filter_type === 'contacts') ? 'selected' : '' }" data-type="contacts" title="${o.title_contact_filter}"></span>
<span @click=${o.changeTypeFilter} class="fa fa-users ${ (o.filter_type === 'groups') ? 'selected' : '' }" data-type="groups" title="${o.title_group_filter}"></span>
<span @click=${o.changeTypeFilter} class="fa fa-circle ${ (o.filter_type === 'state') ? 'selected' : '' }" data-type="state" title="${o.title_status_filter}"></span>
</div>
<div class="btn-group">
<input .value="${o.filter_text || ''}"
@keydown=${o.liveFilter}
class="roster-filter form-control ${ (o.filter_type === 'state') ? 'hidden' : '' }"
placeholder="${o.placeholder}"/>
<span class="clear-input fa fa-times ${ (!o.filter_text || o.filter_type === 'state') ? 'hidden' : '' }"
@click=${o.clearFilter}>
</span>
</div>
<select class="form-control state-type ${ (o.filter_type !== 'state') ? 'hidden' : '' }"
@change=${o.changeChatStateFilter}>
<option value="">${o.label_any}</option>
<option ?selected=${o.chat_state === 'unread_messages'} value="unread_messages">${o.label_unread_messages}</option>
<option ?selected=${o.chat_state === 'online'} value="online">${o.label_online}</option>
<option ?selected=${o.chat_state === 'chat'} value="chat">${o.label_chatty}</option>
<option ?selected=${o.chat_state === 'dnd'} value="dnd">${o.label_busy}</option>
<option ?selected=${o.chat_state === 'away'} value="away">${o.label_away}</option>
<option ?selected=${o.chat_state === 'xa'} value="xa">${o.label_xa}</option>
<option ?selected=${o.chat_state === 'offline'} value="offline">${o.label_offline}</option>
</select>
</div>
</form>
`;