diff --git a/css/converse.css b/css/converse.css
index f9752d0c8..9477ca8a6 100644
--- a/css/converse.css
+++ b/css/converse.css
@@ -1347,6 +1347,9 @@
#conversejs .chatbox .chat-body .chat-info.chat-date {
display: inline-block;
margin-top: 1em; }
+ #conversejs .chatbox .chat-body .chat-image {
+ max-width: 100%;
+ max-height: 100%; }
#conversejs .chatbox .chat-body .chat-message {
margin: 0.3em; }
#conversejs .chatbox .chat-body .chat-message span {
diff --git a/sass/_chatbox.scss b/sass/_chatbox.scss
index 423f35eee..31151f7cb 100644
--- a/sass/_chatbox.scss
+++ b/sass/_chatbox.scss
@@ -154,6 +154,10 @@
margin-top: 1em;
}
}
+ .chat-image {
+ max-width: 100%;
+ max-height: 100%;
+ }
.chat-message {
margin: 0.3em;
span {
diff --git a/spec/chatbox.js b/spec/chatbox.js
index 4625e7205..a7b8864b3 100644
--- a/spec/chatbox.js
+++ b/spec/chatbox.js
@@ -819,19 +819,6 @@
expect(msg.html()).toEqual('<p>This message contains <em>some</em> <b>markup</b></p>');
}.bind(converse));
- it("can contain hyperlinks, which will be clickable", function () {
- var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
- test_utils.openChatBoxFor(contact_jid);
- var view = this.chatboxviews.get(contact_jid);
- var message = 'This message contains a hyperlink: www.opkode.com';
- spyOn(view, 'sendMessage').andCallThrough();
- test_utils.sendMessage(view, message);
- expect(view.sendMessage).toHaveBeenCalled();
- var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
- expect(msg.text()).toEqual(message);
- expect(msg.html()).toEqual('This message contains a hyperlink: www.opkode.com');
- }.bind(converse));
-
it("should display emoticons correctly", function () {
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(contact_jid);
@@ -856,40 +843,99 @@
}
}.bind(converse));
- it("will have properly escaped URLs", function () {
+ it("can contain hyperlinks, which will be clickable", function () {
var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(contact_jid);
- var view = this.chatboxviews.get(contact_jid);
+ var view = converse.chatboxviews.get(contact_jid);
+ var message = 'This message contains a hyperlink: www.opkode.com';
spyOn(view, 'sendMessage').andCallThrough();
+ runs(function () {
+ test_utils.sendMessage(view, message);
+ });
+ waits(500);
+ runs(function () {
+ expect(view.sendMessage).toHaveBeenCalled();
+ var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
+ expect(msg.text()).toEqual(message);
+ expect(msg.html()).toEqual('This message contains a hyperlink: www.opkode.com');
+ });
+ });
- var message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
- test_utils.sendMessage(view, message);
- expect(view.sendMessage).toHaveBeenCalled();
- var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
- expect(msg.text()).toEqual(message);
- expect(msg.html()).toEqual('http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever');
+ it("will have properly escaped URLs", function () {
+ if (/PhantomJS/.test(window.navigator.userAgent)) {
+ // Flaky under PhantomJS due to timeouts
+ return;
+ }
+ // TODO: make these local urls
+ var message, msg;
+ var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+ test_utils.openChatBoxFor(contact_jid);
+ var view = converse.chatboxviews.get(contact_jid);
+ spyOn(view, 'sendMessage').andCallThrough();
+ runs(function () {
+ message = "http://www.opkode.com/'onmouseover='alert(1)'whatever";
+ test_utils.sendMessage(view, message);
+ });
+ waits(500);
+ runs(function () {
+ expect(view.sendMessage).toHaveBeenCalled();
+ msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
+ expect(msg.text()).toEqual(message);
+ expect(msg.html()).toEqual('http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever');
- message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
- test_utils.sendMessage(view, message);
- expect(view.sendMessage).toHaveBeenCalled();
- msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
- expect(msg.text()).toEqual(message);
- expect(msg.html()).toEqual('http://www.opkode.com/"onmouseover="alert(1)"whatever');
+ message = 'http://www.opkode.com/"onmouseover="alert(1)"whatever';
+ test_utils.sendMessage(view, message);
+ });
+ waits(500);
+ runs(function () {
+ expect(view.sendMessage).toHaveBeenCalled();
+ msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
+ expect(msg.text()).toEqual(message);
+ expect(msg.html()).toEqual('http://www.opkode.com/"onmouseover="alert(1)"whatever');
- message = "https://en.wikipedia.org/wiki/Ender's_Game";
- test_utils.sendMessage(view, message);
- expect(view.sendMessage).toHaveBeenCalled();
- msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
- expect(msg.text()).toEqual(message);
- expect(msg.html()).toEqual('https://en.wikipedia.org/wiki/Ender\'s_Game');
+ message = "https://en.wikipedia.org/wiki/Ender's_Game";
+ test_utils.sendMessage(view, message);
+ });
+ waits(500);
+ runs(function () {
+ expect(view.sendMessage).toHaveBeenCalled();
+ msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
+ expect(msg.text()).toEqual(message);
+ expect(msg.html()).toEqual('https://en.wikipedia.org/wiki/Ender\'s_Game');
- message = "https://en.wikipedia.org/wiki/Ender%27s_Game";
- test_utils.sendMessage(view, message);
- expect(view.sendMessage).toHaveBeenCalled();
- msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
- expect(msg.text()).toEqual(message);
- expect(msg.html()).toEqual('https://en.wikipedia.org/wiki/Ender%27s_Game');
- }.bind(converse));
+ message = "https://en.wikipedia.org/wiki/Ender%27s_Game";
+ test_utils.sendMessage(view, message);
+ });
+ waits(500);
+ runs(function () {
+ expect(view.sendMessage).toHaveBeenCalled();
+ msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
+ expect(msg.text()).toEqual(message);
+ expect(msg.html()).toEqual('https://en.wikipedia.org/wiki/Ender%27s_Game');
+ });
+ });
+
+ it("will render images from their URLs", function () {
+ if (/PhantomJS/.test(window.navigator.userAgent)) {
+ // Doesn't work when running tests in PhantomJS, since
+ // the page is loaded via file:///
+ return;
+ }
+ var message = document.URL.split(window.location.pathname)[0] + "/logo/conversejs.svg";
+ var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
+ test_utils.openChatBoxFor(contact_jid);
+ var view = converse.chatboxviews.get(contact_jid);
+ spyOn(view, 'sendMessage').andCallThrough();
+ runs(function () {
+ test_utils.sendMessage(view, message);
+ });
+ waits(500);
+ runs(function () {
+ expect(view.sendMessage).toHaveBeenCalled();
+ var msg = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-msg-content');
+ expect(msg.html()).toEqual('');
+ });
+ });
}.bind(converse));
diff --git a/src/utils.js b/src/utils.js
index 227bfd8ef..0da69a171 100755
--- a/src/utils.js
+++ b/src/utils.js
@@ -20,6 +20,16 @@
'list-multi': 'dropdown'
};
+ var isImage = function (url) {
+ var deferred = new $.Deferred();
+ $("", {
+ src: url,
+ error: deferred.reject,
+ load: deferred.resolve
+ });
+ return deferred.promise();
+ };
+
$.expr[':'].emptyVal = function(obj){
return obj.value === '';
};
@@ -34,19 +44,27 @@
return false;
};
+ $.fn.throttledHTML = _.throttle($.fn.html, 500);
+
$.fn.addHyperlinks = function () {
if (this.length > 0) {
this.each(function (i, obj) {
- var x = $(obj).html();
- var list = x.match(/\b(https?:\/\/|www\.|https?:\/\/www\.)[^\s<]{2,200}\b/g );
- if (list) {
- for (i=0; i'+ list[i] + '' );
- }
- }
- $(obj).html(x);
+ var $obj = $(obj);
+ var x = $obj.html();
+ _.each(x.match(/\b(https?:\/\/|www\.|https?:\/\/www\.)[^\s<]{2,200}\b/g), function (url) {
+ isImage(url)
+ .then(function () {
+ event.target.className = 'chat-image';
+ x = x.replace(url, event.target.outerHTML);
+ $obj.throttledHTML(x);
+ })
+ .fail(function () {
+ var prot = url.indexOf('http://') === 0 || url.indexOf('https://') === 0 ? '' : 'http://';
+ var escaped_url = encodeURI(decodeURI(url)).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
+ x = x.replace(url, ''+ url + '' );
+ $obj.throttledHTML(x);
+ });
+ });
});
}
return this;