Re-add xhr_user_search_url
and autocomplete when adding contacts
This commit is contained in:
parent
1e927294e0
commit
95406a149d
@ -149,7 +149,7 @@
|
||||
"no-negated-condition": "off",
|
||||
"no-negated-in-lhs": "error",
|
||||
"no-nested-ternary": "off",
|
||||
"no-new": "error",
|
||||
"no-new": "off",
|
||||
"no-new-func": "error",
|
||||
"no-new-object": "error",
|
||||
"no-new-require": "error",
|
||||
|
@ -7,7 +7,7 @@ addons:
|
||||
chrome: stable
|
||||
node_js:
|
||||
- 6
|
||||
install: make node_modules
|
||||
install: make stamp-npm
|
||||
before_script: make serve_bg
|
||||
script: make check
|
||||
sudo: false
|
||||
|
22
CHANGES.md
22
CHANGES.md
@ -2,29 +2,19 @@
|
||||
|
||||
## 4.0.0 (Unreleased)
|
||||
|
||||
## Removed configuration settings
|
||||
## UI changes
|
||||
|
||||
Due to rewriting parts of the code, we regrettably had to remove certain
|
||||
lesser-used configuration settings because the cost of adding them to the
|
||||
new code was too high.
|
||||
The UI is now based on Bootstrap4 and Flexbox is used extensively.
|
||||
|
||||
If you relied on any of these settings, you can reproduce their
|
||||
functionality in your own 3rd party plugins, or you can [contact us](http://opkode.com/contact.html)
|
||||
with regards to sponsoring development on reintroducing them.
|
||||
## Configuration changes
|
||||
|
||||
* Removed the `xhr_custom_status` and `xhr_custom_status_url` configuration
|
||||
settings. If you relied on these settings, you can instead listen for the
|
||||
[statusMessageChanged](https://conversejs.org/docs/html/events.html#contactstatusmessagechanged)
|
||||
event and make the XMLHttpRequest yourself.
|
||||
* Removed the `xhr_user_search` and `xhr_user_search_url` configuration options.
|
||||
|
||||
## Updated UI
|
||||
|
||||
The UI is now rewritten with Bootstrap4 and Flexbox is used pretty much
|
||||
everywhere. Unfortunately this means that in the overlayed view_mode, chat
|
||||
boxes can no longer be resized horizontally (or diagonally). Perhaps a solution
|
||||
for this can again be found, but time constraints meant that this feature had
|
||||
to be removed.
|
||||
* Removed `xhr_user_search` in favor of only accepting `xhr_user_search_url` as configuration option.
|
||||
* The data returned from the `xhr_user_search_url` must now include the user's
|
||||
`jid` instead of just an `id`.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
135
css/converse.css
135
css/converse.css
@ -8586,20 +8586,23 @@ body.reset {
|
||||
#conversejs:not(.fullscreen) #minimized-chats .chat-head-message-count-hidden {
|
||||
display: none; }
|
||||
|
||||
#converse-embedded-chat,
|
||||
#conversejs {
|
||||
/* Pointer */ }
|
||||
#converse-embedded-chat [hidden],
|
||||
#conversejs [hidden] {
|
||||
display: none; }
|
||||
#converse-embedded-chat .visually-hidden,
|
||||
#conversejs .visually-hidden {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0); }
|
||||
#converse-embedded-chat div.awesomplete,
|
||||
#conversejs div.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative; }
|
||||
#converse-embedded-chat [hidden],
|
||||
#conversejs [hidden] {
|
||||
display: none; }
|
||||
#converse-embedded-chat .visually-hidden,
|
||||
#conversejs .visually-hidden {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0); }
|
||||
#converse-embedded-chat .form-group .awesomplete,
|
||||
#conversejs .form-group .awesomplete {
|
||||
width: 100%; }
|
||||
#converse-embedded-chat div.awesomplete,
|
||||
#conversejs div.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative; }
|
||||
#converse-embedded-chat div.awesomplete mark,
|
||||
#conversejs div.awesomplete mark {
|
||||
background: #FFB9A7; }
|
||||
#converse-embedded-chat div.awesomplete > input,
|
||||
#conversejs div.awesomplete > input {
|
||||
display: block; }
|
||||
@ -8620,62 +8623,60 @@ body.reset {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
|
||||
text-shadow: none; }
|
||||
#converse-embedded-chat div.awesomplete > ul:before,
|
||||
#conversejs div.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg); }
|
||||
#converse-embedded-chat div.awesomplete > ul > li,
|
||||
#conversejs div.awesomplete > ul > li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 1em; }
|
||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||
#conversejs div.awesomplete > ul[hidden],
|
||||
#conversejs div.awesomplete > ul:empty {
|
||||
display: none; }
|
||||
@supports (transform: scale(0)) {
|
||||
#converse-embedded-chat div.awesomplete > ul,
|
||||
#conversejs div.awesomplete > ul {
|
||||
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
|
||||
transform-origin: 1.43em -.43em; }
|
||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||
#conversejs div.awesomplete > ul[hidden],
|
||||
#conversejs div.awesomplete > ul:empty {
|
||||
display: none; }
|
||||
@supports (transform: scale(0)) {
|
||||
#converse-embedded-chat div.awesomplete > ul,
|
||||
#conversejs div.awesomplete > ul {
|
||||
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
|
||||
transform-origin: 1.43em -.43em; }
|
||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||
#conversejs div.awesomplete > ul[hidden],
|
||||
#conversejs div.awesomplete > ul:empty {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
display: block;
|
||||
transition-timing-function: ease; } }
|
||||
#converse-embedded-chat div.awesomplete > ul:before,
|
||||
#conversejs div.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg); }
|
||||
#converse-embedded-chat div.awesomplete > ul > li,
|
||||
#conversejs div.awesomplete > ul > li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
cursor: pointer; }
|
||||
#converse-embedded-chat div.awesomplete > ul > li:hover,
|
||||
#conversejs div.awesomplete > ul > li:hover {
|
||||
background: #E77051;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete > ul > li[aria-selected="true"],
|
||||
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
|
||||
background: #3d6d8f;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete mark,
|
||||
#conversejs div.awesomplete mark {
|
||||
background: #FFB9A7; }
|
||||
#converse-embedded-chat div.awesomplete li:hover mark,
|
||||
#conversejs div.awesomplete li:hover mark {
|
||||
background: #A53214;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete li[aria-selected="true"] mark,
|
||||
#conversejs div.awesomplete li[aria-selected="true"] mark {
|
||||
background: #3d6b00;
|
||||
color: inherit; }
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
display: block;
|
||||
transition-timing-function: ease; } }
|
||||
#converse-embedded-chat div.awesomplete > ul > li:hover,
|
||||
#conversejs div.awesomplete > ul > li:hover {
|
||||
background: #E77051;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete > ul > li[aria-selected="true"],
|
||||
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
|
||||
background: #3d6d8f;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete li:hover mark,
|
||||
#conversejs div.awesomplete li:hover mark {
|
||||
background: #A53214;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete li[aria-selected="true"] mark,
|
||||
#conversejs div.awesomplete li[aria-selected="true"] mark {
|
||||
background: #3d6b00;
|
||||
color: inherit; }
|
||||
|
||||
/*# sourceMappingURL=converse.css.map */
|
||||
|
135
css/inverse.css
135
css/inverse.css
@ -8698,20 +8698,23 @@ body {
|
||||
border: 1.2em solid #E7A151;
|
||||
border-top: 0.8em solid #E7A151; }
|
||||
|
||||
#converse-embedded-chat,
|
||||
#conversejs {
|
||||
/* Pointer */ }
|
||||
#converse-embedded-chat [hidden],
|
||||
#conversejs [hidden] {
|
||||
display: none; }
|
||||
#converse-embedded-chat .visually-hidden,
|
||||
#conversejs .visually-hidden {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0); }
|
||||
#converse-embedded-chat div.awesomplete,
|
||||
#conversejs div.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative; }
|
||||
#converse-embedded-chat [hidden],
|
||||
#conversejs [hidden] {
|
||||
display: none; }
|
||||
#converse-embedded-chat .visually-hidden,
|
||||
#conversejs .visually-hidden {
|
||||
position: absolute;
|
||||
clip: rect(0, 0, 0, 0); }
|
||||
#converse-embedded-chat .form-group .awesomplete,
|
||||
#conversejs .form-group .awesomplete {
|
||||
width: 100%; }
|
||||
#converse-embedded-chat div.awesomplete,
|
||||
#conversejs div.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative; }
|
||||
#converse-embedded-chat div.awesomplete mark,
|
||||
#conversejs div.awesomplete mark {
|
||||
background: #FFB9A7; }
|
||||
#converse-embedded-chat div.awesomplete > input,
|
||||
#conversejs div.awesomplete > input {
|
||||
display: block; }
|
||||
@ -8732,62 +8735,60 @@ body {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
|
||||
text-shadow: none; }
|
||||
#converse-embedded-chat div.awesomplete > ul:before,
|
||||
#conversejs div.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg); }
|
||||
#converse-embedded-chat div.awesomplete > ul > li,
|
||||
#conversejs div.awesomplete > ul > li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 1em; }
|
||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||
#conversejs div.awesomplete > ul[hidden],
|
||||
#conversejs div.awesomplete > ul:empty {
|
||||
display: none; }
|
||||
@supports (transform: scale(0)) {
|
||||
#converse-embedded-chat div.awesomplete > ul,
|
||||
#conversejs div.awesomplete > ul {
|
||||
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
|
||||
transform-origin: 1.43em -.43em; }
|
||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||
#conversejs div.awesomplete > ul[hidden],
|
||||
#conversejs div.awesomplete > ul:empty {
|
||||
display: none; }
|
||||
@supports (transform: scale(0)) {
|
||||
#converse-embedded-chat div.awesomplete > ul,
|
||||
#conversejs div.awesomplete > ul {
|
||||
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
|
||||
transform-origin: 1.43em -.43em; }
|
||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||
#conversejs div.awesomplete > ul[hidden],
|
||||
#conversejs div.awesomplete > ul:empty {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
display: block;
|
||||
transition-timing-function: ease; } }
|
||||
#converse-embedded-chat div.awesomplete > ul:before,
|
||||
#conversejs div.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg); }
|
||||
#converse-embedded-chat div.awesomplete > ul > li,
|
||||
#conversejs div.awesomplete > ul > li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
cursor: pointer; }
|
||||
#converse-embedded-chat div.awesomplete > ul > li:hover,
|
||||
#conversejs div.awesomplete > ul > li:hover {
|
||||
background: #E77051;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete > ul > li[aria-selected="true"],
|
||||
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
|
||||
background: #3d6d8f;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete mark,
|
||||
#conversejs div.awesomplete mark {
|
||||
background: #FFB9A7; }
|
||||
#converse-embedded-chat div.awesomplete li:hover mark,
|
||||
#conversejs div.awesomplete li:hover mark {
|
||||
background: #A53214;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete li[aria-selected="true"] mark,
|
||||
#conversejs div.awesomplete li[aria-selected="true"] mark {
|
||||
background: #3d6b00;
|
||||
color: inherit; }
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
display: block;
|
||||
transition-timing-function: ease; } }
|
||||
#converse-embedded-chat div.awesomplete > ul > li:hover,
|
||||
#conversejs div.awesomplete > ul > li:hover {
|
||||
background: #E77051;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete > ul > li[aria-selected="true"],
|
||||
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
|
||||
background: #3d6d8f;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete li:hover mark,
|
||||
#conversejs div.awesomplete li:hover mark {
|
||||
background: #A53214;
|
||||
color: white; }
|
||||
#converse-embedded-chat div.awesomplete li[aria-selected="true"] mark,
|
||||
#conversejs div.awesomplete li[aria-selected="true"] mark {
|
||||
background: #3d6b00;
|
||||
color: inherit; }
|
||||
|
||||
/*# sourceMappingURL=inverse.css.map */
|
||||
|
@ -1535,3 +1535,38 @@ Example:
|
||||
whitelisted_plugins: ['myplugin']
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
xhr_user_search_url
|
||||
-------------------
|
||||
|
||||
.. note::
|
||||
XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous JavaScript and XML).
|
||||
|
||||
* Default: ``null``
|
||||
|
||||
There are two ways to add users.
|
||||
|
||||
* The user inputs a valid JID (Jabber ID, aka XMPP address), and the user is added as a pending contact.
|
||||
* The user inputs some text (for example part of a first name or last name),
|
||||
an XHR (Ajax Request) will be made to a remote server, and a list of matches are returned.
|
||||
The user can then choose one of the matches to add as a contact.
|
||||
|
||||
By providing an XHR search URL, you're enabling the second mechanism.
|
||||
|
||||
*What is expected from the remote server?*
|
||||
|
||||
A default JSON encoded list of objects must be returned. Each object
|
||||
corresponds to a matched user and needs the keys ``jid`` and ``fullname``.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
[{"jid": "marty@mcfly.net", "fullname": "Marty McFly"}, {"jid": "doc@brown.com", "fullname": "Doc Brown"}]
|
||||
|
||||
.. note::
|
||||
Make sure your server script sets the header `Content-Type: application/json`.
|
||||
|
||||
This is the URL to which an XHR GET request will be made to fetch user data from your remote server.
|
||||
The query string will be included in the request with ``q`` as its key.
|
||||
|
||||
The data returned must be a JSON encoded list of user JIDs.
|
||||
|
@ -7,31 +7,62 @@
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
.awesomplete {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
div.awesomplete {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
mark {
|
||||
background: $lightest-red;
|
||||
}
|
||||
|
||||
div.awesomplete > input {
|
||||
display: block;
|
||||
}
|
||||
> input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.awesomplete > ul {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
border-radius: .3em;
|
||||
margin: .2em 0 0;
|
||||
background: hsla(0,0%,100%,.9);
|
||||
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
|
||||
border: 1px solid rgba(0,0,0,.3);
|
||||
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
|
||||
text-shadow: none;
|
||||
> ul {
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0; height: 0;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
border-radius: .3em;
|
||||
margin: .2em 0 0;
|
||||
background: hsla(0,0%,100%,.9);
|
||||
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
|
||||
border: 1px solid rgba(0,0,0,.3);
|
||||
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
|
||||
text-shadow: none;
|
||||
|
||||
> li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.awesomplete > ul[hidden],
|
||||
@ -54,28 +85,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Pointer */
|
||||
div.awesomplete > ul:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -.43em;
|
||||
left: 1em;
|
||||
width: 0; height: 0;
|
||||
background: white;
|
||||
border: inherit;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
div.awesomplete > ul > li {
|
||||
text-overflow: ellipsis;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.awesomplete > ul > li:hover {
|
||||
background: $red;
|
||||
color: $inverse-link-color;
|
||||
@ -86,10 +95,6 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.awesomplete mark {
|
||||
background: $lightest-red;
|
||||
}
|
||||
|
||||
div.awesomplete li:hover mark {
|
||||
background: $darkest-red;
|
||||
color: $inverse-link-color;
|
||||
|
@ -1353,20 +1353,12 @@
|
||||
$(view.el).find('.chat-area').remove();
|
||||
|
||||
test_utils.waitUntil(function () {
|
||||
return $(view.el).find('input.invited-contact').length;
|
||||
return $(view.el).find('input.invited-contact').length;
|
||||
}, 300).then(function () {
|
||||
var $input = $(view.el).find('input.invited-contact');
|
||||
expect($input.attr('placeholder')).toBe('Invite');
|
||||
$input.val("Felix");
|
||||
var evt;
|
||||
// check if Event() is a constructor function
|
||||
// usage as per the spec, if true
|
||||
if (typeof(Event) === 'function') {
|
||||
evt = new Event('input');
|
||||
} else { // the deprecated way for PhantomJS
|
||||
evt = document.createEvent('CustomEvent');
|
||||
evt.initCustomEvent('input', false, false, null);
|
||||
}
|
||||
var evt = new Event('input');
|
||||
$input[0].dispatchEvent(evt);
|
||||
|
||||
var sent_stanza;
|
||||
|
@ -33,6 +33,37 @@
|
||||
|
||||
describe("The \"Contacts\" section", function () {
|
||||
|
||||
it("can be used to add contact and it checks for case-sensivity",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
test_utils.openControlBox();
|
||||
// Adding two contacts one with Capital initials and one with small initials of same JID (Case sensitive check)
|
||||
_converse.roster.create({
|
||||
jid: mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
|
||||
subscription: 'none',
|
||||
ask: 'subscribe',
|
||||
fullname: mock.pend_names[0]
|
||||
});
|
||||
_converse.roster.create({
|
||||
jid: mock.pend_names[0].replace(/ /g,'.') + '@localhost',
|
||||
subscription: 'none',
|
||||
ask: 'subscribe',
|
||||
fullname: mock.pend_names[0]
|
||||
});
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group li:visible').length;
|
||||
}, 700).then(function () {
|
||||
// Checking that only one entry is created because both JID is same (Case sensitive check)
|
||||
expect($(_converse.rosterview.el).find('li:visible').length).toBe(1);
|
||||
expect(_converse.rosterview.update).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("shows the number of unread mentions received",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
@ -157,6 +188,8 @@
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
test_utils.createContacts(_converse, 'all').openControlBox();
|
||||
|
||||
var panel = _converse.chatboxviews.get('controlbox').contactspanel;
|
||||
var cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
@ -165,37 +198,55 @@
|
||||
return u.isVisible(modal.el);
|
||||
}, 1000).then(function () {
|
||||
expect(!_.isNull(modal.el.querySelector('form.add-xmpp-contact'))).toBeTruthy();
|
||||
var input_el = modal.el.querySelector('input[name="jid"]');
|
||||
input_el.value = 'someone@';
|
||||
var evt = new Event('input');
|
||||
input_el.dispatchEvent(evt);
|
||||
expect(modal.el.querySelector('.awesomplete li').textContent).toBe('someone@localhost');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("can be used to add contact and it checks for case-sensivity",
|
||||
|
||||
it("integrates with xhr_user_search_url to search for contacts",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
null, ['rosterGroupsFetched'],
|
||||
{ 'xhr_user_search': true,
|
||||
'xhr_user_search_url': 'http://example.org/'
|
||||
},
|
||||
function (done, _converse) {
|
||||
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
test_utils.openControlBox();
|
||||
// Adding two contacts one with Capital initials and one with small initials of same JID (Case sensitive check)
|
||||
_converse.roster.create({
|
||||
jid: mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
|
||||
subscription: 'none',
|
||||
ask: 'subscribe',
|
||||
fullname: mock.pend_names[0]
|
||||
var xhr = {
|
||||
'open': _.noop,
|
||||
'send': function () {
|
||||
xhr.responseText = JSON.stringify([
|
||||
{"jid": "marty@mcfly.net", "fullname": "Marty McFly"},
|
||||
{"jid": "doc@brown.com", "fullname": "Doc Brown"}
|
||||
]);
|
||||
xhr.onload();
|
||||
}
|
||||
};
|
||||
window.XMLHttpRequest = jasmine.createSpy('XMLHttpRequest');
|
||||
XMLHttpRequest.and.callFake(function () {
|
||||
return xhr;
|
||||
});
|
||||
_converse.roster.create({
|
||||
jid: mock.pend_names[0].replace(/ /g,'.') + '@localhost',
|
||||
subscription: 'none',
|
||||
ask: 'subscribe',
|
||||
fullname: mock.pend_names[0]
|
||||
});
|
||||
test_utils.waitUntil(function () {
|
||||
return $(_converse.rosterview.el).find('.roster-group li:visible').length;
|
||||
}, 700).then(function () {
|
||||
// Checking that only one entry is created because both JID is same (Case sensitive check)
|
||||
expect($(_converse.rosterview.el).find('li:visible').length).toBe(1);
|
||||
expect(_converse.rosterview.update).toHaveBeenCalled();
|
||||
|
||||
var panel = _converse.chatboxviews.get('controlbox').contactspanel;
|
||||
var cbview = _converse.chatboxviews.get('controlbox');
|
||||
cbview.el.querySelector('.add-contact').click()
|
||||
var modal = _converse.rosterview.add_contact_modal;
|
||||
return test_utils.waitUntil(function () {
|
||||
return u.isVisible(modal.el);
|
||||
}, 1000).then(function () {
|
||||
var input_el = modal.el.querySelector('input[name="jid"]');
|
||||
input_el.value = 'marty@';
|
||||
var evt = new Event('input');
|
||||
input_el.dispatchEvent(evt);
|
||||
return test_utils.waitUntil(function () {
|
||||
return modal.el.querySelector('.awesomplete li');
|
||||
});
|
||||
}).then(function () {
|
||||
expect(modal.el.querySelector('.awesomplete li').textContent).toBe('marty@mcfly.net');
|
||||
done();
|
||||
});
|
||||
}));
|
||||
|
@ -16,6 +16,7 @@
|
||||
"tpl!roster_filter",
|
||||
"tpl!roster_item",
|
||||
"tpl!search_contact",
|
||||
"awesomplete",
|
||||
"converse-chatboxes",
|
||||
"converse-modal"
|
||||
], factory);
|
||||
@ -28,7 +29,8 @@
|
||||
tpl_roster,
|
||||
tpl_roster_filter,
|
||||
tpl_roster_item,
|
||||
tpl_search_contact
|
||||
tpl_search_contact,
|
||||
Awesomplete
|
||||
) {
|
||||
"use strict";
|
||||
const { Backbone, Strophe, $iq, b64_sha1, sizzle, _ } = converse.env;
|
||||
@ -78,9 +80,10 @@
|
||||
{ __ } = _converse;
|
||||
|
||||
_converse.api.settings.update({
|
||||
allow_chat_pending_contacts: true,
|
||||
allow_contact_removal: true,
|
||||
show_toolbar: true,
|
||||
'allow_chat_pending_contacts': true,
|
||||
'allow_contact_removal': true,
|
||||
'show_toolbar': true,
|
||||
'xhr_user_search_url': null
|
||||
});
|
||||
_converse.api.promises.add('rosterViewInitialized');
|
||||
|
||||
@ -147,6 +150,31 @@
|
||||
}));
|
||||
},
|
||||
|
||||
afterRender () {
|
||||
const input_el = this.el.querySelector('input[name="jid"]');
|
||||
if (_converse.xhr_user_search_url && _.isString(_converse.xhr_user_search_url)) {
|
||||
const awesomplete = new Awesomplete(input_el, {'list': [], 'minChars': 2});
|
||||
const xhr = new window.XMLHttpRequest();
|
||||
// `open` must be called after `onload` for
|
||||
// mock/testing purposes.
|
||||
xhr.onload = function () {
|
||||
awesomplete.list = JSON.parse(xhr.responseText).map((i) => i.jid);
|
||||
awesomplete.evaluate();
|
||||
};
|
||||
xhr.open("GET", _converse.xhr_user_search_url, true);
|
||||
input_el.addEventListener('input', _.debounce(() => xhr.send()), 100, {'leading': true});
|
||||
} else {
|
||||
const list = _.uniq(_converse.roster.map((item) => Strophe.getDomainFromJid(item.get('jid'))));
|
||||
new Awesomplete(input_el, {
|
||||
'list': list,
|
||||
'data': function (text, input) {
|
||||
return input.slice(0, input.indexOf("@")) + "@" + text;
|
||||
},
|
||||
'filter': Awesomplete.FILTER_STARTSWITH
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
addContactFromForm (ev) {
|
||||
ev.preventDefault();
|
||||
const data = new FormData(ev.target),
|
||||
|
@ -1,11 +0,0 @@
|
||||
<form class="pure-form add-xmpp-contact">
|
||||
{[ if (o.error_message) { ]}
|
||||
<span class="pure-form-message error">{{{o.error_message}}}</span>
|
||||
{[ } ]}
|
||||
<input type="text"
|
||||
name="identifier"
|
||||
value="{{{o.value}}}"
|
||||
class="username {[ if (o.error_message) { ]} error {[ } ]}"
|
||||
placeholder="{{{o.label_contact_username}}}"/>
|
||||
<button class="btn btn-primary" type="submit">{{{o.label_add}}}</button>
|
||||
</form>
|
@ -9,7 +9,7 @@
|
||||
<form class="converse-form add-xmpp-contact">
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label 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}}}"
|
||||
class="form-control {[ if (o.error_message) { ]} is-invalid {[ } ]}"
|
||||
placeholder="{{{o.contact_placeholder}}}">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<form class="room-invite">
|
||||
{[ if (o.error_message) { ]}
|
||||
<span class="pure-form-message error">{{{o.error_message}}}</span>
|
||||
<span class="error">{{{o.error_message}}}</span>
|
||||
{[ } ]}
|
||||
<input class="form-control invited-contact" placeholder="{{{o.label_invitation}}}" type="text"/>
|
||||
</form>
|
||||
|
Loading…
Reference in New Issue
Block a user