Merge branch 'worlword-httpFileUpload' into http-file-upload
This commit is contained in:
commit
9c2a5bd3b8
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
}));
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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') ?
|
||||
|
@ -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': {
|
||||
|
@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
ChatRoomView: {
|
||||
events: {
|
||||
'click .upload-file': 'toggleFileUpload',
|
||||
'change .input.fileupload': 'handleFileSelect'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initialize () {
|
||||
/* The initialize function gets called as soon as the plugin is
|
||||
* loaded by converse.js's plugin machinery.
|
||||
*/
|
||||
const { _converse } = this;
|
||||
}
|
||||
});
|
||||
return converse;
|
||||
}));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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(
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user