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
acd9a186
Commit
acd9a186
authored
Jul 20, 2018
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update with new message markup
parent
6a462f6c
Changes
17
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
386 additions
and
428 deletions
+386
-428
css/converse.css
css/converse.css
+17
-29
dist/converse.js
dist/converse.js
+91
-91
mockup/chatroom.html
mockup/chatroom.html
+7
-3
sass/_chatbox.scss
sass/_chatbox.scss
+1
-31
sass/_messages.scss
sass/_messages.scss
+16
-2
spec/chatbox.js
spec/chatbox.js
+14
-14
spec/chatroom.js
spec/chatroom.js
+8
-8
spec/http-file-upload.js
spec/http-file-upload.js
+3
-3
spec/messages.js
spec/messages.js
+170
-177
spec/spoilers.js
spec/spoilers.js
+8
-8
src/converse-chatview.js
src/converse-chatview.js
+5
-7
src/converse-message-view.js
src/converse-message-view.js
+14
-19
src/templates/action.html
src/templates/action.html
+0
-6
src/templates/file_progress.html
src/templates/file_progress.html
+3
-3
src/templates/message.html
src/templates/message.html
+21
-10
src/templates/spoiler_message.html
src/templates/spoiler_message.html
+0
-14
src/utils/core.js
src/utils/core.js
+8
-3
No files found.
css/converse.css
View file @
acd9a186
...
...
@@ -7381,7 +7381,7 @@ body.reset {
background-color
:
#3AA569
;
box-shadow
:
1px
3px
5px
3px
rgba
(
0
,
0
,
0
,
0.4
);
z-index
:
1
;
overflow-y
:
scroll
;
overflow-y
:
hidden
;
width
:
100%
;
}
@media
screen
and
(
max-height
:
450px
)
{
#conversejs
.chatbox
.box-flyout
{
...
...
@@ -7648,18 +7648,6 @@ body.reset {
#conversejs
.converse-overlayed
.chatbox
.box-flyout
{
min-width
:
250px
!important
;
width
:
250px
;
}
#conversejs
.converse-embedded
.chatbox
.chat-body
.chat-message
,
#conversejs
.converse-overlayed
.chatbox
.chat-body
.chat-message
{
line-height
:
20px
;
}
#conversejs
.converse-embedded
.chatbox
.chat-body
.chat-message
.chat-msg-author
,
#conversejs
.converse-overlayed
.chatbox
.chat-body
.chat-message
.chat-msg-author
{
line-height
:
20px
;
}
#conversejs
.converse-embedded
.chatbox
.chat-body
.chat-message
.chat-msg-content
,
#conversejs
.converse-overlayed
.chatbox
.chat-body
.chat-message
.chat-msg-content
{
line-height
:
20px
;
}
#conversejs
.converse-embedded
.chatbox
.chat-body
.chat-message
.chat-msg-content
.emojione
,
#conversejs
.converse-overlayed
.chatbox
.chat-body
.chat-message
.chat-msg-content
.emojione
{
margin-bottom
:
-5px
;
}
#conversejs
.converse-embedded
.chatbox
form
.sendXMPPMessage
.chat-toolbar
li
.toolbar-menu
,
#conversejs
.converse-overlayed
.chatbox
form
.sendXMPPMessage
.chat-toolbar
li
.toolbar-menu
{
min-width
:
235px
;
}
...
...
@@ -7746,16 +7734,6 @@ body.reset {
background-color
:
#3AA569
;
border-top-left-radius
:
4px
;
border-top-right-radius
:
4px
;
}
#conversejs
.converse-fullscreen
.chatbox
.chat-body
.chat-message
{
line-height
:
16px
;
font-size
:
12px
;
}
#conversejs
.converse-fullscreen
.chatbox
.chat-body
.chat-message
.chat-msg-author
{
line-height
:
16px
;
}
#conversejs
.converse-fullscreen
.chatbox
.chat-body
.chat-message
.chat-msg-content
{
line-height
:
16px
;
}
#conversejs
.converse-fullscreen
.chatbox
.chat-body
.chat-message
.chat-msg-content
.emojione
{
height
:
16px
;
margin-bottom
:
-4px
;
}
#conversejs
.converse-fullscreen
.chatbox
.chat-content
{
border-top-left-radius
:
4px
;
border-top-right-radius
:
4px
;
}
...
...
@@ -8884,6 +8862,8 @@ body.reset {
align-items
:
stretch
;
margin-left
:
0.5rem
;
width
:
100%
;
}
#conversejs
.message.chat-msg
.chat-msg__content--action
{
margin-left
:
0
;
}
#conversejs
.message.chat-msg
.chat-msg__body
{
display
:
flex
;
flex-direction
:
row
;
...
...
@@ -8893,8 +8873,9 @@ body.reset {
display
:
flex
;
flex-direction
:
column
;
width
:
100%
;
}
#conversejs
.message.chat-msg
.chat-msg-edited
{
cursor
:
pointer
;
}
#conversejs
.message.chat-msg
.chat-msg__edit-modal
{
cursor
:
pointer
;
padding-right
:
0.5em
;
}
#conversejs
.message.chat-msg.headline
.chat-msg__body
{
margin-left
:
0
;
}
#conversejs
.message.chat-msg
.chat-msg__text
{
...
...
@@ -8906,11 +8887,12 @@ body.reset {
word-break
:
break-all
;
}
#conversejs
.message.chat-msg
.chat-msg__text
.emojione
{
margin-bottom
:
-6px
;
}
#conversejs
.message.chat-msg
.chat-msg-media
{
margin-top
:
0.25rem
;
}
#conversejs
.message.chat-msg
.chat-msg-media
a
{
#conversejs
.message.chat-msg
.chat-msg__media
{
margin-top
:
0.25rem
;
word-break
:
break-all
;
}
#conversejs
.message.chat-msg
.chat-msg__media
a
{
word-wrap
:
break-word
;
}
#conversejs
.message.chat-msg
.chat-msg
-
media
audio
{
#conversejs
.message.chat-msg
.chat-msg
__
media
audio
{
width
:
100%
;
}
#conversejs
.message.chat-msg
.chat-msg__actions
.chat-msg__action
{
height
:
14px
;
...
...
@@ -8934,6 +8916,7 @@ body.reset {
padding-bottom
:
0.25rem
;
display
:
block
;
}
#conversejs
.message.chat-msg
.chat-msg__heading
.chat-msg__author
{
white-space
:
nowrap
;
font-family
:
"Century Gothic"
,
futura
,
"URW Gothic L"
,
Verdana
,
sans-serif
;
font-size
:
115%
;
}
#conversejs
.message.chat-msg
.chat-msg__heading
.chat-msg__author
.badge
{
...
...
@@ -8943,6 +8926,7 @@ body.reset {
padding-left
:
0.25em
;
color
:
#8c8c8c
;
}
#conversejs
.message.chat-msg.chat-msg--action
.chat-msg__content
{
flex-wrap
:
wrap
;
flex-direction
:
row
;
justify-content
:
flex-start
;
}
#conversejs
.message.chat-msg.chat-msg--action
.chat-msg__text
{
...
...
@@ -8951,6 +8935,10 @@ body.reset {
margin-top
:
0
;
padding-bottom
:
0
;
width
:
auto
;
}
#conversejs
.message.chat-msg.chat-msg--action
.chat-msg__author
{
font-size
:
14px
;
}
#conversejs
.message.chat-msg.chat-msg--action
.chat-msg__time
{
margin-left
:
0
;
}
#conversejs
.message.chat-msg.chat-msg--followup
.chat-msg__heading
,
#conversejs
.message.chat-msg.chat-msg--followup
.chat-msg__avatar
{
display
:
none
;
}
...
...
dist/converse.js
View file @
acd9a186
This diff is collapsed.
Click to expand it.
mockup/chatroom.html
View file @
acd9a186
...
...
@@ -45,8 +45,11 @@
Romeo Montague has entered the room
</div>
<div
class=
"message chat-msg chat-msg--action"
data-isodate=
"2018-04-36T18:07:38+02:00"
>
<div
class=
"chat-msg__content"
>
<span
class=
"chat-msg__heading"
><span
class=
"chat-msg__author"
>
**Romeo Montague
</span></span>
<div
class=
"chat-msg__content chat-msg__content--action"
>
<span
class=
"chat-msg__heading"
>
<time
timestamp=
"2018-12-29"
class=
"chat-msg__time"
>
15:29
</time>
<span
class=
"chat-msg__author"
>
**Romeo Montague
</span>
</span>
<span
class=
"chat-msg__text"
>
looks around
</span>
</div>
</div>
...
...
@@ -177,7 +180,7 @@
</div>
<div
class=
"chat-msg__body"
>
<div
class=
"chat-msg__message"
>
<div
class=
"chat-msg
-
media"
>
<div
class=
"chat-msg
__
media"
>
<a
href=
"https://images.unsplash.com/photo-1496660067708-010ebdd7ce72?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ea3514e6e00d8ce25c24d992b97929d9&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb"
target=
"_blank"
rel=
"noopener"
>
<img
class=
"chat-image img-thumbnail"
src=
"https://images.unsplash.com/photo-1496660067708-010ebdd7ce72?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ea3514e6e00d8ce25c24d992b97929d9&dpr=1&auto=format&fit=crop&w=1000&q=80&cs=tinysrgb"
>
...
...
@@ -227,6 +230,7 @@
<span
class=
"chat-msg__time"
>
19:49
</span>
</div>
<div
class=
"chat-msg__body"
>
<i
title=
"This message has been edited"
class=
"fa fa-edit chat-msg__edit-modal"
></i>
<div
class=
"chat-msg__message"
>
<span
class=
"chat-msg__text"
>
I mean, sir, in delay We waste our lights in vain, like lamps by day.
</span>
</div>
...
...
sass/_chatbox.scss
View file @
acd9a186
...
...
@@ -124,7 +124,7 @@
background-color
:
$chat-head-color
;
box-shadow
:
1px
3px
5px
3px
rgba
(
0
,
0
,
0
,
0
.4
);
z-index
:
1
;
overflow-y
:
scroll
;
overflow-y
:
hidden
;
width
:
100%
;
@media
screen
and
(
max-height
:
$mobile-landscape-height
)
{
...
...
@@ -464,21 +464,6 @@
min-width
:
$overlayed-chat-width
!
important
;
width
:
$overlayed-chat-width
;
}
.chat-body
{
.chat-message
{
line-height
:
$line-height-large
;
.chat-msg-author
{
line-height
:
$line-height-large
;
}
.chat-msg-content
{
line-height
:
$line-height-large
;
.emojione
{
margin-bottom
:
-5px
;
}
}
}
}
}
.chatbox
{
form
.sendXMPPMessage
{
...
...
@@ -597,21 +582,6 @@
background-color
:
$chat-head-color
;
border-top-left-radius
:
$chatbox-border-radius
;
border-top-right-radius
:
$chatbox-border-radius
;
.chat-message
{
line-height
:
$line-height
;
font-size
:
$font-size-small
;
.chat-msg-author
{
line-height
:
$line-height
;
}
.chat-msg-content
{
line-height
:
$line-height
;
.emojione
{
height
:
$line-height
;
margin-bottom
:
-
$line-height
/
4
;
}
}
}
}
.chat-content
{
border-top-left-radius
:
$chatbox-border-radius
;
...
...
sass/_messages.scss
View file @
acd9a186
...
...
@@ -104,6 +104,7 @@
whitespace
:
nowrap
;
}
}
.chat-msg__content
{
display
:
flex
;
flex-direction
:
column
;
...
...
@@ -112,6 +113,9 @@
margin-left
:
0
.5rem
;
width
:
100%
;
}
.chat-msg__content--action
{
margin-left
:
0
;
}
.chat-msg__body
{
display
:
flex
;
...
...
@@ -126,8 +130,9 @@
width
:
100%
;
}
.chat-msg
-edited
{
.chat-msg
__edit-modal
{
cursor
:
pointer
;
padding-right
:
0
.5em
;
}
&
.headline
{
.chat-msg__body
{
...
...
@@ -148,8 +153,9 @@
}
}
.chat-msg
-
media
{
.chat-msg
__
media
{
margin-top
:
0
.25rem
;
word-break
:
break-all
;
a
{
word-wrap
:
break-word
;
}
...
...
@@ -188,6 +194,7 @@
display
:
block
;
.chat-msg__author
{
white-space
:
nowrap
;
font-family
:
$heading-font
;
font-size
:
115%
;
.badge
{
...
...
@@ -202,6 +209,7 @@
}
&
.chat-msg--action
{
.chat-msg__content
{
flex-wrap
:
wrap
;
flex-direction
:
row
;
justify-content
:
flex-start
;
}
...
...
@@ -213,6 +221,12 @@
padding-bottom
:
0
;
width
:
auto
;
}
.chat-msg__author
{
font-size
:
$message-font-size
;
}
.chat-msg__time
{
margin-left
:
0
;
}
}
&
.chat-msg--followup
{
...
...
spec/chatbox.js
View file @
acd9a186
...
...
@@ -76,33 +76,33 @@
test_utils
.
waitUntil
(
function
()
{
return
u
.
isVisible
(
view
.
el
);
}).
then
(
function
()
{
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-action
'
).
length
).
toBe
(
1
);
expect
(
_
.
includes
(
view
.
el
.
querySelector
(
'
.chat-msg
-
author
'
).
textContent
,
'
**Max Frankfurter
'
)).
toBeTruthy
();
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
text
'
).
text
()).
toBe
(
'
is tired
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-
msg--
action
'
).
length
).
toBe
(
1
);
expect
(
_
.
includes
(
view
.
el
.
querySelector
(
'
.chat-msg
__
author
'
).
textContent
,
'
**Max Frankfurter
'
)).
toBeTruthy
();
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
text
'
).
text
()).
toBe
(
'
is tired
'
);
message
=
'
/me is as well
'
;
test_utils
.
sendMessage
(
view
,
message
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-action
'
).
length
).
toBe
(
2
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-
msg--
action
'
).
length
).
toBe
(
2
);
return
test_utils
.
waitUntil
(()
=>
$
(
view
.
el
).
find
(
'
.chat-msg
-author:last
'
).
text
()
===
'
**Max Mustermann
'
);
return
test_utils
.
waitUntil
(()
=>
$
(
view
.
el
).
find
(
'
.chat-msg
__author:last
'
).
text
().
trim
()
===
'
**Max Mustermann
'
);
}).
then
(
function
()
{
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
text:last
'
).
text
()).
toBe
(
'
is as well
'
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg:last
'
).
hasClass
(
'
chat-msg-followup
'
)).
toBe
(
false
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
text:last
'
).
text
()).
toBe
(
'
is as well
'
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg:last
'
).
hasClass
(
'
chat-msg-
-
followup
'
)).
toBe
(
false
);
// Check that /me messages after a normal message don't
// get the 'chat-msg-followup' class.
// get the 'chat-msg-
-
followup' class.
message
=
'
This a normal message
'
;
test_utils
.
sendMessage
(
view
,
message
);
let
message_el
=
view
.
el
.
querySelector
(
'
.message:last-child
'
);
expect
(
u
.
hasClass
(
'
chat-msg-followup
'
,
message_el
)).
toBeFalsy
();
expect
(
u
.
hasClass
(
'
chat-msg-
-
followup
'
,
message_el
)).
toBeFalsy
();
message
=
'
/me wrote a 3rd person message
'
;
test_utils
.
sendMessage
(
view
,
message
);
message_el
=
view
.
el
.
querySelector
(
'
.message:last-child
'
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-action
'
).
length
).
toBe
(
3
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
text:last
'
).
text
()).
toBe
(
'
wrote a 3rd person message
'
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
author:last
'
).
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
u
.
hasClass
(
'
chat-msg-followup
'
,
message_el
)).
toBeFalsy
();
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-
msg--
action
'
).
length
).
toBe
(
3
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
text:last
'
).
text
()).
toBe
(
'
wrote a 3rd person message
'
);
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
author:last
'
).
is
(
'
:visible
'
)).
toBeTruthy
();
expect
(
u
.
hasClass
(
'
chat-msg-
-
followup
'
,
message_el
)).
toBeFalsy
();
done
();
});
});
...
...
@@ -1627,7 +1627,7 @@
return
$
(
view
.
el
).
find
(
'
.chat-content
'
).
find
(
'
.chat-msg
'
).
length
;
},
1000
).
then
(
function
()
{
expect
(
view
.
model
.
sendMessage
).
toHaveBeenCalled
();
var
msg
=
$
(
view
.
el
).
find
(
'
.chat-content
'
).
find
(
'
.chat-msg
'
).
last
().
find
(
'
.chat-msg
-
text
'
);
var
msg
=
$
(
view
.
el
).
find
(
'
.chat-content
'
).
find
(
'
.chat-msg
'
).
last
().
find
(
'
.chat-msg
__
text
'
);
expect
(
msg
.
html
()).
toEqual
(
'
<a target="_blank" rel="noopener" href="https://www.openstreetmap.org/?mlat=37.786971&
'
+
'
mlon=-122.399677#map=18/37.786971/-122.399677">https://www.openstreetmap.org/?mlat=37.7869
'
+
...
...
spec/chatroom.js
View file @
acd9a186
...
...
@@ -867,8 +867,8 @@
'
type
'
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
message
).
tree
();
view
.
model
.
onMessage
(
msg
);
expect
(
_
.
includes
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
author
'
).
text
(),
'
**Dyon van de Wege
'
)).
toBeTruthy
();
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
text
'
).
text
()).
toBe
(
'
is tired
'
);
expect
(
_
.
includes
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
author
'
).
text
(),
'
**Dyon van de Wege
'
)).
toBeTruthy
();
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
text
'
).
text
()).
toBe
(
'
is tired
'
);
message
=
'
/me is as well
'
;
msg
=
$msg
({
...
...
@@ -878,8 +878,8 @@
type
:
'
groupchat
'
}).
c
(
'
body
'
).
t
(
message
).
tree
();
view
.
model
.
onMessage
(
msg
);
expect
(
_
.
includes
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
author:last
'
).
text
(),
'
**Max Mustermann
'
)).
toBeTruthy
();
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
-
text:last
'
).
text
()).
toBe
(
'
is as well
'
);
expect
(
_
.
includes
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
author:last
'
).
text
(),
'
**Max Mustermann
'
)).
toBeTruthy
();
expect
(
$
(
view
.
el
).
find
(
'
.chat-msg
__
text:last
'
).
text
()).
toBe
(
'
is as well
'
);
done
();
});
}));
...
...
@@ -1545,7 +1545,7 @@
view
.
model
.
onMessage
(
message
.
nodeTree
);
var
$chat_content
=
$
(
view
.
el
).
find
(
'
.chat-content
'
);
expect
(
$chat_content
.
find
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
$chat_content
.
find
(
'
.chat-msg
-
text
'
).
text
()).
toBe
(
text
);
expect
(
$chat_content
.
find
(
'
.chat-msg
__
text
'
).
text
()).
toBe
(
text
);
expect
(
_converse
.
emit
).
toHaveBeenCalledWith
(
'
message
'
,
jasmine
.
any
(
Object
));
done
();
});
...
...
@@ -1583,7 +1583,7 @@
}).
c
(
'
body
'
).
t
(
text
);
view
.
model
.
onMessage
(
message
.
nodeTree
);
expect
(
$chat_content
.
find
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
$chat_content
.
find
(
'
.chat-msg
-
text
'
).
last
().
text
()).
toBe
(
text
);
expect
(
$chat_content
.
find
(
'
.chat-msg
__
text
'
).
last
().
text
()).
toBe
(
text
);
// We don't emit an event if it's our own message
expect
(
_converse
.
emit
.
calls
.
count
(),
1
);
done
();
...
...
@@ -1624,7 +1624,7 @@
// Now check that the message appears inside the chatbox in the DOM
var
$chat_content
=
$
(
view
.
el
).
find
(
'
.chat-content
'
);
var
msg_txt
=
$chat_content
.
find
(
'
.chat-msg:last
'
).
find
(
'
.chat-msg
-
text
'
).
text
();
var
msg_txt
=
$chat_content
.
find
(
'
.chat-msg:last
'
).
find
(
'
.chat-msg
__
text
'
).
text
();
expect
(
msg_txt
).
toEqual
(
message
);
expect
(
view
.
content
.
scrollTop
).
toBe
(
0
);
done
();
...
...
@@ -3475,7 +3475,7 @@
var
messages
=
view
.
el
.
querySelectorAll
(
'
.message
'
);
expect
(
messages
.
length
).
toBe
(
8
);
expect
(
view
.
el
.
querySelectorAll
(
'
.chat-msg
'
).
length
).
toBe
(
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg
-
text
'
).
textContent
).
toBe
(
'
hello world
'
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg
__
text
'
).
textContent
).
toBe
(
'
hello world
'
);
// Test that the composing notifications get removed
// via timeout.
...
...
spec/http-file-upload.js
View file @
acd9a186
...
...
@@ -364,7 +364,7 @@
},
1000
);
}).
then
(
function
()
{
// Check that the image renders
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg
-
media
'
).
innerHTML
.
trim
()).
toEqual
(
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg
__
media
'
).
innerHTML
.
trim
()).
toEqual
(
'
<!-- src/templates/image.html -->
\n
'
+
'
<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">
'
+
'
<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg">
'
+
...
...
@@ -472,7 +472,7 @@
},
1000
);
}).
then
(
function
()
{
// Check that the image renders
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg
-
media
'
).
innerHTML
.
trim
()).
toEqual
(
expect
(
view
.
el
.
querySelector
(
'
.chat-msg .chat-msg
__
media
'
).
innerHTML
.
trim
()).
toEqual
(
'
<!-- src/templates/image.html -->
\n
'
+
'
<a href="http://localhost:8000/logo/conversejs-filled.svg" target="_blank" rel="noopener">
'
+
'
<img class="chat-image img-thumbnail" src="http://localhost:8000/logo/conversejs-filled.svg"></a>
'
)
...
...
@@ -683,7 +683,7 @@
expect
(
view
.
el
.
querySelector
(
'
.chat-content progress
'
).
getAttribute
(
'
value
'
)).
toBe
(
'
0.5
'
);
message
.
set
(
'
progress
'
,
1
);
expect
(
view
.
el
.
querySelector
(
'
.chat-content progress
'
).
getAttribute
(
'
value
'
)).
toBe
(
'
1
'
);
expect
(
view
.
el
.
querySelector
(
'
.chat-content .chat-msg
-
text
'
).
textContent
).
toBe
(
'
Uploading file: my-juliet.jpg, 22.91 KB
'
);
expect
(
view
.
el
.
querySelector
(
'
.chat-content .chat-msg
__
text
'
).
textContent
).
toBe
(
'
Uploading file: my-juliet.jpg, 22.91 KB
'
);
done
();
});
var
sent_stanza
;
...
...
spec/messages.js
View file @
acd9a186
This diff is collapsed.
Click to expand it.
spec/spoilers.js
View file @
acd9a186
...
...
@@ -40,9 +40,9 @@
return
test_utils
.
waitUntil
(()
=>
view
.
model
.
vcard
.
get
(
'
fullname
'
)
===
'
Max Frankfurter
'
)
.
then
(
function
()
{
expect
(
view
.
el
.
querySelector
(
'
.chat-msg
-author
'
).
textContent
).
toBe
(
'
Max Frankfurter
'
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg
__author
'
).
textContent
.
trim
()
).
toBe
(
'
Max Frankfurter
'
);
var
message_content
=
view
.
el
.
querySelector
(
'
.chat-msg
-
text
'
);
var
message_content
=
view
.
el
.
querySelector
(
'
.chat-msg
__
text
'
);
expect
(
message_content
.
textContent
).
toBe
(
spoiler
);
var
spoiler_hint_el
=
view
.
el
.
querySelector
(
'
.spoiler-hint
'
);
...
...
@@ -79,9 +79,9 @@
var
view
=
_converse
.
chatboxviews
.
get
(
sender_jid
);
return
test_utils
.
waitUntil
(()
=>
view
.
model
.
vcard
.
get
(
'
fullname
'
)
===
'
Max Frankfurter
'
)
.
then
(
function
()
{
expect
(
_
.
includes
(
view
.
el
.
querySelector
(
'
.chat-msg
-
author
'
).
textContent
,
'
Max Frankfurter
'
)).
toBeTruthy
();
expect
(
_
.
includes
(
view
.
el
.
querySelector
(
'
.chat-msg
__
author
'
).
textContent
,
'
Max Frankfurter
'
)).
toBeTruthy
();
var
message_content
=
view
.
el
.
querySelector
(
'
.chat-msg
-
text
'
);
var
message_content
=
view
.
el
.
querySelector
(
'
.chat-msg
__
text
'
);
expect
(
message_content
.
textContent
).
toBe
(
spoiler
);
var
spoiler_hint_el
=
view
.
el
.
querySelector
(
'
.spoiler-hint
'
);
...
...
@@ -148,9 +148,9 @@
expect
(
body_el
.
textContent
).
toBe
(
'
This is the spoiler
'
);
/* Test the HTML spoiler message */
expect
(
view
.
el
.
querySelector
(
'
.chat-msg
-author
'
).
textContent
).
toBe
(
'
Max Mustermann
'
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg
__author
'
).
textContent
.
trim
()
).
toBe
(
'
Max Mustermann
'
);
var
spoiler_msg_el
=
view
.
el
.
querySelector
(
'
.chat-msg
-
text.spoiler
'
);
var
spoiler_msg_el
=
view
.
el
.
querySelector
(
'
.chat-msg
__
text.spoiler
'
);
expect
(
spoiler_msg_el
.
textContent
).
toBe
(
'
This is the spoiler
'
);
expect
(
_
.
includes
(
spoiler_msg_el
.
classList
,
'
collapsed
'
)).
toBeTruthy
();
...
...
@@ -227,9 +227,9 @@
expect
(
body_el
.
textContent
).
toBe
(
'
This is the spoiler
'
);
/* Test the HTML spoiler message */
expect
(
view
.
el
.
querySelector
(
'
.chat-msg
-author
'
).
textContent
).
toBe
(
'
Max Mustermann
'
);
expect
(
view
.
el
.
querySelector
(
'
.chat-msg
__author
'
).
textContent
.
trim
()
).
toBe
(
'
Max Mustermann
'
);
var
spoiler_msg_el
=
view
.
el
.
querySelector
(
'
.chat-msg
-
text.spoiler
'
);
var
spoiler_msg_el
=
view
.
el
.
querySelector
(
'
.chat-msg
__
text.spoiler
'
);
expect
(
spoiler_msg_el
.
textContent
).
toBe
(
'
This is the spoiler
'
);
expect
(
_
.
includes
(
spoiler_msg_el
.
classList
,
'
collapsed
'
)).
toBeTruthy
();
...
...
src/converse-chatview.js
View file @
acd9a186
...
...
@@ -9,7 +9,6 @@
"
bootstrap
"
,
"
emojione
"
,
"
xss
"
,
"
templates/action.html
"
,
"
templates/chatbox.html
"
,
"
templates/chatbox_head.html
"
,
"
templates/chatbox_message_form.html
"
,
...
...
@@ -33,7 +32,6 @@
bootstrap
,
emojione
,
xss
,
tpl_action
,
tpl_chatbox
,
tpl_chatbox_head
,
tpl_chatbox_message_form
,
...
...
@@ -747,19 +745,19 @@
date
=
moment
(
el
.
getAttribute
(
'
data-isodate
'
)),
next_el
=
el
.
nextElementSibling
;
if
(
!
u
.
hasClass
(
'
chat-
action
'
,
el
)
&&
!
u
.
hasClass
(
'
chat
-action
'
,
previous_el
)
&&
if
(
!
u
.
hasClass
(
'
chat-
msg--action
'
,
el
)
&&
!
u
.
hasClass
(
'
chat-msg-
-action
'
,
previous_el
)
&&
previous_el
.
getAttribute
(
'
data-from
'
)
===
from
&&
date
.
isBefore
(
moment
(
previous_el
.
getAttribute
(
'
data-isodate
'
)).
add
(
10
,
'
minutes
'
)))
{
u
.
addClass
(
'
chat-msg-followup
'
,
el
);
u
.
addClass
(
'
chat-msg-
-
followup
'
,
el
);
}
if
(
!
next_el
)
{
return
;
}
if
(
!
u
.
hasClass
(
'
chat-action
'
,
'
el
'
)
&&
if
(
!
u
.
hasClass
(
'
chat-
msg--
action
'
,
'
el
'
)
&&
next_el
.
getAttribute
(
'
data-from
'
)
===
from
&&
moment
(
next_el
.
getAttribute
(
'
data-isodate
'
)).
isBefore
(
date
.
add
(
10
,
'
minutes
'
)))
{
u
.
addClass
(
'
chat-msg-followup
'
,
next_el
);
u
.
addClass
(
'
chat-msg-
-
followup
'
,
next_el
);
}
else
{
u
.
removeClass
(
'
chat-msg-followup
'
,
next_el
);
u
.
removeClass
(
'
chat-msg-
-
followup
'
,
next_el
);
}
},
...
...
src/converse-message-view.js
View file @
acd9a186
...
...
@@ -10,26 +10,22 @@
"
xss
"
,
"
emojione
"
,
"
filesize
"
,
"
templates/action.html
"
,
"
templates/csn.html
"
,
"
templates/file_progress.html
"
,
"
templates/info.html
"
,
"
templates/message.html
"
,
"
templates/message_versions_modal.html
"
,
"
templates/spoiler_message.html
"
],
factory
);
}(
this
,
function
(
converse
,
xss
,
emojione
,
filesize
,
tpl_action
,
tpl_csn
,
tpl_file_progress
,
tpl_info
,
tpl_message
,
tpl_message_versions_modal
,
tpl_spoiler_message
tpl_message_versions_modal
)
{
"
use strict
"
;
const
{
Backbone
,
_
,
moment
}
=
converse
.
env
;
...
...
@@ -101,7 +97,7 @@
},
render
()
{
const
is_followup
=
u
.
hasClass
(
'
chat-msg-followup
'
,
this
.
el
);
const
is_followup
=
u
.
hasClass
(
'
chat-msg-
-
followup
'
,
this
.
el
);
let
msg
;
if
(
this
.
model
.
isOnlyChatStateNotification
())
{
this
.
renderChatStateNotification
()
...
...
@@ -113,7 +109,7 @@
this
.
renderChatMessage
();
}
if
(
is_followup
)
{
u
.
addClass
(
'
chat-msg-followup
'
,
this
.
el
);
u
.
addClass
(
'
chat-msg-
-
followup
'
,
this
.
el
);
}
return
this
.
el
;
},
...
...
@@ -135,21 +131,16 @@
},
renderChatMessage
()
{
let
template
,
text
=
this
.
model
.
get
(
'
message
'
);
if
(
this
.
isMeCommand
())
{
template
=
tpl_action
;
text
=
this
.
model
.
get
(
'
message
'
).
replace
(
/^
\/
me/
,
''
);
}
else
{
template
=
this
.
model
.
get
(
'
is_spoiler
'
)
?
tpl_spoiler_message
:
tpl_message
;
}
const
moment_time
=
moment
(
this
.
model
.
get
(
'
time
'
)),
const
is_me_message
=
this
.
isMeCommand
(),
moment_time
=
moment
(
this
.
model
.
get
(
'
time
'
)),
role
=
this
.
model
.
vcard
.
get
(
'
role
'
),
roles
=
role
?
role
.
split
(
'
,
'
)
:
[];
const
msg
=
u
.
stringToElement
(
t
emplat
e
(
const
msg
=
u
.
stringToElement
(
t
pl_messag
e
(
_
.
extend
(
this
.
model
.
toJSON
(),
{
'
__
'
:
__
,
'
is_me_message
'
:
is_me_message
,
'
roles
'
:
roles
,
'
pretty_time
'
:
moment_time
.
format
(
_converse
.
time_format
),
'
time
'
:
moment_time
.
format
(),
...
...
@@ -159,16 +150,20 @@
})
));
var
url
=
this
.
model
.
get
(
'
oob_url
'
);
const
url
=
this
.
model
.
get
(
'
oob_url
'
);
if
(
url
)
{
msg
.
querySelector
(
'
.chat-msg
-
media
'
).
innerHTML
=
_
.
flow
(
msg
.
querySelector
(
'
.chat-msg
__
media
'
).
innerHTML
=
_
.
flow
(
_
.
partial
(
u
.
renderFileURL
,
_converse
),
_
.
partial
(
u
.
renderMovieURL
,
_converse
),
_
.
partial
(
u
.
renderAudioURL
,
_converse
),
_
.
partial
(
u
.
renderImageURL
,
_converse
))(
url
);
}
const
msg_content
=
msg
.
querySelector
(
'
.chat-msg-text
'
);
let
text
=
this
.
model
.
get
(
'
message
'
);
if
(
is_me_message
)
{
text
=
text
.
replace
(
/^
\/
me/
,
''
);
}
const
msg_content
=
msg
.
querySelector
(
'
.chat-msg__text
'
);
if
(
text
!==
url
)
{
text
=
xss
.
filterXSS
(
text
,
{
'
whiteList
'
:
{}});
msg_content
.
innerHTML
=
_
.
flow
(
...
...
src/templates/action.html
deleted
100644 → 0
View file @
6a462f6c
<div
class=
"message chat-msg chat-action {{{o.extra_classes}}}"
data-isodate=
"{{{o.time}}}"
data-from=
"{{{o.from}}}"
>
<span
class=
"chat-msg-heading"
>
<span
class=
"chat-msg-author"
>
**{{{o.username}}}
</span>
</span>
<p
class=
"chat-msg-text"
>
<!-- message gets added here via renderMessage -->
</p>
</div>
src/templates/file_progress.html
View file @
acd9a186
<div
class=
"message chat-msg"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
>
<canvas
class=
"avatar"
height=
"36"
width=
"36"
></canvas>
<div
class=
"chat-msg
-
content"
>
<span
class=
"chat-msg
-
text"
>
Uploading file:
<strong>
{{{o.file.name}}}
</strong>
, {{{o.filesize}}}
</span>
<canvas
class=
"avatar
chat-msg__avatar
"
height=
"36"
width=
"36"
></canvas>
<div
class=
"chat-msg
__
content"
>
<span
class=
"chat-msg
__
text"
>
Uploading file:
<strong>
{{{o.file.name}}}
</strong>
, {{{o.filesize}}}
</span>
<progress
value=
"{{{o.progress}}}"
/>
</div>
</div>
src/templates/message.html
View file @
acd9a186
<div
class=
"message chat-msg {{{o.type}}} {{{o.extra_classes}}}"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
data-from=
"{{{o.from}}}"
>
{[ if (o.type !== 'headline') { ]}
<canvas
class=
"avatar"
height=
"36"
width=
"36"
></canvas>
<div
class=
"message chat-msg {{{o.type}}} {
[ if (o.is_me_message) { ]} chat-msg--action {[ } ]} {
{{o.extra_classes}}}"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
data-from=
"{{{o.from}}}"
>
{[ if (o.type !== 'headline'
&&
!o.is_me_message
) { ]}
<canvas
class=
"avatar
chat-msg__avatar
"
height=
"36"
width=
"36"
></canvas>
{[ } ]}
<div
class=
"chat-msg-content"
>
<span
class=
"chat-msg-heading"
>
<span
class=
"chat-msg-author"
>
{{{o.username}}}
<div
class=
"chat-msg__content {[ if (o.is_me_message) { ]}chat-msg__content--action{[ } ]}"
>
<span
class=
"chat-msg__heading"
>
{[ if (o.is_me_message) { ]}
<time
timestamp=
"{{{o.isodate}}}"
class=
"chat-msg__time"
>
{{{o.pretty_time}}}
</time>
{[ } ]}
<span
class=
"chat-msg__author"
>
{[ if (o.is_me_message) { ]}**{[ }; ]}{{{o.username}}}
{[o.roles.forEach(function (role) { ]}
<span
class=
"badge badge-secondary"
>
{{{role}}}
</span>
{[ }); ]}
</span>
<time
timestamp=
"{{{o.isodate}}}"
class=
"chat-msg-time"
>
{{{o.pretty_time}}}
</time>
{[ if (!o.is_me_message) { ]}
<time
timestamp=
"{{{o.isodate}}}"
class=
"chat-msg__time"
>
{{{o.pretty_time}}}
</time>
{[ } ]}
</span>
{[ if (!o.is_me_message) { ]}
<div
class=
"chat-msg__body"
>
{[ } ]}
{[ if (o.edited) { ]}
<i
title=
"{{{o.__('This message has been edited')}}}"
class=
"fa fa-edit chat-msg-edited"
></i>
{[ } ]}
<span
class=
"chat-msg-text"
></span>
<div
class=
"chat-msg-media"
></div>
{[ if (!o.is_me_message) { ]}
<div
class=
"chat-msg__message"
>
{[ } ]}
{[ if (o.is_spoiler) { ]}
<div
class=
"chat-msg__spoiler-hint"
>
<span
class=
"spoiler-hint"
>
{{{o.spoiler_hint}}}
</span>
<a
class=
"badge badge-info spoiler-toggle"
data-toggle-state=
"closed"
href=
"#"
><i
class=
"fa fa-eye"
></i>
{{{o.label_show}}}
</a>
</div>
{[ } ]}
<div
class=
"chat-msg__text{[ if (o.is_spoiler) { ]} spoiler collapsed{[ } ]}"
>
<!-- message gets added here via renderMessage -->
</div>
<div
class=
"chat-msg__media"
></div>
{[ if (!o.is_me_message) { ]}
</div>
{[ } ]}
{[ if (!o.is_me_message) { ]}
</div>
{[ } ]}
</div>
</div>
src/templates/spoiler_message.html
deleted
100644 → 0
View file @
6a462f6c
<div
class=
"message chat-msg {{{o.extra_classes}}}"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
>
<canvas
class=
"avatar"
height=
"36"
width=
"36"
></canvas>
<div
class=
"chat-msg-content"
>
<span
class=
"chat-msg-heading"
>
<span
class=
"chat-msg-author"
>
{{{o.username}}}
</span>
<span
class=
"chat-msg-time"
>
{{{o.pretty_time}}}
</span>
</span>
<div>
<span
class=
"spoiler-hint"
>
{{{o.spoiler_hint}}}
</span>
<a
class=
"badge badge-info spoiler-toggle"
data-toggle-state=
"closed"
href=
"#"
><i
class=
"fa fa-eye"
></i>
{{{o.label_show}}}
</a>
</div>
<div
class=
"chat-msg-text spoiler collapsed"
>
<!-- message gets added here via renderMessage -->
</div>
</div>
</div>
src/utils/core.js
View file @
acd9a186
...
...
@@ -210,6 +210,10 @@
.
replace
(
/"/g
,
"
"
"
);
};
u
.
escapeURL
=
function
(
url
)
{
return
encodeURI
(
decodeURI
(
url
)).
replace
(
/
[
!'()
]
/g
,
escape
).
replace
(
/
\*
/g
,
"
%2A
"
);
};
u
.
addHyperlinks
=
function
(
text
)
{
return
URI
.
withinString
(
text
,
function
(
url
)
{
var
uri
=
new
URI
(
url
);
...
...
@@ -217,8 +221,8 @@
if
(
!
url
.
startsWith
(
'
http://
'
)
&&
!
url
.
startsWith
(
'
https://
'
))
{
url
=
'
http://
'
+
url
;
}
url
=
encodeURI
(
decodeURI
(
url
)).
replace
(
/
[
!'()
]
/g
,
escape
).
replace
(
/
\*
/g
,
"
%2A
"
);
return
`<a target="_blank" rel="noopener" href="
${
u
.
escapeHTML
(
url
)
}
">
${
u
.
escapeHTML
(
uri
.
readable
())}
</a>`
;
url
=
u
.
escapeHTML
(
u
.
escapeURL
(
url
)
);
return
`<a target="_blank" rel="noopener" href="
${
u
rl
}
">
${
u
.
escapeHTML
(
uri
.
readable
())}
</a>`
;
});
};
...
...
@@ -255,7 +259,8 @@
};
u
.
renderFileURL
=
function
(
_converse
,
url
)
{
const
uri
=
new
URI
(
url
),
{
__
}
=
_converse
,
const
uri
=
new
URI
(
url
),
{
__
}
=
_converse
,
filename
=
uri
.
filename
();
if
(
!
_
.
includes
([
"
https
"
,
"
http
"
],
uri
.
protocol
())
||
filename
.
endsWith
(
'
mp3
'
)
||
filename
.
endsWith
(
'
mp4
'
)
||
...
...
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