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
a19e7aef
Commit
a19e7aef
authored
Apr 18, 2018
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for XEP-0066 Out of band data
parent
d048cff9
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
291 additions
and
44 deletions
+291
-44
.eslintrc.json
.eslintrc.json
+1
-1
CHANGES.md
CHANGES.md
+2
-1
css/converse.css
css/converse.css
+4
-2
css/inverse.css
css/inverse.css
+4
-2
index.html
index.html
+1
-0
sass/_chatbox.scss
sass/_chatbox.scss
+3
-2
spec/chatbox.js
spec/chatbox.js
+169
-4
src/converse-chatboxes.js
src/converse-chatboxes.js
+14
-4
src/converse-core.js
src/converse-core.js
+1
-0
src/converse-disco.js
src/converse-disco.js
+2
-2
src/converse-message-view.js
src/converse-message-view.js
+23
-12
src/templates/audio.html
src/templates/audio.html
+2
-0
src/templates/file.html
src/templates/file.html
+1
-4
src/templates/file_progress.html
src/templates/file_progress.html
+4
-0
src/templates/image.html
src/templates/image.html
+1
-0
src/templates/message.html
src/templates/message.html
+2
-1
src/templates/video.html
src/templates/video.html
+2
-0
src/utils/core.js
src/utils/core.js
+55
-9
No files found.
.eslintrc.json
View file @
a19e7aef
...
...
@@ -57,7 +57,7 @@
"property"
],
"dot-notation"
:
[
"
error
"
,
"
off
"
,
{
"allowKeywords"
:
true
}
...
...
CHANGES.md
View file @
a19e7aef
...
...
@@ -5,7 +5,8 @@
## New Features
-
#161 XEP-0363: HTTP File Upload
-
mp4 and mp3 files will now be playable directly in chat
-
Support for rendering URLs sent according to XEP-0066 Out of Band Data.
-
mp4 and mp3 files when sent as XEP-0066 Out of Band Data, will now be playable directly in chat
## 4.0.0 (Unreleased)
...
...
css/converse.css
View file @
a19e7aef
...
...
@@ -7382,8 +7382,7 @@ body.reset {
font-style
:
italic
;
}
#converse-embedded-chat
.chatbox
.chat-body
.chat-message
,
#conversejs
.chatbox
.chat-body
.chat-message
{
overflow
:
auto
;
margin
:
0
;
}
overflow
:
auto
;
}
#converse-embedded-chat
.chatbox
.chat-body
.chat-message.onload
,
#conversejs
.chatbox
.chat-body
.chat-message.onload
{
animation
:
colorchange-chatmessage
1s
;
...
...
@@ -7444,6 +7443,9 @@ body.reset {
#conversejs
.chatbox
.chat-content
.toggle-spoiler
:before
{
padding-right
:
0.25em
;
whitespace
:
nowrap
;
}
#converse-embedded-chat
.chatbox
.chat-content
video
,
#conversejs
.chatbox
.chat-content
video
{
width
:
100%
;
}
#converse-embedded-chat
.chatbox
.chat-content
progress
,
#conversejs
.chatbox
.chat-content
progress
{
margin
:
0.5em
0
;
...
...
css/inverse.css
View file @
a19e7aef
...
...
@@ -7435,8 +7435,7 @@ body {
font-style
:
italic
;
}
#converse-embedded-chat
.chatbox
.chat-body
.chat-message
,
#conversejs
.chatbox
.chat-body
.chat-message
{
overflow
:
auto
;
margin
:
0
;
}
overflow
:
auto
;
}
#converse-embedded-chat
.chatbox
.chat-body
.chat-message.onload
,
#conversejs
.chatbox
.chat-body
.chat-message.onload
{
animation
:
colorchange-chatmessage
1s
;
...
...
@@ -7497,6 +7496,9 @@ body {
#conversejs
.chatbox
.chat-content
.toggle-spoiler
:before
{
padding-right
:
0.25em
;
whitespace
:
nowrap
;
}
#converse-embedded-chat
.chatbox
.chat-content
video
,
#conversejs
.chatbox
.chat-content
video
{
width
:
100%
;
}
#converse-embedded-chat
.chatbox
.chat-content
progress
,
#conversejs
.chatbox
.chat-content
progress
{
margin
:
0.5em
0
;
...
...
index.html
View file @
a19e7aef
...
...
@@ -167,6 +167,7 @@
<li>
Custom status messages
</li>
<li>
Typing and chat state notifications (
<a
href=
"http://xmpp.org/extensions/xep-0085.html"
target=
"_blank"
rel=
"noopener"
>
XEP 85
</a>
)
</li>
<li>
Desktop notifications
</li>
<li>
File sharing (
<a
href=
"http://xmpp.org/extensions/xep-0363.html"
target=
"_blank"
rel=
"noopener"
>
XEP 363
</a>
)
</li>
<li>
Messages appear in all connected chat clients (
<a
href=
"http://xmpp.org/extensions/xep-0280.html"
target=
"_blank"
rel=
"noopener"
>
XEP 280
</a>
)
</li>
<li>
Third person "/me" messages (
<a
href=
"http://xmpp.org/extensions/xep-0245.html"
target=
"_blank"
rel=
"noopener"
>
XEP 245
</a>
)
</li>
<li>
XMPP Ping (
<a
href=
"http://xmpp.org/extensions/xep-0199.html"
target=
"_blank"
rel=
"noopener"
>
XEP 199
</a>
)
</li>
...
...
sass/_chatbox.scss
View file @
a19e7aef
...
...
@@ -211,7 +211,6 @@
}
.chat-message
{
overflow
:
auto
;
// Ensures that content stays inside
margin
:
0
;
&
.onload
{
animation
:
colorchange-chatmessage
1s
;
...
...
@@ -281,7 +280,9 @@
padding-right
:
0
.25em
;
whitespace
:
nowrap
;
}
video
{
width
:
100%
}
progress
{
margin
:
0
.5em
0
;
width
:
100%
...
...
spec/chatbox.js
View file @
a19e7aef
...
...
@@ -1578,6 +1578,171 @@
done
();
}));
it
(
"
will render audio from oob mp3 URLs
"
,
mock
.
initConverseWithPromises
(
null
,
[
'
rosterGroupsFetched
'
],
{},
function
(
done
,
_converse
)
{
test_utils
.
createContacts
(
_converse
,
'
current
'
);
var
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
var
view
=
_converse
.
chatboxviews
.
get
(
contact_jid
);
spyOn
(
view
.
model
,
'
sendMessage
'
).
and
.
callThrough
();
var
stanza
=
Strophe
.
xmlHtmlNode
(
"
<message from='
"
+
contact_jid
+
"
'
"
+
"
type='chat'
"
+
"
to='dummy@localhost/resource'>
"
+
"
<body>Have you heard this funny audio?</body>
"
+
"
<x xmlns='jabber:x:oob'><url>http://localhost/audio.mp3</url></x>
"
+
"
</message>
"
).
firstChild
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
test_utils
.
waitUntil
(
function
()
{
return
view
.
el
.
querySelectorAll
(
'
.chat-content .chat-message audio
'
).
length
;
},
1000
).
then
(
function
()
{
var
msg
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-content
'
);
expect
(
msg
.
outerHTML
).
toEqual
(
'
<span class="chat-msg-content">Have you heard this funny audio?</span>
'
);
var
media
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-media
'
);
expect
(
media
.
innerHTML
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
""
)).
toEqual
(
'
<audio controls=""><source src="http://localhost/audio.mp3" type="audio/mpeg"></audio>
'
+
'
<a target="_blank" rel="noopener" href="http://localhost/audio.mp3">Download audio file</a>
'
);
// If the <url> and <body> contents is the same, don't duplicate.
var
stanza
=
Strophe
.
xmlHtmlNode
(
"
<message from='
"
+
contact_jid
+
"
'
"
+
"
type='chat'
"
+
"
to='dummy@localhost/resource'>
"
+
"
<body>http://localhost/audio.mp3</body>
"
+
"
<x xmlns='jabber:x:oob'><url>http://localhost/audio.mp3</url></x>
"
+
"
</message>
"
).
firstChild
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
msg
=
view
.
el
.
querySelector
(
'
.chat-message:last-child .chat-msg-content
'
);
expect
(
msg
.
innerHTML
).
toEqual
(
''
);
media
=
view
.
el
.
querySelector
(
'
.chat-message:last-child .chat-msg-media
'
);
expect
(
media
.
innerHTML
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
""
)).
toEqual
(
'
<audio controls=""><source src="http://localhost/audio.mp3" type="audio/mpeg"></audio>
'
+
'
<a target="_blank" rel="noopener" href="http://localhost/audio.mp3">Download audio file</a>
'
);
done
();
});
}));
it
(
"
will render video from oob mp4 URLs
"
,
mock
.
initConverseWithPromises
(
null
,
[
'
rosterGroupsFetched
'
],
{},
function
(
done
,
_converse
)
{
test_utils
.
createContacts
(
_converse
,
'
current
'
);
var
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
var
view
=
_converse
.
chatboxviews
.
get
(
contact_jid
);
spyOn
(
view
.
model
,
'
sendMessage
'
).
and
.
callThrough
();
var
stanza
=
Strophe
.
xmlHtmlNode
(
"
<message from='
"
+
contact_jid
+
"
'
"
+
"
type='chat'
"
+
"
to='dummy@localhost/resource'>
"
+
"
<body>Have you seen this funny video?</body>
"
+
"
<x xmlns='jabber:x:oob'><url>http://localhost/video.mp4</url></x>
"
+
"
</message>
"
).
firstChild
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
test_utils
.
waitUntil
(
function
()
{
return
view
.
el
.
querySelectorAll
(
'
.chat-content .chat-message video
'
).
length
;
},
1000
).
then
(
function
()
{
var
msg
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-content
'
);
expect
(
msg
.
outerHTML
).
toEqual
(
'
<span class="chat-msg-content">Have you seen this funny video?</span>
'
);
var
media
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-media
'
);
expect
(
media
.
innerHTML
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
""
)).
toEqual
(
'
<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>
'
+
'
<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>
'
);
// If the <url> and <body> contents is the same, don't duplicate.
var
stanza
=
Strophe
.
xmlHtmlNode
(
"
<message from='
"
+
contact_jid
+
"
'
"
+
"
type='chat'
"
+
"
to='dummy@localhost/resource'>
"
+
"
<body>http://localhost/video.mp4</body>
"
+
"
<x xmlns='jabber:x:oob'><url>http://localhost/video.mp4</url></x>
"
+
"
</message>
"
).
firstChild
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
msg
=
view
.
el
.
querySelector
(
'
.chat-message:last-child .chat-msg-content
'
);
expect
(
msg
.
innerHTML
).
toEqual
(
''
);
media
=
view
.
el
.
querySelector
(
'
.chat-message:last-child .chat-msg-media
'
);
expect
(
media
.
innerHTML
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
""
)).
toEqual
(
'
<video controls=""><source src="http://localhost/video.mp4" type="video/mp4"></video>
'
+
'
<a target="_blank" rel="noopener" href="http://localhost/video.mp4">Download video file</a>
'
);
done
();
});
}));
it
(
"
will render download links for files from oob URLs
"
,
mock
.
initConverseWithPromises
(
null
,
[
'
rosterGroupsFetched
'
],
{},
function
(
done
,
_converse
)
{
test_utils
.
createContacts
(
_converse
,
'
current
'
);
var
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
var
view
=
_converse
.
chatboxviews
.
get
(
contact_jid
);
spyOn
(
view
.
model
,
'
sendMessage
'
).
and
.
callThrough
();
var
stanza
=
Strophe
.
xmlHtmlNode
(
"
<message from='
"
+
contact_jid
+
"
'
"
+
"
type='chat'
"
+
"
to='dummy@localhost/resource'>
"
+
"
<body>Have you downloaded this funny file?</body>
"
+
"
<x xmlns='jabber:x:oob'><url>http://localhost/funny.pdf</url></x>
"
+
"
</message>
"
).
firstChild
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
test_utils
.
waitUntil
(
function
()
{
return
view
.
el
.
querySelectorAll
(
'
.chat-content .chat-message a
'
).
length
;
},
1000
).
then
(
function
()
{
var
msg
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-content
'
);
expect
(
msg
.
outerHTML
).
toEqual
(
'
<span class="chat-msg-content">Have you downloaded this funny file?</span>
'
);
var
media
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-media
'
);
expect
(
media
.
innerHTML
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
""
)).
toEqual
(
'
<a target="_blank" rel="noopener" href="http://localhost/funny.pdf">Download file: "funny.pdf</a>
'
);
done
();
});
}));
it
(
"
will render images from oob URLs
"
,
mock
.
initConverseWithPromises
(
null
,
[
'
rosterGroupsFetched
'
],
{},
function
(
done
,
_converse
)
{
test_utils
.
createContacts
(
_converse
,
'
current
'
);
var
contact_jid
=
mock
.
cur_names
[
0
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
test_utils
.
openChatBoxFor
(
_converse
,
contact_jid
);
var
view
=
_converse
.
chatboxviews
.
get
(
contact_jid
);
spyOn
(
view
.
model
,
'
sendMessage
'
).
and
.
callThrough
();
var
base_url
=
document
.
URL
.
split
(
window
.
location
.
pathname
)[
0
];
var
url
=
base_url
+
"
/logo/conversejs-filled.svg
"
;
var
stanza
=
Strophe
.
xmlHtmlNode
(
"
<message from='
"
+
contact_jid
+
"
'
"
+
"
type='chat'
"
+
"
to='dummy@localhost/resource'>
"
+
"
<body>Have you seen this funny image?</body>
"
+
"
<x xmlns='jabber:x:oob'><url>
"
+
url
+
"
</url></x>
"
+
"
</message>
"
).
firstChild
;
_converse
.
connection
.
_dataRecv
(
test_utils
.
createRequest
(
stanza
));
test_utils
.
waitUntil
(
function
()
{
return
view
.
el
.
querySelectorAll
(
'
.chat-content .chat-message img
'
).
length
;
},
1000
).
then
(
function
()
{
var
msg
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-content
'
);
expect
(
msg
.
outerHTML
).
toEqual
(
'
<span class="chat-msg-content">Have you seen this funny image?</span>
'
);
var
media
=
view
.
el
.
querySelector
(
'
.chat-message .chat-msg-media
'
);
expect
(
media
.
innerHTML
.
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
""
)).
toEqual
(
'
<img class="chat-image" src="http://localhost:8000/logo/conversejs-filled.svg">
'
);
done
();
});
}));
it
(
"
will render images from their URLs
"
,
mock
.
initConverseWithPromises
(
...
...
@@ -1672,10 +1837,10 @@
var
sender_jid
=
mock
.
cur_names
[
1
].
replace
(
/ /g
,
'
.
'
).
toLowerCase
()
+
'
@localhost
'
;
// <composing> state
var
msg
=
$msg
({
from
:
sender_jid
,
to
:
_converse
.
connection
.
jid
,
type
:
'
chat
'
,
id
:
(
new
Date
()).
getTime
()
'
from
'
:
sender_jid
,
'
to
'
:
_converse
.
connection
.
jid
,
'
type
'
:
'
chat
'
,
'
id
'
:
(
new
Date
()).
getTime
()
}).
c
(
'
composing
'
,
{
'
xmlns
'
:
Strophe
.
NS
.
CHATSTATES
}).
tree
();
_converse
.
chatboxes
.
onMessage
(
msg
);
expect
(
_converse
.
emit
).
toHaveBeenCalledWith
(
'
message
'
,
jasmine
.
any
(
Object
));
...
...
src/converse-chatboxes.js
View file @
a19e7aef
...
...
@@ -10,16 +10,15 @@
"
emojione
"
,
"
filesize
"
,
"
tpl!chatboxes
"
,
"
backbone.overview
"
"
backbone.overview
"
,
"
form-utils
"
],
factory
);
}(
this
,
function
(
converse
,
emojione
,
filesize
,
tpl_chatboxes
)
{
"
use strict
"
;
const
{
$msg
,
Backbone
,
Promise
,
Strophe
,
b64_sha1
,
moment
,
utils
,
_
}
=
converse
.
env
;
const
{
$msg
,
Backbone
,
Promise
,
Strophe
,
b64_sha1
,
moment
,
sizzle
,
utils
,
_
}
=
converse
.
env
;
const
u
=
converse
.
env
.
utils
;
Strophe
.
addNamespace
(
'
OUTOFBAND
'
,
'
jabber:x:oob
'
);
converse
.
plugins
.
add
(
'
converse-chatboxes
'
,
{
...
...
@@ -373,6 +372,7 @@
sender
=
'
them
'
;
fullname
=
this
.
get
(
'
fullname
'
);
}
const
spoiler
=
message
.
querySelector
(
`spoiler[xmlns="
${
Strophe
.
NS
.
SPOILER
}
"]`
);
const
attrs
=
{
'
type
'
:
type
,
...
...
@@ -386,6 +386,10 @@
'
time
'
:
time
,
'
is_spoiler
'
:
!
_
.
isNull
(
spoiler
)
};
_
.
each
(
sizzle
(
`x[xmlns="
${
Strophe
.
NS
.
OUTOFBAND
}
"]`
,
message
),
(
xform
)
=>
{
attrs
[
'
oob_url
'
]
=
xform
.
querySelector
(
'
url
'
).
textContent
;
attrs
[
'
oob_desc
'
]
=
xform
.
querySelector
(
'
url
'
).
textContent
;
});
if
(
spoiler
)
{
attrs
.
spoiler_hint
=
spoiler
.
textContent
.
length
>
0
?
spoiler
.
textContent
:
''
;
}
...
...
@@ -679,7 +683,13 @@
return
_converse
.
chatboxviews
.
get
(
chatbox
.
get
(
'
id
'
));
};
/************************ BEGIN Event Handlers ************************/
_converse
.
on
(
'
addClientFeatures
'
,
()
=>
{
_converse
.
connection
.
disco
.
addFeature
(
Strophe
.
NS
.
HTTPUPLOAD
);
_converse
.
connection
.
disco
.
addFeature
(
Strophe
.
NS
.
OUTOFBAND
);
});
_converse
.
api
.
listen
.
on
(
'
pluginsInitialized
'
,
()
=>
{
_converse
.
chatboxes
=
new
_converse
.
ChatBoxes
();
_converse
.
chatboxviews
=
new
_converse
.
ChatBoxViews
({
...
...
src/converse-core.js
View file @
a19e7aef
...
...
@@ -41,6 +41,7 @@
Strophe
.
addNamespace
(
'
HTTPUPLOAD
'
,
'
urn:xmpp:http:upload:0
'
);
Strophe
.
addNamespace
(
'
MAM
'
,
'
urn:xmpp:mam:2
'
);
Strophe
.
addNamespace
(
'
NICK
'
,
'
http://jabber.org/protocol/nick
'
);
Strophe
.
addNamespace
(
'
OUTOFBAND
'
,
'
jabber:x:oob
'
);
Strophe
.
addNamespace
(
'
PUBSUB
'
,
'
http://jabber.org/protocol/pubsub
'
);
Strophe
.
addNamespace
(
'
ROSTERX
'
,
'
http://jabber.org/protocol/rosterx
'
);
Strophe
.
addNamespace
(
'
RSM
'
,
'
http://jabber.org/protocol/rsm
'
);
...
...
src/converse-disco.js
View file @
a19e7aef
...
...
@@ -161,7 +161,7 @@
});
});
_
.
each
(
sizzle
(
'
x[type="result"][xmlns="jabber:x:data"]
'
,
stanza
),
(
form
)
=>
{
_
.
each
(
sizzle
(
`x[type="result"][xmlns="
${
Strophe
.
NS
.
XFORM
}
"]`
,
stanza
),
(
form
)
=>
{
const
data
=
{};
_
.
each
(
form
.
querySelectorAll
(
'
field
'
),
(
field
)
=>
{
data
[
field
.
getAttribute
(
'
var
'
)]
=
{
...
...
@@ -172,7 +172,7 @@
this
.
dataforms
.
create
(
data
);
});
if
(
stanza
.
querySelector
(
'
feature[var="
'
+
Strophe
.
NS
.
DISCO_ITEMS
+
'
"]
'
))
{
if
(
stanza
.
querySelector
(
`feature[var="
${
Strophe
.
NS
.
DISCO_ITEMS
}
"]`
))
{
this
.
queryForItems
();
}
_
.
forEach
(
stanza
.
querySelectorAll
(
'
feature
'
),
(
feature
)
=>
{
...
...
src/converse-message-view.js
View file @
a19e7aef
...
...
@@ -11,7 +11,7 @@
"
emojione
"
,
"
filesize
"
,
"
tpl!action
"
,
"
tpl!file
"
,
"
tpl!file
_progress
"
,
"
tpl!info
"
,
"
tpl!message
"
,
"
tpl!spoiler_message
"
...
...
@@ -22,7 +22,7 @@
emojione
,
filesize
,
tpl_action
,
tpl_file
,
tpl_file
_progress
,
tpl_info
,
tpl_message
,
tpl_spoiler_message
...
...
@@ -85,16 +85,27 @@
'
label_show
'
:
__
(
'
Show hidden message
'
)
})
));
const
msg_content
=
msg
.
querySelector
(
'
.chat-msg-content
'
);
text
=
xss
.
filterXSS
(
text
,
{
'
whiteList
'
:
{}});
msg_content
.
innerHTML
=
_
.
flow
(
_
.
partial
(
u
.
geoUriToHttp
,
_
,
_converse
.
geouri_replacement
),
_
.
partial
(
u
.
addHyperlinks
,
_
),
_
.
partial
(
u
.
addEmoji
,
_converse
,
emojione
,
_
),
u
.
renderMovieURLs
,
u
.
renderAudioURLs
)(
text
);
var
url
=
this
.
model
.
get
(
'
oob_url
'
);
if
(
url
)
{
const
msg_media
=
msg
.
querySelector
(
'
.chat-msg-media
'
);
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-content
'
);
if
(
text
!==
url
)
{
text
=
xss
.
filterXSS
(
text
,
{
'
whiteList
'
:
{}});
msg_content
.
innerHTML
=
_
.
flow
(
_
.
partial
(
u
.
geoUriToHttp
,
_
,
_converse
.
geouri_replacement
),
u
.
addHyperlinks
,
_
.
partial
(
u
.
addEmoji
,
_converse
,
emojione
,
_
)
)(
text
);
}
u
.
renderImageURLs
(
msg_content
).
then
(()
=>
{
this
.
model
.
collection
.
trigger
(
'
rendered
'
);
});
...
...
@@ -121,7 +132,7 @@
},
renderFileUploadProgresBar
()
{
const
msg
=
u
.
stringToElement
(
tpl_file
(
const
msg
=
u
.
stringToElement
(
tpl_file
_progress
(
_
.
extend
(
this
.
model
.
toJSON
(),
{
'
filesize
'
:
filesize
(
this
.
model
.
get
(
'
file
'
).
size
)}
)));
...
...
src/templates/audio.html
0 → 100644
View file @
a19e7aef
<audio
controls
><source
src=
"{{{o.url}}}"
type=
"audio/mpeg"
></audio>
<a
target=
"_blank"
rel=
"noopener"
href=
"{{{o.url}}}"
>
{{{o.label_download}}}
</a>
src/templates/file.html
View file @
a19e7aef
<div
class=
"message"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
>
<span
class=
"chat-msg-content"
>
Uploading file:
<strong>
{{{o.file.name}}}
</strong>
, {{{o.filesize}}}
</span>
<progress
value=
"{{{o.progress}}}"
/>
</div>
<a
target=
"_blank"
rel=
"noopener"
href=
"{{{o.url}}}"
>
{{{o.label_download}}}
</a>
src/templates/file_progress.html
0 → 100644
View file @
a19e7aef
<div
class=
"message"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
>
<span
class=
"chat-msg-content"
>
Uploading file:
<strong>
{{{o.file.name}}}
</strong>
, {{{o.filesize}}}
</span>
<progress
value=
"{{{o.progress}}}"
/>
</div>
src/templates/image.html
0 → 100644
View file @
a19e7aef
<img
class=
"chat-image"
src=
"{{{o.url}}}"
/>
src/templates/message.html
View file @
a19e7aef
<div
class=
"message chat-message {{{o.extra_classes}}}"
data-isodate=
"{{{o.time}}}"
data-msgid=
"{{{o.msgid}}}"
>
<span
class=
"chat-msg-author chat-msg-{{{o.sender}}}"
>
{{{o.pretty_time}}} {{{o.username}}}:
</span>
<span
class=
"chat-msg-content"
>
<!-- message gets added here via renderMessage -->
</span>
<span
class=
"chat-msg-content"
></span>
<div
class=
"chat-msg-media"
></div>
</div>
src/templates/video.html
0 → 100644
View file @
a19e7aef
<video
controls
><source
src=
"{{{o.url}}}"
type=
"video/mp4"
></video>
<a
target=
"_blank"
rel=
"noopener"
href=
"{{{o.url}}}"
>
{{{o.label_download}}}
</a>
src/utils/core.js
View file @
a19e7aef
...
...
@@ -13,12 +13,20 @@
"
es6-promise
"
,
"
lodash.noconflict
"
,
"
strophe
"
,
"
tpl!audio
"
,
"
tpl!file
"
,
"
tpl!image
"
,
"
tpl!video
"
],
factory
);
}(
this
,
function
(
sizzle
,
Promise
,
_
,
Strophe
Strophe
,
tpl_audio
,
tpl_file
,
tpl_image
,
tpl_video
)
{
"
use strict
"
;
const
b64_sha1
=
Strophe
.
SHA1
.
b64_sha1
;
...
...
@@ -213,18 +221,56 @@
))
};
u
.
renderMovieURLs
=
function
(
text
)
{
if
(
text
.
endsWith
(
'
mp4
'
))
{
return
"
<video controls><source src=
\"
"
+
text
+
"
\"
type=
\"
video/mp4
\"
></video>
"
;
u
.
renderFileURL
=
function
(
_converse
,
url
)
{
if
(
url
.
endsWith
(
'
mp3
'
)
||
url
.
endsWith
(
'
mp4
'
)
||
url
.
endsWith
(
'
jpg
'
)
||
url
.
endsWith
(
'
jpeg
'
)
||
url
.
endsWith
(
'
png
'
)
||
url
.
endsWith
(
'
gif
'
)
||
url
.
endsWith
(
'
svg
'
))
{
return
url
;
}
return
text
;
const
name
=
url
.
split
(
'
/
'
).
pop
(),
{
__
}
=
_converse
;
return
tpl_file
({
'
url
'
:
url
,
'
label_download
'
:
__
(
'
Download file: "%1$s
'
,
name
)
})
};
u
.
renderAudioURLs
=
function
(
text
)
{
if
(
text
.
endsWith
(
'
mp3
'
))
{
return
"
<audio controls><source src=
\"
"
+
text
+
"
\"
type=
\"
audio/mpeg
\"
></audio>
"
;
u
.
renderImageURL
=
function
(
_converse
,
url
)
{
const
{
__
}
=
_converse
;
if
(
url
.
endsWith
(
'
jpg
'
)
||
url
.
endsWith
(
'
jpeg
'
)
||
url
.
endsWith
(
'
png
'
)
||
url
.
endsWith
(
'
gif
'
)
||
url
.
endsWith
(
'
svg
'
))
{
return
tpl_image
({
'
url
'
:
url
,
'
label_download
'
:
__
(
'
Download image file
'
)
})
}
return
text
;
return
url
;
};
u
.
renderMovieURL
=
function
(
_converse
,
url
)
{
const
{
__
}
=
_converse
;
if
(
url
.
endsWith
(
'
mp4
'
))
{
return
tpl_video
({
'
url
'
:
url
,
'
label_download
'
:
__
(
'
Download video file
'
)
})
}
return
url
;
};
u
.
renderAudioURL
=
function
(
_converse
,
url
)
{
const
{
__
}
=
_converse
;
if
(
url
.
endsWith
(
'
mp3
'
))
{
return
tpl_audio
({
'
url
'
:
url
,
'
label_download
'
:
__
(
'
Download audio file
'
)
})
}
return
url
;
};
u
.
slideInAllElements
=
function
(
elements
,
duration
=
300
)
{
...
...
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