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-condition": "off",
|
||||||
"no-negated-in-lhs": "error",
|
"no-negated-in-lhs": "error",
|
||||||
"no-nested-ternary": "off",
|
"no-nested-ternary": "off",
|
||||||
"no-new": "error",
|
"no-new": "off",
|
||||||
"no-new-func": "error",
|
"no-new-func": "error",
|
||||||
"no-new-object": "error",
|
"no-new-object": "error",
|
||||||
"no-new-require": "error",
|
"no-new-require": "error",
|
||||||
|
@ -7,7 +7,7 @@ addons:
|
|||||||
chrome: stable
|
chrome: stable
|
||||||
node_js:
|
node_js:
|
||||||
- 6
|
- 6
|
||||||
install: make node_modules
|
install: make stamp-npm
|
||||||
before_script: make serve_bg
|
before_script: make serve_bg
|
||||||
script: make check
|
script: make check
|
||||||
sudo: false
|
sudo: false
|
||||||
|
22
CHANGES.md
22
CHANGES.md
@ -2,29 +2,19 @@
|
|||||||
|
|
||||||
## 4.0.0 (Unreleased)
|
## 4.0.0 (Unreleased)
|
||||||
|
|
||||||
## Removed configuration settings
|
## UI changes
|
||||||
|
|
||||||
Due to rewriting parts of the code, we regrettably had to remove certain
|
The UI is now based on Bootstrap4 and Flexbox is used extensively.
|
||||||
lesser-used configuration settings because the cost of adding them to the
|
|
||||||
new code was too high.
|
|
||||||
|
|
||||||
If you relied on any of these settings, you can reproduce their
|
## Configuration changes
|
||||||
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.
|
|
||||||
|
|
||||||
* Removed the `xhr_custom_status` and `xhr_custom_status_url` configuration
|
* Removed the `xhr_custom_status` and `xhr_custom_status_url` configuration
|
||||||
settings. If you relied on these settings, you can instead listen for the
|
settings. If you relied on these settings, you can instead listen for the
|
||||||
[statusMessageChanged](https://conversejs.org/docs/html/events.html#contactstatusmessagechanged)
|
[statusMessageChanged](https://conversejs.org/docs/html/events.html#contactstatusmessagechanged)
|
||||||
event and make the XMLHttpRequest yourself.
|
event and make the XMLHttpRequest yourself.
|
||||||
* Removed the `xhr_user_search` and `xhr_user_search_url` configuration options.
|
* 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
|
||||||
## Updated UI
|
`jid` instead of just an `id`.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
### Bugfixes
|
### 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 {
|
#conversejs:not(.fullscreen) #minimized-chats .chat-head-message-count-hidden {
|
||||||
display: none; }
|
display: none; }
|
||||||
|
|
||||||
#converse-embedded-chat,
|
#converse-embedded-chat [hidden],
|
||||||
#conversejs {
|
#conversejs [hidden] {
|
||||||
/* Pointer */ }
|
display: none; }
|
||||||
#converse-embedded-chat [hidden],
|
#converse-embedded-chat .visually-hidden,
|
||||||
#conversejs [hidden] {
|
#conversejs .visually-hidden {
|
||||||
display: none; }
|
position: absolute;
|
||||||
#converse-embedded-chat .visually-hidden,
|
clip: rect(0, 0, 0, 0); }
|
||||||
#conversejs .visually-hidden {
|
#converse-embedded-chat .form-group .awesomplete,
|
||||||
position: absolute;
|
#conversejs .form-group .awesomplete {
|
||||||
clip: rect(0, 0, 0, 0); }
|
width: 100%; }
|
||||||
#converse-embedded-chat div.awesomplete,
|
#converse-embedded-chat div.awesomplete,
|
||||||
#conversejs div.awesomplete {
|
#conversejs div.awesomplete {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative; }
|
position: relative; }
|
||||||
|
#converse-embedded-chat div.awesomplete mark,
|
||||||
|
#conversejs div.awesomplete mark {
|
||||||
|
background: #FFB9A7; }
|
||||||
#converse-embedded-chat div.awesomplete > input,
|
#converse-embedded-chat div.awesomplete > input,
|
||||||
#conversejs div.awesomplete > input {
|
#conversejs div.awesomplete > input {
|
||||||
display: block; }
|
display: block; }
|
||||||
@ -8620,62 +8623,60 @@ body.reset {
|
|||||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
|
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
|
||||||
text-shadow: none; }
|
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[hidden],
|
||||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||||
#conversejs div.awesomplete > ul[hidden],
|
#conversejs div.awesomplete > ul[hidden],
|
||||||
#conversejs div.awesomplete > ul:empty {
|
#conversejs div.awesomplete > ul:empty {
|
||||||
display: none; }
|
opacity: 0;
|
||||||
@supports (transform: scale(0)) {
|
transform: scale(0);
|
||||||
#converse-embedded-chat div.awesomplete > ul,
|
display: block;
|
||||||
#conversejs div.awesomplete > ul {
|
transition-timing-function: ease; } }
|
||||||
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
|
#converse-embedded-chat div.awesomplete > ul > li:hover,
|
||||||
transform-origin: 1.43em -.43em; }
|
#conversejs div.awesomplete > ul > li:hover {
|
||||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
background: #E77051;
|
||||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
color: white; }
|
||||||
#conversejs div.awesomplete > ul[hidden],
|
#converse-embedded-chat div.awesomplete > ul > li[aria-selected="true"],
|
||||||
#conversejs div.awesomplete > ul:empty {
|
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
|
||||||
opacity: 0;
|
background: #3d6d8f;
|
||||||
transform: scale(0);
|
color: white; }
|
||||||
display: block;
|
#converse-embedded-chat div.awesomplete li:hover mark,
|
||||||
transition-timing-function: ease; } }
|
#conversejs div.awesomplete li:hover mark {
|
||||||
#converse-embedded-chat div.awesomplete > ul:before,
|
background: #A53214;
|
||||||
#conversejs div.awesomplete > ul:before {
|
color: white; }
|
||||||
content: "";
|
#converse-embedded-chat div.awesomplete li[aria-selected="true"] mark,
|
||||||
position: absolute;
|
#conversejs div.awesomplete li[aria-selected="true"] mark {
|
||||||
top: -.43em;
|
background: #3d6b00;
|
||||||
left: 1em;
|
color: inherit; }
|
||||||
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; }
|
|
||||||
|
|
||||||
/*# sourceMappingURL=converse.css.map */
|
/*# sourceMappingURL=converse.css.map */
|
||||||
|
135
css/inverse.css
135
css/inverse.css
@ -8698,20 +8698,23 @@ body {
|
|||||||
border: 1.2em solid #E7A151;
|
border: 1.2em solid #E7A151;
|
||||||
border-top: 0.8em solid #E7A151; }
|
border-top: 0.8em solid #E7A151; }
|
||||||
|
|
||||||
#converse-embedded-chat,
|
#converse-embedded-chat [hidden],
|
||||||
#conversejs {
|
#conversejs [hidden] {
|
||||||
/* Pointer */ }
|
display: none; }
|
||||||
#converse-embedded-chat [hidden],
|
#converse-embedded-chat .visually-hidden,
|
||||||
#conversejs [hidden] {
|
#conversejs .visually-hidden {
|
||||||
display: none; }
|
position: absolute;
|
||||||
#converse-embedded-chat .visually-hidden,
|
clip: rect(0, 0, 0, 0); }
|
||||||
#conversejs .visually-hidden {
|
#converse-embedded-chat .form-group .awesomplete,
|
||||||
position: absolute;
|
#conversejs .form-group .awesomplete {
|
||||||
clip: rect(0, 0, 0, 0); }
|
width: 100%; }
|
||||||
#converse-embedded-chat div.awesomplete,
|
#converse-embedded-chat div.awesomplete,
|
||||||
#conversejs div.awesomplete {
|
#conversejs div.awesomplete {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative; }
|
position: relative; }
|
||||||
|
#converse-embedded-chat div.awesomplete mark,
|
||||||
|
#conversejs div.awesomplete mark {
|
||||||
|
background: #FFB9A7; }
|
||||||
#converse-embedded-chat div.awesomplete > input,
|
#converse-embedded-chat div.awesomplete > input,
|
||||||
#conversejs div.awesomplete > input {
|
#conversejs div.awesomplete > input {
|
||||||
display: block; }
|
display: block; }
|
||||||
@ -8732,62 +8735,60 @@ body {
|
|||||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||||
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
|
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
|
||||||
text-shadow: none; }
|
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[hidden],
|
||||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
#converse-embedded-chat div.awesomplete > ul:empty,
|
||||||
#conversejs div.awesomplete > ul[hidden],
|
#conversejs div.awesomplete > ul[hidden],
|
||||||
#conversejs div.awesomplete > ul:empty {
|
#conversejs div.awesomplete > ul:empty {
|
||||||
display: none; }
|
opacity: 0;
|
||||||
@supports (transform: scale(0)) {
|
transform: scale(0);
|
||||||
#converse-embedded-chat div.awesomplete > ul,
|
display: block;
|
||||||
#conversejs div.awesomplete > ul {
|
transition-timing-function: ease; } }
|
||||||
transition: 0.3s cubic-bezier(0.4, 0.2, 0.5, 1.4);
|
#converse-embedded-chat div.awesomplete > ul > li:hover,
|
||||||
transform-origin: 1.43em -.43em; }
|
#conversejs div.awesomplete > ul > li:hover {
|
||||||
#converse-embedded-chat div.awesomplete > ul[hidden],
|
background: #E77051;
|
||||||
#converse-embedded-chat div.awesomplete > ul:empty,
|
color: white; }
|
||||||
#conversejs div.awesomplete > ul[hidden],
|
#converse-embedded-chat div.awesomplete > ul > li[aria-selected="true"],
|
||||||
#conversejs div.awesomplete > ul:empty {
|
#conversejs div.awesomplete > ul > li[aria-selected="true"] {
|
||||||
opacity: 0;
|
background: #3d6d8f;
|
||||||
transform: scale(0);
|
color: white; }
|
||||||
display: block;
|
#converse-embedded-chat div.awesomplete li:hover mark,
|
||||||
transition-timing-function: ease; } }
|
#conversejs div.awesomplete li:hover mark {
|
||||||
#converse-embedded-chat div.awesomplete > ul:before,
|
background: #A53214;
|
||||||
#conversejs div.awesomplete > ul:before {
|
color: white; }
|
||||||
content: "";
|
#converse-embedded-chat div.awesomplete li[aria-selected="true"] mark,
|
||||||
position: absolute;
|
#conversejs div.awesomplete li[aria-selected="true"] mark {
|
||||||
top: -.43em;
|
background: #3d6b00;
|
||||||
left: 1em;
|
color: inherit; }
|
||||||
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; }
|
|
||||||
|
|
||||||
/*# sourceMappingURL=inverse.css.map */
|
/*# sourceMappingURL=inverse.css.map */
|
||||||
|
@ -1535,3 +1535,38 @@ Example:
|
|||||||
whitelisted_plugins: ['myplugin']
|
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);
|
clip: rect(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
.awesomplete {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
div.awesomplete {
|
div.awesomplete {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
mark {
|
||||||
|
background: $lightest-red;
|
||||||
|
}
|
||||||
|
|
||||||
div.awesomplete > input {
|
> input {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.awesomplete > ul {
|
> ul {
|
||||||
position: absolute;
|
&:before {
|
||||||
left: 0;
|
content: "";
|
||||||
right: 0;
|
position: absolute;
|
||||||
z-index: 1;
|
top: -.43em;
|
||||||
min-width: 100%;
|
left: 1em;
|
||||||
box-sizing: border-box;
|
width: 0; height: 0;
|
||||||
list-style: none;
|
background: white;
|
||||||
padding: 0;
|
border: inherit;
|
||||||
border-radius: .3em;
|
border-right: 0;
|
||||||
margin: .2em 0 0;
|
border-bottom: 0;
|
||||||
background: hsla(0,0%,100%,.9);
|
-webkit-transform: rotate(45deg);
|
||||||
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
|
transform: rotate(45deg);
|
||||||
border: 1px solid rgba(0,0,0,.3);
|
}
|
||||||
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
|
|
||||||
text-shadow: none;
|
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],
|
div.awesomplete > ul[hidden],
|
||||||
@ -53,28 +84,6 @@
|
|||||||
transition-timing-function: ease;
|
transition-timing-function: ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 {
|
div.awesomplete > ul > li:hover {
|
||||||
background: $red;
|
background: $red;
|
||||||
@ -86,10 +95,6 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.awesomplete mark {
|
|
||||||
background: $lightest-red;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.awesomplete li:hover mark {
|
div.awesomplete li:hover mark {
|
||||||
background: $darkest-red;
|
background: $darkest-red;
|
||||||
color: $inverse-link-color;
|
color: $inverse-link-color;
|
||||||
|
@ -1353,20 +1353,12 @@
|
|||||||
$(view.el).find('.chat-area').remove();
|
$(view.el).find('.chat-area').remove();
|
||||||
|
|
||||||
test_utils.waitUntil(function () {
|
test_utils.waitUntil(function () {
|
||||||
return $(view.el).find('input.invited-contact').length;
|
return $(view.el).find('input.invited-contact').length;
|
||||||
}, 300).then(function () {
|
}, 300).then(function () {
|
||||||
var $input = $(view.el).find('input.invited-contact');
|
var $input = $(view.el).find('input.invited-contact');
|
||||||
expect($input.attr('placeholder')).toBe('Invite');
|
expect($input.attr('placeholder')).toBe('Invite');
|
||||||
$input.val("Felix");
|
$input.val("Felix");
|
||||||
var evt;
|
var evt = new Event('input');
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
$input[0].dispatchEvent(evt);
|
$input[0].dispatchEvent(evt);
|
||||||
|
|
||||||
var sent_stanza;
|
var sent_stanza;
|
||||||
|
@ -33,6 +33,37 @@
|
|||||||
|
|
||||||
describe("The \"Contacts\" section", function () {
|
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",
|
it("shows the number of unread mentions received",
|
||||||
mock.initConverseWithPromises(
|
mock.initConverseWithPromises(
|
||||||
null, ['rosterGroupsFetched'], {},
|
null, ['rosterGroupsFetched'], {},
|
||||||
@ -157,6 +188,8 @@
|
|||||||
null, ['rosterGroupsFetched'], {},
|
null, ['rosterGroupsFetched'], {},
|
||||||
function (done, _converse) {
|
function (done, _converse) {
|
||||||
|
|
||||||
|
test_utils.createContacts(_converse, 'all').openControlBox();
|
||||||
|
|
||||||
var panel = _converse.chatboxviews.get('controlbox').contactspanel;
|
var panel = _converse.chatboxviews.get('controlbox').contactspanel;
|
||||||
var cbview = _converse.chatboxviews.get('controlbox');
|
var cbview = _converse.chatboxviews.get('controlbox');
|
||||||
cbview.el.querySelector('.add-contact').click()
|
cbview.el.querySelector('.add-contact').click()
|
||||||
@ -165,37 +198,55 @@
|
|||||||
return u.isVisible(modal.el);
|
return u.isVisible(modal.el);
|
||||||
}, 1000).then(function () {
|
}, 1000).then(function () {
|
||||||
expect(!_.isNull(modal.el.querySelector('form.add-xmpp-contact'))).toBeTruthy();
|
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();
|
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(
|
mock.initConverseWithPromises(
|
||||||
null, ['rosterGroupsFetched'], {},
|
null, ['rosterGroupsFetched'],
|
||||||
|
{ 'xhr_user_search': true,
|
||||||
|
'xhr_user_search_url': 'http://example.org/'
|
||||||
|
},
|
||||||
function (done, _converse) {
|
function (done, _converse) {
|
||||||
|
|
||||||
spyOn(_converse, 'emit');
|
var xhr = {
|
||||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
'open': _.noop,
|
||||||
test_utils.openControlBox();
|
'send': function () {
|
||||||
// Adding two contacts one with Capital initials and one with small initials of same JID (Case sensitive check)
|
xhr.responseText = JSON.stringify([
|
||||||
_converse.roster.create({
|
{"jid": "marty@mcfly.net", "fullname": "Marty McFly"},
|
||||||
jid: mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@localhost',
|
{"jid": "doc@brown.com", "fullname": "Doc Brown"}
|
||||||
subscription: 'none',
|
]);
|
||||||
ask: 'subscribe',
|
xhr.onload();
|
||||||
fullname: mock.pend_names[0]
|
}
|
||||||
|
};
|
||||||
|
window.XMLHttpRequest = jasmine.createSpy('XMLHttpRequest');
|
||||||
|
XMLHttpRequest.and.callFake(function () {
|
||||||
|
return xhr;
|
||||||
});
|
});
|
||||||
_converse.roster.create({
|
|
||||||
jid: mock.pend_names[0].replace(/ /g,'.') + '@localhost',
|
var panel = _converse.chatboxviews.get('controlbox').contactspanel;
|
||||||
subscription: 'none',
|
var cbview = _converse.chatboxviews.get('controlbox');
|
||||||
ask: 'subscribe',
|
cbview.el.querySelector('.add-contact').click()
|
||||||
fullname: mock.pend_names[0]
|
var modal = _converse.rosterview.add_contact_modal;
|
||||||
});
|
return test_utils.waitUntil(function () {
|
||||||
test_utils.waitUntil(function () {
|
return u.isVisible(modal.el);
|
||||||
return $(_converse.rosterview.el).find('.roster-group li:visible').length;
|
}, 1000).then(function () {
|
||||||
}, 700).then(function () {
|
var input_el = modal.el.querySelector('input[name="jid"]');
|
||||||
// Checking that only one entry is created because both JID is same (Case sensitive check)
|
input_el.value = 'marty@';
|
||||||
expect($(_converse.rosterview.el).find('li:visible').length).toBe(1);
|
var evt = new Event('input');
|
||||||
expect(_converse.rosterview.update).toHaveBeenCalled();
|
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();
|
done();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"tpl!roster_filter",
|
"tpl!roster_filter",
|
||||||
"tpl!roster_item",
|
"tpl!roster_item",
|
||||||
"tpl!search_contact",
|
"tpl!search_contact",
|
||||||
|
"awesomplete",
|
||||||
"converse-chatboxes",
|
"converse-chatboxes",
|
||||||
"converse-modal"
|
"converse-modal"
|
||||||
], factory);
|
], factory);
|
||||||
@ -28,7 +29,8 @@
|
|||||||
tpl_roster,
|
tpl_roster,
|
||||||
tpl_roster_filter,
|
tpl_roster_filter,
|
||||||
tpl_roster_item,
|
tpl_roster_item,
|
||||||
tpl_search_contact
|
tpl_search_contact,
|
||||||
|
Awesomplete
|
||||||
) {
|
) {
|
||||||
"use strict";
|
"use strict";
|
||||||
const { Backbone, Strophe, $iq, b64_sha1, sizzle, _ } = converse.env;
|
const { Backbone, Strophe, $iq, b64_sha1, sizzle, _ } = converse.env;
|
||||||
@ -78,9 +80,10 @@
|
|||||||
{ __ } = _converse;
|
{ __ } = _converse;
|
||||||
|
|
||||||
_converse.api.settings.update({
|
_converse.api.settings.update({
|
||||||
allow_chat_pending_contacts: true,
|
'allow_chat_pending_contacts': true,
|
||||||
allow_contact_removal: true,
|
'allow_contact_removal': true,
|
||||||
show_toolbar: true,
|
'show_toolbar': true,
|
||||||
|
'xhr_user_search_url': null
|
||||||
});
|
});
|
||||||
_converse.api.promises.add('rosterViewInitialized');
|
_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) {
|
addContactFromForm (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
const data = new FormData(ev.target),
|
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">
|
<form class="converse-form add-xmpp-contact">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="form-group">
|
<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}}}"
|
<input type="text" name="jid" required="required" value="{{{o.jid}}}"
|
||||||
class="form-control {[ if (o.error_message) { ]} is-invalid {[ } ]}"
|
class="form-control {[ if (o.error_message) { ]} is-invalid {[ } ]}"
|
||||||
placeholder="{{{o.contact_placeholder}}}">
|
placeholder="{{{o.contact_placeholder}}}">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<form class="room-invite">
|
<form class="room-invite">
|
||||||
{[ if (o.error_message) { ]}
|
{[ 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"/>
|
<input class="form-control invited-contact" placeholder="{{{o.label_invitation}}}" type="text"/>
|
||||||
</form>
|
</form>
|
||||||
|
Loading…
Reference in New Issue
Block a user