Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
95406a14
Commit
95406a14
authored
Mar 26, 2018
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-add `xhr_user_search_url` and autocomplete when adding contacts
parent
1e927294
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
340 additions
and
248 deletions
+340
-248
.eslintrc.json
.eslintrc.json
+1
-1
.travis.yml
.travis.yml
+1
-1
CHANGES.md
CHANGES.md
+6
-16
css/converse.css
css/converse.css
+68
-67
css/inverse.css
css/inverse.css
+68
-67
docs/source/configuration.rst
docs/source/configuration.rst
+35
-0
sass/_awesomplete.scss
sass/_awesomplete.scss
+51
-46
spec/chatroom.js
spec/chatroom.js
+2
-10
spec/controlbox.js
spec/controlbox.js
+74
-23
src/converse-rosterview.js
src/converse-rosterview.js
+32
-4
src/templates/add_contact_form.html
src/templates/add_contact_form.html
+0
-11
src/templates/add_contact_modal.html
src/templates/add_contact_modal.html
+1
-1
src/templates/chatroom_invite.html
src/templates/chatroom_invite.html
+1
-1
No files found.
.eslintrc.json
View file @
95406a14
...
...
@@ -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"
,
...
...
.travis.yml
View file @
95406a14
...
...
@@ -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
CHANGES.md
View file @
95406a14
...
...
@@ -2,29 +2,19 @@
## 4.0.0 (Unreleased)
##
Removed configuration setting
s
##
UI change
s
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
...
...
css/converse.css
View file @
95406a14
...
...
@@ -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
]
{
#converse-embedded-chat
[
hidden
],
#conversejs
[
hidden
]
{
display
:
none
;
}
#converse-embedded-chat
.visually-hidden
,
#conversejs
.visually-hidden
{
#converse-embedded-chat
.visually-hidden
,
#conversejs
.visually-hidden
{
position
:
absolute
;
clip
:
rect
(
0
,
0
,
0
,
0
);
}
#converse-embedded-chat
div
.awesomplete
,
#conversejs
div
.awesomplete
{
#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,24 +8623,6 @@ 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
[
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
:
""
;
...
...
@@ -8657,24 +8642,40 @@ body.reset {
text-overflow
:
ellipsis
;
overflow-x
:
hidden
;
position
:
relative
;
cursor
:
pointer
;
}
#converse-embedded-chat
div
.awesomplete
>
ul
>
li
:hover
,
#conversejs
div
.awesomplete
>
ul
>
li
:hover
{
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
{
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"
]
{
#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
{
#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
{
#converse-embedded-chat
div
.awesomplete
li
[
aria-selected
=
"true"
]
mark
,
#conversejs
div
.awesomplete
li
[
aria-selected
=
"true"
]
mark
{
background
:
#3d6b00
;
color
:
inherit
;
}
...
...
css/inverse.css
View file @
95406a14
...
...
@@ -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
]
{
#converse-embedded-chat
[
hidden
],
#conversejs
[
hidden
]
{
display
:
none
;
}
#converse-embedded-chat
.visually-hidden
,
#conversejs
.visually-hidden
{
#converse-embedded-chat
.visually-hidden
,
#conversejs
.visually-hidden
{
position
:
absolute
;
clip
:
rect
(
0
,
0
,
0
,
0
);
}
#converse-embedded-chat
div
.awesomplete
,
#conversejs
div
.awesomplete
{
#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,24 +8735,6 @@ 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
[
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
:
""
;
...
...
@@ -8769,24 +8754,40 @@ body {
text-overflow
:
ellipsis
;
overflow-x
:
hidden
;
position
:
relative
;
cursor
:
pointer
;
}
#converse-embedded-chat
div
.awesomplete
>
ul
>
li
:hover
,
#conversejs
div
.awesomplete
>
ul
>
li
:hover
{
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
{
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"
]
{
#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
{
#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
{
#converse-embedded-chat
div
.awesomplete
li
[
aria-selected
=
"true"
]
mark
,
#conversejs
div
.awesomplete
li
[
aria-selected
=
"true"
]
mark
{
background
:
#3d6b00
;
color
:
inherit
;
}
...
...
docs/source/configuration.rst
View file @
95406a14
...
...
@@ -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.
sass/_awesomplete.scss
View file @
95406a14
...
...
@@ -7,16 +7,38 @@
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
{
>
input
{
display
:
block
;
}
div
.awesomplete
>
ul
{
>
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
;
...
...
@@ -32,6 +54,15 @@
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
;
...
...
spec/chatroom.js
View file @
95406a14
...
...
@@ -1358,15 +1358,7 @@
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
;
...
...
spec/controlbox.js
View file @
95406a14
...
...
@@ -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
]
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
'
);
});
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
();
}).
then
(
function
()
{
expect
(
modal
.
el
.
querySelector
(
'
.awesomplete li
'
).
textContent
).
toBe
(
'
marty@mcfly.net
'
);
done
();
});
}));
...
...
src/converse-rosterview.js
View file @
95406a14
...
...
@@ -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
),
...
...
src/templates/add_contact_form.html
deleted
100644 → 0
View file @
1e927294
<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>
src/templates/add_contact_modal.html
View file @
95406a14
...
...
@@ -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}}}"
>
...
...
src/templates/chatroom_invite.html
View file @
95406a14
<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>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment