소스 검색

Merge branch 'worlword-httpFileUpload' into http-file-upload

JC Brand 7 년 전
부모
커밋
9c2a5bd3b8

+ 7 - 0
CHANGES.md

@@ -1,5 +1,12 @@
 # Changelog
 
+## Http-File-Upload
+
+## New Features
+
+- files can now be sent via http-file-upload (XEP-0363)
+- mp4 and mp3 files will now be playable directly in chat. 
+
 ## 4.0.0 (Unreleased)
 
 ## UI changes

+ 4 - 0
locale/de/LC_MESSAGES/converse.po

@@ -145,6 +145,10 @@ msgstr "tippt nicht mehr"
 msgid "has gone away"
 msgstr "ist jetzt abwesend"
 
+#: src/converse-chatview.js:860
+msgid "Choose a file to send"
+msgstr "Datei versenden"
+
 #: dist/converse-no-dependencies.js:14851
 #: dist/converse-no-dependencies.js:23427
 msgid "Remove messages"

+ 1 - 1
spec/chatbox.js

@@ -416,7 +416,7 @@
                     expect(view).toBeDefined();
                     var $toolbar = $(view.el).find('ul.chat-toolbar');
                     expect($toolbar.length).toBe(1);
-                    expect($toolbar.children('li').length).toBe(2);
+                    expect($toolbar.children('li').length).toBe(3);
                     done();
                 }));
 

+ 1 - 0
src/build.js

@@ -13,6 +13,7 @@
         "converse-dragresize":      "builds/converse-dragresize",
         "converse-fullscreen":      "builds/converse-fullscreen",
         "converse-headline":        "builds/converse-headline",
+        "converse-http-file-upload":"builds/converse-http-file-upload",
         "converse-mam":             "builds/converse-mam",
         "converse-minimize":        "builds/converse-minimize",
         "converse-modal":           "builds/converse-modal",

+ 99 - 3
src/converse-chatboxes.js

@@ -15,8 +15,8 @@
 }(this, function (converse, tpl_chatboxes) {
     "use strict";
 
-    const { Backbone, Promise, Strophe, b64_sha1, moment, utils, _ } = converse.env;
-
+    const { $msg, Backbone, Promise, Strophe, b64_sha1, moment, utils, _ } = converse.env;
+    Strophe.addNamespace('OUTOFBAND', 'jabber:x:oob');
 
     converse.plugins.add('converse-chatboxes', {
 
@@ -50,7 +50,8 @@
             /* The initialize function gets called as soon as the plugin is
              * loaded by converse.js's plugin machinery.
              */
-            const { _converse } = this;
+            const { _converse } = this,
+                { __ } = _converse;
 
             _converse.api.promises.add([
                 'chatBoxesFetched',
@@ -115,6 +116,101 @@
                     });
                 },
 
+                createFileMessageStanza (message, to) {
+                    const stanza = $msg({
+                        'from': _converse.connection.jid,
+                        'to': to,
+                        'type': 'chat',
+                        'id': message.get('msgid')
+                    }).c('body').t(message.get('message')).up()
+                      .c(_converse.ACTIVE, {'xmlns': Strophe.NS.CHATSTATES}).up()
+                      .c('x', {'xmlns': Strophe.NS.OUTOFBAND}).c('url').t(message.get('message')).up();
+
+                    return stanza;
+                },
+
+                sendFile (file, chatbox) {
+                    const self = this;
+                    const request_slot_url = 'upload.' + _converse.domain;
+                    _converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, request_slot_url)
+                        .then((result) => { 
+                            chatbox.showHelpMessages([__('The file upload starts now')],'info');
+                            self.requestSlot(file, request_slot_url, function(data) {
+                                if (!data) {
+                                    alert(__('File upload failed. Please check the log.'));
+                                } else if (data.error) {
+                                    alert(__('File upload failed. Please check the log.'));
+                                } else if (data.get && data.put) {
+                                    self.uploadFile(data.put, file, function() {
+                                        console.log(data.put);
+                                        chatbox.onMessageSubmitted(data.put, null, file);
+                                    });
+                                }
+                            });
+                        });
+                },
+
+                requestSlot (file, request_slot_url, cb) {
+                    const self = this;
+                    console.log("try sending file to: " + request_slot_url);
+                    const iq = converse.env.$iq({
+                        to: request_slot_url,
+                        type: 'get'
+                    }).c('request', {
+                        xmlns: Strophe.NS.HTTPUPLOAD
+                    }).c('filename').t(file.name)
+                    .up()
+                    .c('size').t(file.size);
+                
+                    _converse.connection.sendIQ(iq, function(stanza) {
+                        self.successfulRequestSlotCB(stanza, cb);
+                    }, function(stanza) {
+                        self.failedRequestSlotCB(stanza, cb);
+                    });
+                },
+                
+                uploadFile (url, file, callback) {
+                    console.log("uploadFile start");
+                    const xmlhttp = new XMLHttpRequest();
+                    const contentType = 'application/octet-stream';
+                    xmlhttp.onreadystatechange = function() {
+                        if (xmlhttp.readyState === XMLHttpRequest.DONE) {   
+                            console.log("Status: " + xmlhttp.status);
+                            if (xmlhttp.status === 200 || xmlhttp.status === 201) {
+                                if (callback) {
+                                    callback();
+                                }    
+                            }
+                            else {
+                                alert(__('Could not upload File please try again.'));
+                            }
+                        }
+                    };
+                
+                    xmlhttp.open('PUT', url, true);
+                    xmlhttp.setRequestHeader("Content-type", contentType);
+                    xmlhttp.send(file);
+                },
+
+                successfulRequestSlotCB (stanza, cb) {
+                    const slot = stanza.getElementsByTagName('slot')[0];
+                
+                    if (slot != undefined) {
+                        var put = slot.getElementsByTagName('put')[0].textContent;
+                        var get = slot.getElementsByTagName('get')[0].textContent;
+                        cb({
+                            put: put,
+                            get: get
+                        });
+                    } else {
+                        this.failedRequestSlotCB(stanza, cb);
+                    }
+                },
+                
+                failedRequestSlotCB (stanza, cb) {
+                    alert(__('Could not upload File please try again.'));
+                },
+
                 getMessageBody (message) {
                     const type = message.getAttribute('type');
                     return (type === 'error') ?

+ 22 - 10
src/converse-chatview.js

@@ -28,6 +28,7 @@
             "tpl!spoiler_message",
             "tpl!status_message",
             "tpl!toolbar",
+            "converse-http-file-upload",
             "converse-chatboxes"
     ], factory);
 }(this, function (
@@ -50,7 +51,8 @@
             tpl_spoiler_button,
             tpl_spoiler_message,
             tpl_status_message,
-            tpl_toolbar
+            tpl_toolbar,
+            filetransfer
     ) {
     "use strict";
     const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
@@ -237,7 +239,6 @@
                 }
             });
 
-
             _converse.ChatBoxView = Backbone.NativeView.extend({
                 length: 200,
                 className: 'chatbox hidden',
@@ -648,7 +649,14 @@
                     if (attrs.is_spoiler) {
                         this.renderSpoilerMessage(msg, attrs)
                     }
-                    u.renderImageURLs(msg_content).then(this.scrollDown.bind(this));
+                    
+                    if (msg_content.textContent.endsWith('mp4')) {
+                        msg_content.innerHTML = u.renderMovieURLs(msg_content);
+                    } else if (msg_content.textContent.endsWith('mp3')) {
+                        msg_content.innerHTML = u.renderAudioURLs(msg_content); 
+                    } else {
+                        u.renderImageURLs(msg_content).then(this.scrollDown.bind(this));
+                    }
                     return msg;
                 },
 
@@ -807,7 +815,7 @@
                     return stanza;
                 },
 
-                sendMessage (message) {
+                sendMessage (message, file = null) {
                     /* Responsible for sending off a text message.
                      *
                      *  Parameters:
@@ -815,7 +823,13 @@
                      */
                     // TODO: We might want to send to specfic resources.
                     // Especially in the OTR case.
-                    const messageStanza = this.createMessageStanza(message);
+                    var messageStanza;
+                    if (file !== null) {
+                        messageStanza = this.model.createFileMessageStanza(message, this.model.get('jid'));
+                    }
+                    else {
+                        messageStanza = this.createMessageStanza(message);
+                    }
                     _converse.connection.send(messageStanza);
                     if (_converse.forward_messages) {
                         // Forward the message, so that other connected resources are also aware of it.
@@ -850,7 +864,7 @@
                     }
                 },
 
-                onMessageSubmitted (text, spoiler_hint) {
+                onMessageSubmitted (text, spoiler_hint, file = null) {
                     /* This method gets called once the user has typed a message
                      * and then pressed enter in a chat box.
                      *
@@ -869,9 +883,9 @@
                     if (this.parseMessageForCommands(text)) {
                         return;
                     }
-                    const attrs = this.getOutgoingMessageAttributes(text, spoiler_hint)
+                    const attrs = this.getOutgoingMessageAttributes(text, spoiler_hint);
                     const message = this.model.messages.create(attrs);
-                    this.sendMessage(message);
+                    this.sendMessage(message, file);
                 },
 
                 getOutgoingMessageAttributes (text, spoiler_hint) {
@@ -1228,13 +1242,11 @@
                 }
             });
 
-
             _converse.on('connected', () => {
                 // Advertise that we support XEP-0382 Message Spoilers
                 _converse.connection.disco.addFeature(Strophe.NS.SPOILER);
             });
 
-
             /************************ BEGIN API ************************/
             _.extend(_converse.api, {
                 'chatviews': {

+ 28 - 9
src/converse-http-file-upload.js

@@ -1,3 +1,7 @@
+/**
+ * Adds Support for Http File Upload (XEP-0363)
+ *
+ */
 (function (root, factory) {
     define([
         "converse-core",
@@ -22,11 +26,15 @@
          *
          * NB: These plugins need to have already been loaded via require.js.
          */
-        dependencies: ["converse-chatview"],
+        dependencies: ["converse-chatboxes", "converse-chatview", "converse-muc-views"],
 
         overrides: {
-
             ChatBoxView:  {
+                events: {
+                    'click .upload-file': 'toggleFileUpload',
+                    'change input.fileupload': 'handleFileSelect'
+                },
+
                 addFileUploadButton (options) {
                     const { __ } = this.__super__._converse;
                     this.el.querySelector('.chat-toolbar').insertAdjacentHTML(
@@ -44,15 +52,26 @@
                             }
                         });
                     return result;
+                },
+
+                toggleFileUpload (ev) {
+                    this.el.querySelector('.input.fileupload').click();
+                },
+
+                handleFileSelect (evt) {
+                    var files = evt.target.files;
+                    var file = files[0];
+                    this.model.sendFile(file, this);
                 }
-            }
-        },
+            },
 
-        initialize () {
-            /* The initialize function gets called as soon as the plugin is
-             * loaded by converse.js's plugin machinery.
-             */
-            const { _converse } = this;
+            ChatRoomView: {
+                events: {
+                    'click .upload-file': 'toggleFileUpload',
+                    'change .input.fileupload': 'handleFileSelect'
+                }
+            }
         }
     });
+    return converse;
 }));

+ 6 - 1
src/converse-muc-views.js

@@ -826,13 +826,18 @@
                     this.showErrorMessage(__("Error: could not execute the command"), true);
                 },
 
-                onMessageSubmitted (text) {
+                // the notNeeded-Parameter is there so this method has the same amount of parameters as converse-chatview.js->onMessageSubmitted
+                // this allows to call the same method from diffrent plugins 
+                onMessageSubmitted (text, notNeeded = null, file = null) {
                     /* Gets called when the user presses enter to send off a
                      * message in a chat room.
                      *
                      * Parameters:
                      *    (String) text - The message text.
                      */
+                    if (file !== null) {
+                        return this.model.sendChatRoomFile(text,this.model.get('jid'));
+                    }
                     if (_converse.muc_disable_moderator_commands) {
                         return this.sendChatRoomMessage(text);
                     }

+ 12 - 0
src/converse-muc.js

@@ -335,6 +335,18 @@
                     const jid = Strophe.getBareJidFromJid(room);
                     return jid + (nick !== null ? `/${nick}` : "");
                 },
+                
+                sendChatRoomFile (text, to) {
+                    const msgid = _converse.connection.getUniqueId();
+                    const stanza = $msg({
+                        'from': _converse.connection.jid,
+                        'to': to,
+                        'type': 'groupchat',
+                        'id': msgid
+                    }).c("body").t(text).up()
+                      .c("x", {'xmlns': Strophe.NS.OUTOFBAND}).c('url').t(text).up();
+                      _converse.connection.send(stanza);
+                },
 
                 directInvite (recipient, reason) {
                     /* Send a direct invitation as per XEP-0249

+ 1 - 1
src/converse.js

@@ -13,7 +13,7 @@ if (typeof define !== 'undefined') {
         "converse-dragresize",      // Allows chat boxes to be resized by dragging them
         "converse-fullscreen",
         "converse-headline",        // Support for headline messages
-        "converse-http-file-upload",
+        "converse-http-file-upload",// Support for XEP-0363
         "converse-mam",             // XEP-0313 Message Archive Management
         "converse-minimize",        // Allows chat boxes to be minimized
         "converse-muc",             // XEP-0045 Multi-user chat

+ 1 - 0
src/inverse.js

@@ -25,6 +25,7 @@ if (typeof define !== 'undefined') {
         "converse-register",    // XEP-0077 In-band registration
         "converse-roomslist",   // Show currently open chat rooms
         "converse-vcard",       // XEP-0054 VCard-temp
+        "converse-http-file-upload", // Support for XEP-0363
         /* END: Removable components */
 
         "converse-inverse",     // Inverse plugin for converse.js

+ 4 - 1
src/templates/toolbar_fileupload.html

@@ -1 +1,4 @@
-<li class="upload-file fa fa-paperclip" title="{{{o.tooltip_upload_file}}}"></li>
+<input type="file" class="fileupload" style="display:none"/>
+<li class="upload-file">
+    <a class="fa fa-paperclip" title="{{{o.tooltip_upload_file}}}"></a>
+</li> 

+ 8 - 0
src/utils/core.js

@@ -213,6 +213,14 @@
             ))
     };
 
+    u.renderMovieURLs = function (obj) {
+        return "<video controls><source src=\"" + obj.textContent + "\" type=\"video/mp4\"></video>";
+    };
+
+    u.renderAudioURLs = function (obj) {
+        return "<audio controls><source src=\"" + obj.textContent + "\" type=\"audio/mpeg\"></audio>";
+    };
+
     u.slideInAllElements = function (elements, duration=300) {
         return Promise.all(
             _.map(

+ 1 - 0
tests/runner-transpiled.js

@@ -24,6 +24,7 @@ config.paths["converse-core"] =         "builds/converse-core";
 config.paths["converse-disco"] =        "builds/converse-disco";
 config.paths["converse-dragresize"] =   "builds/converse-dragresize";
 config.paths["converse-headline"] =     "builds/converse-headline";
+config.paths["converse-http-file-upload"]="builds/converse-http-file-upload";
 config.paths["converse-fullscreen"] =   "builds/converse-fullscreen";
 config.paths["converse-mam"] =          "builds/converse-mam";
 config.paths["converse-minimize"] =     "builds/converse-minimize";