瀏覽代碼

Render images from URLs

JC Brand 9 年之前
父節點
當前提交
5a1b308edd
共有 4 個文件被更改,包括 120 次插入49 次删除
  1. 3 0
      css/converse.css
  2. 4 0
      sass/_chatbox.scss
  3. 85 39
      spec/chatbox.js
  4. 28 10
      src/utils.js

+ 3 - 0
css/converse.css

@@ -1347,6 +1347,9 @@
       #conversejs .chatbox .chat-body .chat-info.chat-date {
       #conversejs .chatbox .chat-body .chat-info.chat-date {
         display: inline-block;
         display: inline-block;
         margin-top: 1em; }
         margin-top: 1em; }
+    #conversejs .chatbox .chat-body .chat-image {
+      max-width: 100%;
+      max-height: 100%; }
     #conversejs .chatbox .chat-body .chat-message {
     #conversejs .chatbox .chat-body .chat-message {
       margin: 0.3em; }
       margin: 0.3em; }
       #conversejs .chatbox .chat-body .chat-message span {
       #conversejs .chatbox .chat-body .chat-message span {

+ 4 - 0
sass/_chatbox.scss

@@ -154,6 +154,10 @@
                     margin-top: 1em;
                     margin-top: 1em;
                 }
                 }
             }
             }
+            .chat-image {
+                max-width: 100%;
+                max-height: 100%;
+            }
             .chat-message {
             .chat-message {
                 margin: 0.3em;
                 margin: 0.3em;
                 span {
                 span {

+ 85 - 39
spec/chatbox.js

@@ -819,19 +819,6 @@
                     expect(msg.html()).toEqual('<p>This message contains <em>some</em> <b>markup</b></p>');
                     expect(msg.html()).toEqual('<p>This message contains <em>some</em> <b>markup</b></p>');
                 }.bind(converse));
                 }.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: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
-                }.bind(converse));
-
                 it("should display emoticons correctly", function () {
                 it("should display emoticons correctly", function () {
                     var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
                     var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
                     test_utils.openChatBoxFor(contact_jid);
                     test_utils.openChatBoxFor(contact_jid);
@@ -856,40 +843,99 @@
                     }
                     }
                 }.bind(converse));
                 }.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 = 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: <a target="_blank" rel="noopener" href="http://www.opkode.com">www.opkode.com</a>');
+                    });
+                });
+
                 it("will have properly escaped URLs", function () {
                 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';
                     var contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
                     test_utils.openChatBoxFor(contact_jid);
                     test_utils.openChatBoxFor(contact_jid);
-                    var view = this.chatboxviews.get(contact_jid);
+                    var view = converse.chatboxviews.get(contact_jid);
                     spyOn(view, 'sendMessage').andCallThrough();
                     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('<a target="_blank" rel="noopener" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
 
 
-                    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('<a target="_blank" rel="noopener" href="http://www.opkode.com/%27onmouseover=%27alert%281%29%27whatever">http://www.opkode.com/\'onmouseover=\'alert(1)\'whatever</a>');
+                        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('<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
 
 
-                    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('<a target="_blank" rel="noopener" href="http://www.opkode.com/%22onmouseover=%22alert%281%29%22whatever">http://www.opkode.com/"onmouseover="alert(1)"whatever</a>');
+                        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('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">https://en.wikipedia.org/wiki/Ender\'s_Game</a>');
 
 
-                    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('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">https://en.wikipedia.org/wiki/Ender\'s_Game</a>');
+                        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('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">https://en.wikipedia.org/wiki/Ender%27s_Game</a>');
+                    });
+                });
 
 
-                    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('<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Ender%27s_Game">https://en.wikipedia.org/wiki/Ender%27s_Game</a>');
-                }.bind(converse));
+                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('<img src="'+message+'" class="chat-image">');
+                    });
+                });
 
 
             }.bind(converse));
             }.bind(converse));
 
 

+ 28 - 10
src/utils.js

@@ -20,6 +20,16 @@
         'list-multi': 'dropdown'
         'list-multi': 'dropdown'
     };
     };
 
 
+    var isImage = function (url) {
+        var deferred = new $.Deferred();
+        $("<img>", {
+            src: url,
+            error: deferred.reject,
+            load: deferred.resolve
+        });
+        return deferred.promise();
+    };
+
     $.expr[':'].emptyVal = function(obj){
     $.expr[':'].emptyVal = function(obj){
         return obj.value === '';
         return obj.value === '';
     };
     };
@@ -34,19 +44,27 @@
         return false;
         return false;
     };
     };
 
 
+    $.fn.throttledHTML = _.throttle($.fn.html, 500);
+
     $.fn.addHyperlinks = function () {
     $.fn.addHyperlinks = function () {
         if (this.length > 0) {
         if (this.length > 0) {
             this.each(function (i, obj) {
             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.length; i++) {
-                        var prot = list[i].indexOf('http://') === 0 || list[i].indexOf('https://') === 0 ? '' : 'http://';
-                        var escaped_url = encodeURI(decodeURI(list[i])).replace(/[!'()]/g, escape).replace(/\*/g, "%2A");
-                        x = x.replace(list[i], '<a target="_blank" rel="noopener" href="' + prot + escaped_url + '">'+ list[i] + '</a>' );
-                    }
-                }
-                $(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, '<a target="_blank" rel="noopener" href="' + prot + escaped_url + '">'+ url + '</a>' );
+                            $obj.throttledHTML(x);
+                        });
+                });
             });
             });
         }
         }
         return this;
         return this;