Commit 75ae76ad authored by JC Brand's avatar JC Brand

Use `_converse.AutoComplete` in "Add Contact" modal

parent f0848c28
...@@ -12198,14 +12198,14 @@ body.converse-fullscreen { ...@@ -12198,14 +12198,14 @@ body.converse-fullscreen {
display: none; } display: none; }
#conversejs .suggestion-box .suggestion-box__results--above:after, #conversejs .suggestion-box .suggestion-box__results--above:after,
#conversejs .awesomplete .suggestion-box__results--above:after { #conversejs .awesomplete .suggestion-box__results--above:after {
z-index: 1; z-index: -1;
content: ""; content: "";
position: absolute; position: absolute;
bottom: -.43em; bottom: -0.43em;
left: 1em; left: 1em;
width: 0; width: 0;
height: 0; height: 0;
padding: .4em; padding: 0.4em;
background: white; background: white;
border: inherit; border: inherit;
border-left: 0; border-left: 0;
...@@ -12252,7 +12252,7 @@ body.converse-fullscreen { ...@@ -12252,7 +12252,7 @@ body.converse-fullscreen {
bottom: 4.5em; } bottom: 4.5em; }
#conversejs.converse-overlayed .suggestion-box__results--above { #conversejs.converse-overlayed .suggestion-box__results--above {
bottom: 5.5em; } bottom: 3.5em; }
#conversejs.converse-embedded { #conversejs.converse-embedded {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
......
...@@ -48035,6 +48035,34 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -48035,6 +48035,34 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
return element; return element;
}; };
class Suggestion extends String {
constructor(data) {
super();
const o = Array.isArray(data) ? {
label: data[0],
value: data[1]
} : typeof data === "object" && "label" in data && "value" in data ? data : {
label: data,
value: data
};
this.label = o.label || o.value;
this.value = o.value;
}
get lenth() {
return this.label.length;
}
toString() {
return "" + this.label;
}
valueOf() {
return this.toString();
}
}
class AutoComplete { class AutoComplete {
constructor(el) { constructor(el) {
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
...@@ -48062,6 +48090,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -48062,6 +48090,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
'min_chars': 2, 'min_chars': 2,
'max_items': 10, 'max_items': 10,
'auto_evaluate': true, 'auto_evaluate': true,
// Should evaluation happen automatically without any particular key as trigger?
'auto_first': false, 'auto_first': false,
// Should the first element be automatically selected? // Should the first element be automatically selected?
'data': _.identity, 'data': _.identity,
...@@ -48121,7 +48150,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -48121,7 +48150,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
if (list && list.children) { if (list && list.children) {
const items = []; const items = [];
slice.apply(list.children).forEach(function (el) { Array.prototype.slice.apply(list.children).forEach(function (el) {
if (!el.disabled) { if (!el.disabled) {
const text = el.textContent.trim(), const text = el.textContent.trim(),
value = el.value || text, value = el.value || text,
...@@ -48230,7 +48259,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -48230,7 +48259,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
} }
} }
select(selected, origin) { select(selected) {
if (selected) { if (selected) {
this.index = u.siblingIndex(selected); this.index = u.siblingIndex(selected);
} else { } else {
...@@ -48311,9 +48340,9 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -48311,9 +48340,9 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
} }
evaluate(ev) { evaluate(ev) {
const arrow_pressed = ev.keyCode === _converse.keycodes.UP_ARROW || ev.keyCode === _converse.keycodes.DOWN_ARROW; const selecting = this.selected && ev && (ev.keyCode === _converse.keycodes.UP_ARROW || ev.keyCode === _converse.keycodes.DOWN_ARROW);
if (!this.auto_completing || this.selected && arrow_pressed) { if (!this.auto_evaluate && !this.auto_completing || selecting) {
return; return;
} }
...@@ -48362,33 +48391,8 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins ...@@ -48362,33 +48391,8 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_0__["default"].plugins
} // Make it an event emitter } // Make it an event emitter
_.extend(AutoComplete.prototype, Backbone.Events); // Private functions _.extend(AutoComplete.prototype, Backbone.Events);
function Suggestion(data) {
const o = Array.isArray(data) ? {
label: data[0],
value: data[1]
} : typeof data === "object" && "label" in data && "value" in data ? data : {
label: data,
value: data
};
this.label = o.label || o.value;
this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
get: function get() {
return this.label.length;
}
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
return "" + this.label;
}; // Helpers
var slice = Array.prototype.slice;
const helpers = { const helpers = {
getElement(expr, el) { getElement(expr, el) {
return typeof expr === "string" ? (el || document).querySelector(expr) : expr || null; return typeof expr === "string" ? (el || document).querySelector(expr) : expr || null;
...@@ -52193,7 +52197,7 @@ __webpack_require__.r(__webpack_exports__); ...@@ -52193,7 +52197,7 @@ __webpack_require__.r(__webpack_exports__);
// Converse.js (A browser based XMPP chat client) // Converse.js (A browser based XMPP chat client)
// https://conversejs.org // https://conversejs.org
// //
// Copyright (c) 2012-2017, Jan-Carel Brand <jc@opkode.com> // Copyright (c) 2019, Jan-Carel Brand <jc@opkode.com>
// Licensed under the Mozilla Public License (MPLv2) // Licensed under the Mozilla Public License (MPLv2)
...@@ -59435,27 +59439,25 @@ __webpack_require__.r(__webpack_exports__); ...@@ -59435,27 +59439,25 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _converse_headless_converse_roster__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @converse/headless/converse-roster */ "./src/headless/converse-roster.js"); /* harmony import */ var _converse_headless_converse_roster__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @converse/headless/converse-roster */ "./src/headless/converse-roster.js");
/* harmony import */ var _converse_headless_converse_chatboxes__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @converse/headless/converse-chatboxes */ "./src/headless/converse-chatboxes.js"); /* harmony import */ var _converse_headless_converse_chatboxes__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @converse/headless/converse-chatboxes */ "./src/headless/converse-chatboxes.js");
/* harmony import */ var converse_modal__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! converse-modal */ "./src/converse-modal.js"); /* harmony import */ var converse_modal__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! converse-modal */ "./src/converse-modal.js");
/* harmony import */ var awesomplete__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! awesomplete */ "./node_modules/awesomplete-avoid-xss/awesomplete.js"); /* harmony import */ var formdata_polyfill__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! formdata-polyfill */ "./node_modules/formdata-polyfill/FormData.js");
/* harmony import */ var awesomplete__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(awesomplete__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var formdata_polyfill__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(formdata_polyfill__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var formdata_polyfill__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! formdata-polyfill */ "./node_modules/formdata-polyfill/FormData.js"); /* harmony import */ var _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @converse/headless/converse-core */ "./src/headless/converse-core.js");
/* harmony import */ var formdata_polyfill__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(formdata_polyfill__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! templates/add_contact_modal.html */ "./src/templates/add_contact_modal.html");
/* harmony import */ var _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @converse/headless/converse-core */ "./src/headless/converse-core.js"); /* harmony import */ var templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! templates/add_contact_modal.html */ "./src/templates/add_contact_modal.html"); /* harmony import */ var templates_group_header_html__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! templates/group_header.html */ "./src/templates/group_header.html");
/* harmony import */ var templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_6__); /* harmony import */ var templates_group_header_html__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(templates_group_header_html__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var templates_group_header_html__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! templates/group_header.html */ "./src/templates/group_header.html"); /* harmony import */ var templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! templates/pending_contact.html */ "./src/templates/pending_contact.html");
/* harmony import */ var templates_group_header_html__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(templates_group_header_html__WEBPACK_IMPORTED_MODULE_7__); /* harmony import */ var templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! templates/pending_contact.html */ "./src/templates/pending_contact.html"); /* harmony import */ var templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! templates/requesting_contact.html */ "./src/templates/requesting_contact.html");
/* harmony import */ var templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_8__); /* harmony import */ var templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_8__);
/* harmony import */ var templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! templates/requesting_contact.html */ "./src/templates/requesting_contact.html"); /* harmony import */ var templates_roster_html__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! templates/roster.html */ "./src/templates/roster.html");
/* harmony import */ var templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_9__); /* harmony import */ var templates_roster_html__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(templates_roster_html__WEBPACK_IMPORTED_MODULE_9__);
/* harmony import */ var templates_roster_html__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! templates/roster.html */ "./src/templates/roster.html"); /* harmony import */ var templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! templates/roster_filter.html */ "./src/templates/roster_filter.html");
/* harmony import */ var templates_roster_html__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(templates_roster_html__WEBPACK_IMPORTED_MODULE_10__); /* harmony import */ var templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_10__);
/* harmony import */ var templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! templates/roster_filter.html */ "./src/templates/roster_filter.html"); /* harmony import */ var templates_roster_item_html__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! templates/roster_item.html */ "./src/templates/roster_item.html");
/* harmony import */ var templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_11__); /* harmony import */ var templates_roster_item_html__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(templates_roster_item_html__WEBPACK_IMPORTED_MODULE_11__);
/* harmony import */ var templates_roster_item_html__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! templates/roster_item.html */ "./src/templates/roster_item.html"); /* harmony import */ var templates_search_contact_html__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! templates/search_contact.html */ "./src/templates/search_contact.html");
/* harmony import */ var templates_roster_item_html__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(templates_roster_item_html__WEBPACK_IMPORTED_MODULE_12__); /* harmony import */ var templates_search_contact_html__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(templates_search_contact_html__WEBPACK_IMPORTED_MODULE_12__);
/* harmony import */ var templates_search_contact_html__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! templates/search_contact.html */ "./src/templates/search_contact.html");
/* harmony import */ var templates_search_contact_html__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(templates_search_contact_html__WEBPACK_IMPORTED_MODULE_13__);
// Converse.js // Converse.js
// https://conversejs.org // https://conversejs.org
// //
...@@ -59474,16 +59476,15 @@ __webpack_require__.r(__webpack_exports__); ...@@ -59474,16 +59476,15 @@ __webpack_require__.r(__webpack_exports__);
const _converse$env = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].env,
const _converse$env = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].env,
Backbone = _converse$env.Backbone, Backbone = _converse$env.Backbone,
Strophe = _converse$env.Strophe, Strophe = _converse$env.Strophe,
$iq = _converse$env.$iq, $iq = _converse$env.$iq,
b64_sha1 = _converse$env.b64_sha1, b64_sha1 = _converse$env.b64_sha1,
sizzle = _converse$env.sizzle, sizzle = _converse$env.sizzle,
_ = _converse$env._; _ = _converse$env._;
const u = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].env.utils; const u = _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].env.utils;
_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins.add('converse-rosterview', { _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].plugins.add('converse-rosterview', {
dependencies: ["converse-roster", "converse-modal"], dependencies: ["converse-roster", "converse-modal"],
overrides: { overrides: {
// Overrides mentioned here will be picked up by converse.js's // Overrides mentioned here will be picked up by converse.js's
...@@ -59588,7 +59589,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59588,7 +59589,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
toHTML() { toHTML() {
const label_nickname = _converse.xhr_user_search_url ? __('Contact name') : __('Optional nickname'); const label_nickname = _converse.xhr_user_search_url ? __('Contact name') : __('Optional nickname');
return templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_6___default()(_.extend(this.model.toJSON(), { return templates_add_contact_modal_html__WEBPACK_IMPORTED_MODULE_5___default()(_.extend(this.model.toJSON(), {
'_converse': _converse, '_converse': _converse,
'heading_new_contact': __('Add a Contact'), 'heading_new_contact': __('Add a Contact'),
'label_xmpp_address': __('XMPP Address'), 'label_xmpp_address': __('XMPP Address'),
...@@ -59601,55 +59602,52 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59601,55 +59602,52 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
afterRender() { afterRender() {
if (_converse.xhr_user_search_url && _.isString(_converse.xhr_user_search_url)) { if (_converse.xhr_user_search_url && _.isString(_converse.xhr_user_search_url)) {
this.initXHRAutoComplete(this.el); this.initXHRAutoComplete();
this.el.addEventListener('awesomplete-selectcomplete', ev => { this.name_auto_complete.on('suggestion-box-selectcomplete', ev => {
this.el.querySelector('input[name="name"]').value = ev.text.label; this.el.querySelector('input[name="name"]').value = ev.text.label;
this.el.querySelector('input[name="jid"]').value = ev.text.value; this.el.querySelector('input[name="jid"]').value = ev.text.value;
}); });
} else { } else {
this.initJIDAutoComplete(this.el); this.initJIDAutoComplete();
} }
const jid_input = this.el.querySelector('input[name="jid"]'); const jid_input = this.el.querySelector('input[name="jid"]');
this.el.addEventListener('shown.bs.modal', () => jid_input.focus(), false); this.el.addEventListener('shown.bs.modal', () => jid_input.focus(), false);
}, },
initJIDAutoComplete(root) { initJIDAutoComplete() {
const jid_input = root.querySelector('input[name="jid"]'); const el = this.el.querySelector('.suggestion-box__jid').parentElement;
this.jid_auto_complete = new _converse.AutoComplete(el, {
const list = _.uniq(_converse.roster.map(item => Strophe.getDomainFromJid(item.get('jid'))));
new awesomplete__WEBPACK_IMPORTED_MODULE_3___default.a(jid_input, {
'list': list,
'data': (text, input) => `${input.slice(0, input.indexOf("@"))}@${text}`, 'data': (text, input) => `${input.slice(0, input.indexOf("@"))}@${text}`,
'filter': awesomplete__WEBPACK_IMPORTED_MODULE_3___default.a.FILTER_STARTSWITH 'filter': _converse.FILTER_STARTSWITH,
'list': _.uniq(_converse.roster.map(item => Strophe.getDomainFromJid(item.get('jid'))))
}); });
}, },
initXHRAutoComplete(root) { initXHRAutoComplete() {
const name_input = this.el.querySelector('input[name="name"]'); const el = this.el.querySelector('.suggestion-box__name').parentElement;
const jid_input = this.el.querySelector('input[name="jid"]'); this.name_auto_complete = new _converse.AutoComplete(el, {
const awesomplete = new awesomplete__WEBPACK_IMPORTED_MODULE_3___default.a(name_input, { 'auto_evaluate': false,
'minChars': 1, 'filter': _converse.FILTER_STARTSWITH,
'list': [] 'list': []
}); });
const xhr = new window.XMLHttpRequest(); // `open` must be called after `onload` for mock/testing purposes. const xhr = new window.XMLHttpRequest(); // `open` must be called after `onload` for mock/testing purposes.
xhr.onload = function () { xhr.onload = () => {
if (xhr.responseText) { if (xhr.responseText) {
awesomplete.list = JSON.parse(xhr.responseText).map(i => { const r = xhr.responseText;
//eslint-disable-line arrow-body-style this.name_auto_complete.list = JSON.parse(r).map(i => ({
return { 'label': i.fullname || i.jid,
'label': i.fullname || i.jid, 'value': i.jid
'value': i.jid }));
}; this.name_auto_complete.auto_completing = true;
}); this.name_auto_complete.evaluate();
awesomplete.evaluate();
} }
}; };
name_input.addEventListener('input', _.debounce(() => { const input_el = this.el.querySelector('input[name="name"]');
xhr.open("GET", `${_converse.xhr_user_search_url}q=${name_input.value}`, true); input_el.addEventListener('input', _.debounce(() => {
xhr.open("GET", `${_converse.xhr_user_search_url}q=${input_el.value}`, true);
xhr.send(); xhr.send();
}, 300)); }, 300));
}, },
...@@ -59661,9 +59659,10 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59661,9 +59659,10 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
name = data.get('name'); name = data.get('name');
if (!jid || _.compact(jid.split('@')).length < 2) { if (!jid || _.compact(jid.split('@')).length < 2) {
// XXX: we have to do this manually, instead of via // XXX: we used to have to do this manually, instead of via
// toHTML because Awesomplete messes things up and // toHTML because Awesomplete messes things up and
// confuses Snabbdom // confuses Snabbdom
// We now use _converse.AutoComplete, can this be removed?
u.addClass('is-invalid', this.el.querySelector('input[name="jid"]')); u.addClass('is-invalid', this.el.querySelector('input[name="jid"]'));
u.addClass('d-block', this.el.querySelector('.invalid-feedback')); u.addClass('d-block', this.el.querySelector('.invalid-feedback'));
} else { } else {
...@@ -59704,7 +59703,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59704,7 +59703,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
}, },
toHTML() { toHTML() {
return templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_11___default()(_.extend(this.model.toJSON(), { return templates_roster_filter_html__WEBPACK_IMPORTED_MODULE_10___default()(_.extend(this.model.toJSON(), {
visible: this.shouldBeVisible(), visible: this.shouldBeVisible(),
placeholder: __('Filter'), placeholder: __('Filter'),
title_contact_filter: __('Filter by contact name'), title_contact_filter: __('Filter by contact name'),
...@@ -59896,7 +59895,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59896,7 +59895,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
*/ */
const display_name = this.model.getDisplayName(); const display_name = this.model.getDisplayName();
this.el.classList.add('pending-xmpp-contact'); this.el.classList.add('pending-xmpp-contact');
this.el.innerHTML = templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_8___default()(_.extend(this.model.toJSON(), { this.el.innerHTML = templates_pending_contact_html__WEBPACK_IMPORTED_MODULE_7___default()(_.extend(this.model.toJSON(), {
'display_name': display_name, 'display_name': display_name,
'desc_remove': __('Click to remove %1$s as a contact', display_name), 'desc_remove': __('Click to remove %1$s as a contact', display_name),
'allow_chat_pending_contacts': _converse.allow_chat_pending_contacts 'allow_chat_pending_contacts': _converse.allow_chat_pending_contacts
...@@ -59904,7 +59903,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59904,7 +59903,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
} else if (requesting === true) { } else if (requesting === true) {
const display_name = this.model.getDisplayName(); const display_name = this.model.getDisplayName();
this.el.classList.add('requesting-xmpp-contact'); this.el.classList.add('requesting-xmpp-contact');
this.el.innerHTML = templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_9___default()(_.extend(this.model.toJSON(), { this.el.innerHTML = templates_requesting_contact_html__WEBPACK_IMPORTED_MODULE_8___default()(_.extend(this.model.toJSON(), {
'display_name': display_name, 'display_name': display_name,
'desc_accept': __("Click to accept the contact request from %1$s", display_name), 'desc_accept': __("Click to accept the contact request from %1$s", display_name),
'desc_decline': __("Click to decline the contact request from %1$s", display_name), 'desc_decline': __("Click to decline the contact request from %1$s", display_name),
...@@ -59951,7 +59950,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -59951,7 +59950,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
} }
const display_name = item.getDisplayName(); const display_name = item.getDisplayName();
this.el.innerHTML = templates_roster_item_html__WEBPACK_IMPORTED_MODULE_12___default()(_.extend(item.toJSON(), { this.el.innerHTML = templates_roster_item_html__WEBPACK_IMPORTED_MODULE_11___default()(_.extend(item.toJSON(), {
'display_name': display_name, 'display_name': display_name,
'desc_status': STATUSES[show], 'desc_status': STATUSES[show],
'status_icon': status_icon, 'status_icon': status_icon,
...@@ -60077,7 +60076,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -60077,7 +60076,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
render() { render() {
this.el.setAttribute('data-group', this.model.get('name')); this.el.setAttribute('data-group', this.model.get('name'));
this.el.innerHTML = templates_group_header_html__WEBPACK_IMPORTED_MODULE_7___default()({ this.el.innerHTML = templates_group_header_html__WEBPACK_IMPORTED_MODULE_6___default()({
'label_group': this.model.get('name'), 'label_group': this.model.get('name'),
'desc_group_toggle': this.model.get('description'), 'desc_group_toggle': this.model.get('description'),
'toggle_state': this.model.get('state'), 'toggle_state': this.model.get('state'),
...@@ -60309,7 +60308,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -60309,7 +60308,7 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
}, },
render() { render() {
this.el.innerHTML = templates_roster_html__WEBPACK_IMPORTED_MODULE_10___default()({ this.el.innerHTML = templates_roster_html__WEBPACK_IMPORTED_MODULE_9___default()({
'allow_contact_requests': _converse.allow_contact_requests, 'allow_contact_requests': _converse.allow_contact_requests,
'heading_contacts': __('Contacts'), 'heading_contacts': __('Contacts'),
'title_add_contact': __('Add a contact'), 'title_add_contact': __('Add a contact'),
...@@ -60554,11 +60553,11 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins ...@@ -60554,11 +60553,11 @@ _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].plugins
_converse.api.listen.on('rosterReadyAfterReconnection', initRoster); _converse.api.listen.on('rosterReadyAfterReconnection', initRoster);
_converse.api.listen.on('afterTearDown', () => { _converse.api.listen.on('afterTearDown', () => {
if (_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].rosterview) { if (_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].rosterview) {
_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].rosterview.model.off().reset(); _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].rosterview.model.off().reset();
_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].rosterview.each(groupview => groupview.removeAll().remove()); _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].rosterview.each(groupview => groupview.removeAll().remove());
_converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].rosterview.removeAll().remove(); _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].rosterview.removeAll().remove();
delete _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_5__["default"].rosterview; delete _converse_headless_converse_core__WEBPACK_IMPORTED_MODULE_4__["default"].rosterview;
} }
}); });
} }
...@@ -92644,19 +92643,21 @@ __p += ' hidden '; ...@@ -92644,19 +92643,21 @@ __p += ' hidden ';
} ; } ;
__p += '">\n <label class="clearfix" for="jid">' + __p += '">\n <label class="clearfix" for="jid">' +
__e(o.label_xmpp_address) + __e(o.label_xmpp_address) +
':</label>\n <input type="text" name="jid" required="required" value="' + ':</label>\n <div class="suggestion-box suggestion-box__jid">\n <ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>\n <input type="text" name="jid" required="required" value="' +
__e(o.jid) + __e(o.jid) +
'"\n class="form-control"\n placeholder="' + '"\n class="form-control suggestion-box__input"\n placeholder="' +
__e(o.contact_placeholder) + __e(o.contact_placeholder) +
'"/>\n <div class="invalid-feedback">' + '"/>\n <div class="invalid-feedback">' +
__e(o.error_message) + __e(o.error_message) +
'</div>\n </div>\n <div class="form-group">\n <label class="clearfix" for="name">' + '</div>\n <span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>\n </div>\n </div>\n <div class="form-group">\n <label class="clearfix" for="name">' +
__e(o.label_nickname) + __e(o.label_nickname) +
':</label>\n <input type="text" name="name" value="' + ':</label>\n <div class="suggestion-box suggestion-box__name">\n <ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>\n <input type="text" name="name" value="' +
__e(o.nickname) + __e(o.nickname) +
'"\n class="form-control"\n placeholder="' + '"\n class="form-control suggestion-box__input"\n placeholder="' +
__e(o.nickname_placeholder) + __e(o.nickname_placeholder) +
'"/>\n </div>\n <button type="submit" class="btn btn-primary">' + '"/>\n <div class="invalid-feedback">' +
__e(o.error_message) +
'</div>\n <span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>\n </div>\n\n </div>\n <button type="submit" class="btn btn-primary">' +
__e(o.label_add) + __e(o.label_add) +
'</button>\n </div>\n </form>\n </div>\n </div>\n</div>\n'; '</button>\n </div>\n </form>\n </div>\n </div>\n</div>\n';
return __p return __p
...@@ -71,13 +71,14 @@ ...@@ -71,13 +71,14 @@
display: none; display: none;
} }
&:after { &:after {
z-index: 1; z-index: -1;
content: ""; content: "";
position: absolute; position: absolute;
bottom: -.43em; bottom: -0.43em;
left: 1em; left: 1em;
width: 0; height: 0; width: 0;
padding: .4em; height: 0;
padding: 0.4em;
background: white; background: white;
border: inherit; border: inherit;
border-left: 0; border-left: 0;
...@@ -140,6 +141,6 @@ ...@@ -140,6 +141,6 @@
#conversejs.converse-overlayed { #conversejs.converse-overlayed {
.suggestion-box__results--above { .suggestion-box__results--above {
bottom: 5.5em; bottom: 3.5em;
} }
} }
...@@ -207,7 +207,7 @@ ...@@ -207,7 +207,7 @@
input_jid.value = 'someone@'; input_jid.value = 'someone@';
const evt = new Event('input'); const evt = new Event('input');
input_jid.dispatchEvent(evt); input_jid.dispatchEvent(evt);
expect(modal.el.querySelector('.awesomplete li').textContent).toBe('someone@localhost'); expect(modal.el.querySelector('.suggestion-box li').textContent).toBe('someone@localhost');
input_jid.value = 'someone@localhost'; input_jid.value = 'someone@localhost';
input_name.value = 'Someone'; input_name.value = 'Someone';
modal.el.querySelector('button[type="submit"]').click(); modal.el.querySelector('button[type="submit"]').click();
...@@ -246,30 +246,28 @@ ...@@ -246,30 +246,28 @@
cbview.el.querySelector('.add-contact').click() cbview.el.querySelector('.add-contact').click()
const modal = _converse.rosterview.add_contact_modal; const modal = _converse.rosterview.add_contact_modal;
await test_utils.waitUntil(() => u.isVisible(modal.el), 1000); await test_utils.waitUntil(() => u.isVisible(modal.el), 1000);
// We only have autocomplete for the name input
expect(modal.jid_auto_complete).toBe(undefined);
expect(modal.name_auto_complete instanceof _converse.AutoComplete).toBe(true);
const input_el = modal.el.querySelector('input[name="name"]'); const input_el = modal.el.querySelector('input[name="name"]');
input_el.value = 'marty'; input_el.value = 'marty';
let evt = new Event('input'); input_el.dispatchEvent(new Event('input'));
input_el.dispatchEvent(evt); await test_utils.waitUntil(() => modal.el.querySelector('.suggestion-box li'), 1000);
await test_utils.waitUntil(() => modal.el.querySelector('.awesomplete li'), 1000);
const sendIQ = _converse.connection.sendIQ; const sendIQ = _converse.connection.sendIQ;
let sent_stanza, IQ_id; let sent_stanza, IQ_id;
spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) { spyOn(_converse.connection, 'sendIQ').and.callFake(function (iq, callback, errback) {
sent_stanza = iq; sent_stanza = iq;
IQ_id = sendIQ.bind(this)(iq, callback, errback); IQ_id = sendIQ.bind(this)(iq, callback, errback);
}); });
expect(modal.el.querySelectorAll('.awesomplete li').length).toBe(1); expect(modal.el.querySelectorAll('.suggestion-box li').length).toBe(1);
const suggestion = modal.el.querySelector('.awesomplete li'); const suggestion = modal.el.querySelector('.suggestion-box li');
expect(suggestion.textContent).toBe('Marty McFly'); expect(suggestion.textContent).toBe('Marty McFly');
// Can't trigger "mousedown" event so trigger the Awesomplete // Mock selection
// custom event which would have been triggered upon mousedown. modal.name_auto_complete.select(suggestion);
evt = document.createEvent("HTMLEvents");
evt.initEvent('awesomplete-selectcomplete', true, true );
evt.text = {
'label': 'Marty McFly',
'value': 'marty@mcfly.net'
}
modal.el.dispatchEvent(evt);
expect(input_el.value).toBe('Marty McFly'); expect(input_el.value).toBe('Marty McFly');
expect(modal.el.querySelector('input[name="jid"]').value).toBe('marty@mcfly.net'); expect(modal.el.querySelector('input[name="jid"]').value).toBe('marty@mcfly.net');
modal.el.querySelector('button[type="submit"]').click(); modal.el.querySelector('button[type="submit"]').click();
......
...@@ -53,6 +53,32 @@ converse.plugins.add("converse-autocomplete", { ...@@ -53,6 +53,32 @@ converse.plugins.add("converse-autocomplete", {
}; };
class Suggestion extends String {
constructor (data) {
super();
const o = Array.isArray(data)
? { label: data[0], value: data[1] }
: typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
this.label = o.label || o.value;
this.value = o.value;
}
get lenth () {
return this.label.length;
}
toString () {
return "" + this.label;
}
valueOf () {
return this.toString();
}
}
class AutoComplete { class AutoComplete {
constructor (el, config={}) { constructor (el, config={}) {
...@@ -76,7 +102,7 @@ converse.plugins.add("converse-autocomplete", { ...@@ -76,7 +102,7 @@ converse.plugins.add("converse-autocomplete", {
'include_triggers': [], // Array of trigger keys which should be included in the returned value 'include_triggers': [], // Array of trigger keys which should be included in the returned value
'min_chars': 2, 'min_chars': 2,
'max_items': 10, 'max_items': 10,
'auto_evaluate': true, 'auto_evaluate': true, // Should evaluation happen automatically without any particular key as trigger?
'auto_first': false, // Should the first element be automatically selected? 'auto_first': false, // Should the first element be automatically selected?
'data': _.identity, 'data': _.identity,
'filter': _converse.FILTER_CONTAINS, 'filter': _converse.FILTER_CONTAINS,
...@@ -129,7 +155,7 @@ converse.plugins.add("converse-autocomplete", { ...@@ -129,7 +155,7 @@ converse.plugins.add("converse-autocomplete", {
list = helpers.getElement(list); list = helpers.getElement(list);
if (list && list.children) { if (list && list.children) {
const items = []; const items = [];
slice.apply(list.children).forEach(function (el) { Array.prototype.slice.apply(list.children).forEach(function (el) {
if (!el.disabled) { if (!el.disabled) {
const text = el.textContent.trim(), const text = el.textContent.trim(),
value = el.value || text, value = el.value || text,
...@@ -230,7 +256,7 @@ converse.plugins.add("converse-autocomplete", { ...@@ -230,7 +256,7 @@ converse.plugins.add("converse-autocomplete", {
} }
} }
select (selected, origin) { select (selected) {
if (selected) { if (selected) {
this.index = u.siblingIndex(selected); this.index = u.siblingIndex(selected);
} else { } else {
...@@ -305,11 +331,11 @@ converse.plugins.add("converse-autocomplete", { ...@@ -305,11 +331,11 @@ converse.plugins.add("converse-autocomplete", {
} }
evaluate (ev) { evaluate (ev) {
const arrow_pressed = ( const selecting = this.selected && ev && (
ev.keyCode === _converse.keycodes.UP_ARROW || ev.keyCode === _converse.keycodes.UP_ARROW ||
ev.keyCode === _converse.keycodes.DOWN_ARROW ev.keyCode === _converse.keycodes.DOWN_ARROW
); );
if (!this.auto_completing || (this.selected && arrow_pressed)) { if (!this.auto_evaluate && !this.auto_completing || selecting) {
return; return;
} }
...@@ -339,7 +365,7 @@ converse.plugins.add("converse-autocomplete", { ...@@ -339,7 +365,7 @@ converse.plugins.add("converse-autocomplete", {
this.suggestions = this.suggestions.sort(this.sort); this.suggestions = this.suggestions.sort(this.sort);
} }
this.suggestions = this.suggestions.slice(0, this.max_items); this.suggestions = this.suggestions.slice(0, this.max_items);
this.suggestions.forEach((text) => this.ul.appendChild(this.item(text, value))); this.suggestions.forEach(text => this.ul.appendChild(this.item(text, value)));
if (this.ul.children.length === 0) { if (this.ul.children.length === 0) {
this.close({'reason': 'nomatches'}); this.close({'reason': 'nomatches'});
...@@ -357,28 +383,6 @@ converse.plugins.add("converse-autocomplete", { ...@@ -357,28 +383,6 @@ converse.plugins.add("converse-autocomplete", {
_.extend(AutoComplete.prototype, Backbone.Events); _.extend(AutoComplete.prototype, Backbone.Events);
// Private functions
function Suggestion(data) {
const o = Array.isArray(data)
? { label: data[0], value: data[1] }
: typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };
this.label = o.label || o.value;
this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
get: function() { return this.label.length; }
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
return "" + this.label;
};
// Helpers
var slice = Array.prototype.slice;
const helpers = { const helpers = {
getElement (expr, el) { getElement (expr, el) {
......
// Converse.js (A browser based XMPP chat client) // Converse.js (A browser based XMPP chat client)
// https://conversejs.org // https://conversejs.org
// //
// Copyright (c) 2012-2017, Jan-Carel Brand <jc@opkode.com> // Copyright (c) 2019, Jan-Carel Brand <jc@opkode.com>
// Licensed under the Mozilla Public License (MPLv2) // Licensed under the Mozilla Public License (MPLv2)
import "converse-chatview"; import "converse-chatview";
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
import "@converse/headless/converse-roster"; import "@converse/headless/converse-roster";
import "@converse/headless/converse-chatboxes"; import "@converse/headless/converse-chatboxes";
import "converse-modal"; import "converse-modal";
import Awesomplete from "awesomplete";
import _FormData from "formdata-polyfill"; import _FormData from "formdata-polyfill";
import converse from "@converse/headless/converse-core"; import converse from "@converse/headless/converse-core";
import tpl_add_contact_modal from "templates/add_contact_modal.html"; import tpl_add_contact_modal from "templates/add_contact_modal.html";
...@@ -119,7 +118,7 @@ converse.plugins.add('converse-rosterview', { ...@@ -119,7 +118,7 @@ converse.plugins.add('converse-rosterview', {
toHTML () { toHTML () {
const label_nickname = _converse.xhr_user_search_url ? __('Contact name') : __('Optional nickname'); const label_nickname = _converse.xhr_user_search_url ? __('Contact name') : __('Optional nickname');
return tpl_add_contact_modal(_.extend(this.model.toJSON(), { return tpl_add_contact_modal(_.extend(this.model.toJSON(), {
'_converse': _converse, '_converse': _converse,
'heading_new_contact': __('Add a Contact'), 'heading_new_contact': __('Add a Contact'),
'label_xmpp_address': __('XMPP Address'), 'label_xmpp_address': __('XMPP Address'),
...@@ -132,47 +131,47 @@ converse.plugins.add('converse-rosterview', { ...@@ -132,47 +131,47 @@ converse.plugins.add('converse-rosterview', {
afterRender () { afterRender () {
if (_converse.xhr_user_search_url && _.isString(_converse.xhr_user_search_url)) { if (_converse.xhr_user_search_url && _.isString(_converse.xhr_user_search_url)) {
this.initXHRAutoComplete(this.el); this.initXHRAutoComplete();
this.el.addEventListener('awesomplete-selectcomplete', ev => { this.name_auto_complete.on('suggestion-box-selectcomplete', ev => {
this.el.querySelector('input[name="name"]').value = ev.text.label; this.el.querySelector('input[name="name"]').value = ev.text.label;
this.el.querySelector('input[name="jid"]').value = ev.text.value; this.el.querySelector('input[name="jid"]').value = ev.text.value;
}); });
} else { } else {
this.initJIDAutoComplete(this.el); this.initJIDAutoComplete();
} }
const jid_input = this.el.querySelector('input[name="jid"]'); const jid_input = this.el.querySelector('input[name="jid"]');
this.el.addEventListener('shown.bs.modal', () => jid_input.focus(), false); this.el.addEventListener('shown.bs.modal', () => jid_input.focus(), false);
}, },
initJIDAutoComplete (root) { initJIDAutoComplete () {
const jid_input = root.querySelector('input[name="jid"]'); const el = this.el.querySelector('.suggestion-box__jid').parentElement;
const list = _.uniq(_converse.roster.map((item) => Strophe.getDomainFromJid(item.get('jid')))); this.jid_auto_complete = new _converse.AutoComplete(el, {
new Awesomplete(jid_input, {
'list': list,
'data': (text, input) => `${input.slice(0, input.indexOf("@"))}@${text}`, 'data': (text, input) => `${input.slice(0, input.indexOf("@"))}@${text}`,
'filter': Awesomplete.FILTER_STARTSWITH 'filter': _converse.FILTER_STARTSWITH,
'list': _.uniq(_converse.roster.map(item => Strophe.getDomainFromJid(item.get('jid'))))
}); });
}, },
initXHRAutoComplete (root) { initXHRAutoComplete () {
const name_input = this.el.querySelector('input[name="name"]'); const el = this.el.querySelector('.suggestion-box__name').parentElement;
const jid_input = this.el.querySelector('input[name="jid"]'); this.name_auto_complete = new _converse.AutoComplete(el, {
const awesomplete = new Awesomplete(name_input, { 'auto_evaluate': false,
'minChars': 1, 'filter': _converse.FILTER_STARTSWITH,
'list': [] 'list': []
}); });
const xhr = new window.XMLHttpRequest(); const xhr = new window.XMLHttpRequest();
// `open` must be called after `onload` for mock/testing purposes. // `open` must be called after `onload` for mock/testing purposes.
xhr.onload = function () { xhr.onload = () => {
if (xhr.responseText) { if (xhr.responseText) {
awesomplete.list = JSON.parse(xhr.responseText).map((i) => { //eslint-disable-line arrow-body-style const r = xhr.responseText;
return {'label': i.fullname || i.jid, 'value': i.jid}; this.name_auto_complete.list = JSON.parse(r).map(i => ({'label': i.fullname || i.jid, 'value': i.jid}));
}); this.name_auto_complete.auto_completing = true;
awesomplete.evaluate(); this.name_auto_complete.evaluate();
} }
}; };
name_input.addEventListener('input', _.debounce(() => { const input_el = this.el.querySelector('input[name="name"]');
xhr.open("GET", `${_converse.xhr_user_search_url}q=${name_input.value}`, true); input_el.addEventListener('input', _.debounce(() => {
xhr.open("GET", `${_converse.xhr_user_search_url}q=${input_el.value}`, true);
xhr.send() xhr.send()
} , 300)); } , 300));
}, },
...@@ -183,9 +182,10 @@ converse.plugins.add('converse-rosterview', { ...@@ -183,9 +182,10 @@ converse.plugins.add('converse-rosterview', {
jid = data.get('jid'), jid = data.get('jid'),
name = data.get('name'); name = data.get('name');
if (!jid || _.compact(jid.split('@')).length < 2) { if (!jid || _.compact(jid.split('@')).length < 2) {
// XXX: we have to do this manually, instead of via // XXX: we used to have to do this manually, instead of via
// toHTML because Awesomplete messes things up and // toHTML because Awesomplete messes things up and
// confuses Snabbdom // confuses Snabbdom
// We now use _converse.AutoComplete, can this be removed?
u.addClass('is-invalid', this.el.querySelector('input[name="jid"]')); u.addClass('is-invalid', this.el.querySelector('input[name="jid"]'));
u.addClass('d-block', this.el.querySelector('.invalid-feedback')); u.addClass('d-block', this.el.querySelector('.invalid-feedback'));
} else { } else {
......
...@@ -10,16 +10,26 @@ ...@@ -10,16 +10,26 @@
<div class="modal-body"> <div class="modal-body">
<div class="form-group {[ if (o._converse.xhr_user_search_url) { ]} hidden {[ } ]}"> <div class="form-group {[ if (o._converse.xhr_user_search_url) { ]} hidden {[ } ]}">
<label class="clearfix" for="jid">{{{o.label_xmpp_address}}}:</label> <label class="clearfix" for="jid">{{{o.label_xmpp_address}}}:</label>
<input type="text" name="jid" required="required" value="{{{o.jid}}}" <div class="suggestion-box suggestion-box__jid">
class="form-control" <ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
placeholder="{{{o.contact_placeholder}}}"/> <input type="text" name="jid" required="required" value="{{{o.jid}}}"
<div class="invalid-feedback">{{{o.error_message}}}</div> class="form-control suggestion-box__input"
placeholder="{{{o.contact_placeholder}}}"/>
<div class="invalid-feedback">{{{o.error_message}}}</div>
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="clearfix" for="name">{{{o.label_nickname}}}:</label> <label class="clearfix" for="name">{{{o.label_nickname}}}:</label>
<input type="text" name="name" value="{{{o.nickname}}}" <div class="suggestion-box suggestion-box__name">
class="form-control" <ul class="suggestion-box__results suggestion-box__results--above" hidden=""></ul>
placeholder="{{{o.nickname_placeholder}}}"/> <input type="text" name="name" value="{{{o.nickname}}}"
class="form-control suggestion-box__input"
placeholder="{{{o.nickname_placeholder}}}"/>
<div class="invalid-feedback">{{{o.error_message}}}</div>
<span class="suggestion-box__additions visually-hidden" role="status" aria-live="assertive" aria-relevant="additions"></span>
</div>
</div> </div>
<button type="submit" class="btn btn-primary">{{{o.label_add}}}</button> <button type="submit" class="btn btn-primary">{{{o.label_add}}}</button>
</div> </div>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment