added httpFileUpload to converse.js
This commit is contained in:
parent
e31373a6ae
commit
b23712aec3
@ -145,6 +145,10 @@ msgstr "tippt nicht mehr"
|
||||
msgid "has gone away"
|
||||
msgstr "ist jetzt abwesend"
|
||||
|
||||
#: src/converse-chatview.js:860
|
||||
msgid "Upload a File"
|
||||
msgstr "Datei versenden"
|
||||
|
||||
#: dist/converse-no-dependencies.js:14851
|
||||
#: dist/converse-no-dependencies.js:23427
|
||||
msgid "Remove messages"
|
||||
|
@ -13,6 +13,7 @@
|
||||
"converse-dragresize": "builds/converse-dragresize",
|
||||
"converse-fullscreen": "builds/converse-fullscreen",
|
||||
"converse-headline": "builds/converse-headline",
|
||||
"converse-httpFileUpload": "builds/converse-httpFileUpload",
|
||||
"converse-mam": "builds/converse-mam",
|
||||
"converse-minimize": "builds/converse-minimize",
|
||||
"converse-modal": "builds/converse-modal",
|
||||
|
@ -74,6 +74,7 @@ require.config({
|
||||
"converse-dragresize": "src/converse-dragresize",
|
||||
"converse-fullscreen": "src/converse-fullscreen",
|
||||
"converse-headline": "src/converse-headline",
|
||||
"converse-httpFileUpload": "src/converse-httpFileUpload",
|
||||
"converse-mam": "src/converse-mam",
|
||||
"converse-minimize": "src/converse-minimize",
|
||||
"converse-modal": "src/converse-modal",
|
||||
|
@ -25,6 +25,7 @@
|
||||
"tpl!spoiler_button",
|
||||
"tpl!spoiler_message",
|
||||
"tpl!toolbar",
|
||||
"converse-httpFileUpload",
|
||||
"converse-chatboxes"
|
||||
], factory);
|
||||
}(this, function (
|
||||
@ -44,7 +45,8 @@
|
||||
tpl_spinner,
|
||||
tpl_spoiler_button,
|
||||
tpl_spoiler_message,
|
||||
tpl_toolbar
|
||||
tpl_toolbar,
|
||||
filetransfer
|
||||
) {
|
||||
"use strict";
|
||||
const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
|
||||
@ -54,6 +56,8 @@
|
||||
FORWARD_SLASH: 47
|
||||
};
|
||||
|
||||
Strophe.addNamespace('OUTOFBAND', 'jabber:x:oob');
|
||||
|
||||
converse.plugins.add('converse-chatview', {
|
||||
/* Plugin dependencies are other plugins which might be
|
||||
* overridden or relied upon, and therefore need to be loaded before
|
||||
@ -108,7 +112,8 @@
|
||||
'call': false,
|
||||
'clear': true,
|
||||
'emoji': true,
|
||||
'spoiler': true
|
||||
'spoiler': true,
|
||||
'fileUpload': true
|
||||
},
|
||||
});
|
||||
emojione.imagePathPNG = _converse.emojione_image_path;
|
||||
@ -247,7 +252,22 @@
|
||||
'click .toggle-smiley': 'toggleEmojiMenu',
|
||||
'click .toggle-spoiler': 'toggleSpoilerMessage',
|
||||
'click .toggle-compose-spoiler': 'toggleComposeSpoilerMessage',
|
||||
'keypress .chat-textarea': 'keyPressed'
|
||||
'keypress .chat-textarea': 'keyPressed',
|
||||
'click .toggle-fileUpload': 'toggleFileUpload',
|
||||
'change .fileUpload_input': 'handleFileSelect'
|
||||
},
|
||||
|
||||
toggleFileUpload(ev) {
|
||||
_converse.FileUpload.prototype.initFiletransfer(_converse.connection);
|
||||
var uploadDialog = this.el.querySelector('.fileUpload_input');
|
||||
uploadDialog.click();
|
||||
},
|
||||
|
||||
handleFileSelect(evt) {
|
||||
var files = evt.target.files;
|
||||
var file = files[0];
|
||||
var jid = this.jid;
|
||||
_converse.FileUpload.prototype.setFile(file,this);
|
||||
},
|
||||
|
||||
initialize () {
|
||||
@ -368,9 +388,11 @@
|
||||
'label_clear': __('Clear all messages'),
|
||||
'label_insert_smiley': __('Insert a smiley'),
|
||||
'label_start_call': __('Start a call'),
|
||||
'label_upload_file': __('Upload a File'),
|
||||
'label_toggle_spoiler': label_toggle_spoiler,
|
||||
'show_call_button': _converse.visible_toolbar_buttons.call,
|
||||
'show_spoiler_button': _converse.visible_toolbar_buttons.spoiler,
|
||||
'show_fileUpload_button': _converse.visible_toolbar_buttons.fileUpload,
|
||||
'use_emoji': _converse.visible_toolbar_buttons.emoji,
|
||||
});
|
||||
},
|
||||
@ -639,7 +661,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;
|
||||
},
|
||||
|
||||
@ -771,6 +800,19 @@
|
||||
return stanza;
|
||||
},
|
||||
|
||||
createFileMessageStanza(message){
|
||||
const stanza = $msg({
|
||||
'from': _converse.connection.jid,
|
||||
'to': this.model.get('jid'),
|
||||
'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;
|
||||
},
|
||||
|
||||
sendMessage (message) {
|
||||
/* Responsible for sending off a text message.
|
||||
*
|
||||
@ -779,8 +821,7 @@
|
||||
*/
|
||||
// TODO: We might want to send to specfic resources.
|
||||
// Especially in the OTR case.
|
||||
const messageStanza = this.createMessageStanza(message);
|
||||
_converse.connection.send(messageStanza);
|
||||
_converse.connection.send(message);
|
||||
if (_converse.forward_messages) {
|
||||
// Forward the message, so that other connected resources are also aware of it.
|
||||
_converse.connection.send(
|
||||
@ -790,7 +831,7 @@
|
||||
'xmns': Strophe.NS.DELAY,
|
||||
'stamp': moment().format()
|
||||
}).up()
|
||||
.cnode(messageStanza.tree())
|
||||
.cnode(message.tree())
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -814,7 +855,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.
|
||||
*
|
||||
@ -833,9 +874,18 @@
|
||||
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);
|
||||
|
||||
/* check, if a file was send. If true it will send the file with XEP-0066. */
|
||||
var messageStanza;
|
||||
if(file !== null){
|
||||
messageStanza = this.createFileMessageStanza(message);
|
||||
}
|
||||
else {
|
||||
messageStanza = this.createMessageStanza(message);
|
||||
}
|
||||
this.sendMessage(messageStanza);
|
||||
},
|
||||
|
||||
getOutgoingMessageAttributes (text, spoiler_hint) {
|
||||
|
@ -78,6 +78,7 @@
|
||||
'converse-dropdown',
|
||||
'converse-fullscreen',
|
||||
'converse-headline',
|
||||
'converse-httpFileUpload',
|
||||
'converse-mam',
|
||||
'converse-minimize',
|
||||
'converse-modal',
|
||||
|
269
src/converse-httpFileUpload.js
Normal file
269
src/converse-httpFileUpload.js
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Klaus Herberth <klaus@jsxc.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements Http File Upload (XEP-0363)
|
||||
*
|
||||
* @see {@link http://xmpp.org/extensions/xep-0363.html}
|
||||
*/
|
||||
(function (root, factory) {
|
||||
define([
|
||||
"converse-core",
|
||||
], factory);
|
||||
}(this, function (
|
||||
converse
|
||||
) {
|
||||
"use strict";
|
||||
const { $msg, Backbone, Strophe, _, b64_sha1, moment, utils } = converse.env;
|
||||
|
||||
Strophe.addNamespace('HTTPUPLOAD', 'urn:xmpp:http:upload');
|
||||
|
||||
var requestSlotUrl;
|
||||
var ready;
|
||||
var httpUploadOption = {
|
||||
enable: true
|
||||
}
|
||||
|
||||
converse.plugins.add('converse-httpFileUpload', {
|
||||
|
||||
dependencies: ["converse-chatboxes", "converse-disco"],
|
||||
|
||||
initialize() {
|
||||
const { _converse } = this,
|
||||
{ __ } = _converse;
|
||||
var connection = _converse.connection;
|
||||
var domain;
|
||||
var file;
|
||||
var chatBox;
|
||||
|
||||
_converse.FileUpload = Backbone.NativeView.extend({
|
||||
/**
|
||||
* Set up http file upload.
|
||||
*
|
||||
* @param {*} connection the current strophe-connection
|
||||
*/
|
||||
initFiletransfer () {
|
||||
connection = _converse.connection;
|
||||
domain = _converse.connection.domain;
|
||||
|
||||
if (httpUploadOption && requestSlotUrl != undefined) {
|
||||
ready = true;
|
||||
return;
|
||||
}
|
||||
this.discoverUploadService();
|
||||
},
|
||||
|
||||
/**
|
||||
* Discover upload service for http upload.
|
||||
*
|
||||
*/
|
||||
discoverUploadService () {
|
||||
var self = this;
|
||||
console.log('discover http upload service');
|
||||
connection.disco.items(domain, null, function(items) {
|
||||
var childs = items.getElementsByTagName('item');
|
||||
for(var i = 0; i < childs.length; i++){
|
||||
var jid = childs[i].attributes.jid.value;
|
||||
if (ready) {
|
||||
// abort, because we already found a service
|
||||
return false;
|
||||
}
|
||||
self.queryItemForUploadService(jid);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Query item for upload service.
|
||||
*
|
||||
* @param {String} jid of the logged-in user
|
||||
* @param {Function} cb Callback on success
|
||||
*/
|
||||
queryItemForUploadService (jid) {
|
||||
var self = this;
|
||||
console.log('query ' + jid + ' for upload service');
|
||||
|
||||
connection.disco.info(jid, null, function(info) {
|
||||
var httpUploadFeature;
|
||||
var temp = info.getElementsByTagName('feature');
|
||||
for(var i = 0; i < temp.length; i++){
|
||||
var feature = temp[i].attributes.var;
|
||||
if(feature != undefined && feature.value === Strophe.NS.HTTPUPLOAD){
|
||||
requestSlotUrl = jid;
|
||||
ready = true;
|
||||
self.sendFile();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the file the user has picked.
|
||||
*
|
||||
* @param {*} file the name of the file the user has picked.
|
||||
* @param {*} chatBox the chatbox from which the user initiated the file-upload
|
||||
*/
|
||||
setFile (file1, chatBox1){
|
||||
file = file1;
|
||||
chatBox = chatBox1;
|
||||
this.sendFile();
|
||||
},
|
||||
|
||||
/**
|
||||
* Upload file.
|
||||
* Waits till the Upload-Service is discovered and till the user has picked a file.
|
||||
*
|
||||
*/
|
||||
sendFile () {
|
||||
var self = this;
|
||||
if(file === undefined){
|
||||
console.log("waiting to choose a file");
|
||||
return;
|
||||
}
|
||||
else if(requestSlotUrl === undefined){
|
||||
console.log("waiting for service discovery");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Send file via http upload');
|
||||
chatBox.showHelpMessages([__('The file upload starts now')],'info');
|
||||
this.requestSlot(file, function(data) {
|
||||
if (!data) {
|
||||
// general error
|
||||
console.log('Unknown error while requesting upload slot.');
|
||||
alert(__('File upload failed. Please check the log.'));
|
||||
} else if (data.error) {
|
||||
// specific error
|
||||
console.log('The XMPP-Server return an error of the type: ' + data.error.type);
|
||||
alert(__('File upload failed. Please check the log.'));
|
||||
} else if (data.get && data.put) {
|
||||
console.log('slot received, start upload to ' + data.put);
|
||||
self.uploadFile(data.put, file, function() {
|
||||
console.log(data.put);
|
||||
|
||||
chatBox.onMessageSubmitted(data.put, null, file);
|
||||
file = undefined;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Request upload slot from xmpp-server
|
||||
*
|
||||
* @param {File} file the file the user picked
|
||||
* @param {Function} cb Callback after finished request
|
||||
*/
|
||||
requestSlot (file, cb) {
|
||||
var self = this;
|
||||
console.log("try sending file to: " + requestSlotUrl);
|
||||
var iq = converse.env.$iq({
|
||||
to: requestSlotUrl,
|
||||
type: 'get'
|
||||
}).c('request', {
|
||||
xmlns: Strophe.NS.HTTPUPLOAD
|
||||
}).c('filename').t(file.name)
|
||||
.up()
|
||||
.c('size').t(file.size);
|
||||
|
||||
connection.sendIQ(iq, function(stanza) {
|
||||
self.successfulRequestSlotCB(stanza, cb);
|
||||
}, function(stanza) {
|
||||
self.failedRequestSlotCB(stanza, cb);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Upload the given file to the given url.
|
||||
*
|
||||
* @param {String} url upload url
|
||||
* @param {File} file the file the user picked
|
||||
* @param {Function} success_cb callback on successful transition
|
||||
*/
|
||||
uploadFile (url, file, success_cb) {
|
||||
console.log("uploadFile start");
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
var type = 'PUT';
|
||||
var contentType = 'application/octet-stream';
|
||||
var data = file;
|
||||
var processData = false;
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
|
||||
console.log("Status: " + xmlhttp.status);
|
||||
if (xmlhttp.status == 200 || xmlhttp.status == 201) {
|
||||
console.log('file successful uploaded');
|
||||
if (success_cb) {
|
||||
success_cb();
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('error while uploading file to ' + url);
|
||||
alert(__('Could not upload File please try again.'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xmlhttp.open(type, url, true);
|
||||
xmlhttp.setRequestHeader("Content-type", contentType);
|
||||
xmlhttp.send(data);
|
||||
|
||||
console.log("uploadFile end");
|
||||
},
|
||||
|
||||
/**
|
||||
* Process successful response to slot request.
|
||||
*
|
||||
* @param {String} stanza
|
||||
* @param {Function} cb
|
||||
*/
|
||||
successfulRequestSlotCB (stanza, cb) {
|
||||
var 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);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process failed response to slot request.
|
||||
*
|
||||
* @param {String} stanza
|
||||
* @param {Function} cb
|
||||
*/
|
||||
failedRequestSlotCB (stanza, cb) {
|
||||
chatBox.showHelpMessages([__('Fileupload failed')],'info');
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
return converse;
|
||||
}));
|
@ -82,6 +82,8 @@
|
||||
'unmoderated': 'moderated'
|
||||
};
|
||||
|
||||
Strophe.addNamespace('OUTOFBAND', 'jabber:x:oob');
|
||||
|
||||
converse.plugins.add('converse-muc-views', {
|
||||
/* Dependencies are other plugins which might be
|
||||
* overridden or relied upon, and therefore need to be loaded before
|
||||
@ -693,6 +695,17 @@
|
||||
msgid
|
||||
});
|
||||
},
|
||||
sendChatRoomFile (text) {
|
||||
const msgid = _converse.connection.getUniqueId();
|
||||
const stanza = $msg({
|
||||
'from': _converse.connection.jid,
|
||||
'to': this.model.get('jid'),
|
||||
'type': 'groupchat',
|
||||
'id': msgid
|
||||
}).c("body").t(text).up()
|
||||
.c("x", {'xmlns': Strophe.NS.OUTOFBAND}).c('url').t(text).up();
|
||||
_converse.connection.send(stanza);
|
||||
},
|
||||
|
||||
modifyRole(room, nick, role, reason, onSuccess, onError) {
|
||||
const item = $build("item", {nick, role});
|
||||
@ -732,13 +745,16 @@
|
||||
this.showStatusNotification(__("Error: could not execute the command"), true);
|
||||
},
|
||||
|
||||
onMessageSubmitted (text) {
|
||||
onMessageSubmitted (text, notNeeded, 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.sendChatRoomFile(text);
|
||||
}
|
||||
if (_converse.muc_disable_moderator_commands) {
|
||||
return this.sendChatRoomMessage(text);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ if (typeof define !== 'undefined') {
|
||||
"converse-minimize", // Allows chat boxes to be minimized
|
||||
"converse-dragresize", // Allows chat boxes to be resized by dragging them
|
||||
"converse-headline", // Support for headline messages
|
||||
"converse-httpFileUpload", // Support for XEP-0363
|
||||
"converse-fullscreen"
|
||||
/* END: Removable components */
|
||||
], function (converse) {
|
||||
|
@ -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-httpFileUpload", // Support for XEP-0363
|
||||
/* END: Removable components */
|
||||
|
||||
"converse-inverse", // Inverse plugin for converse.js
|
||||
|
@ -4,6 +4,12 @@
|
||||
<div class="emoji-picker dropdown-menu toolbar-menu"></div>
|
||||
</li>
|
||||
{[ } ]}
|
||||
{[ if (o.show_fileUpload_button) { ]}
|
||||
<input type="file" class="fileUpload_input" style="display:none"/>
|
||||
<li class="toggle-fileUpload">
|
||||
<a class="fa fa-paperclip" title="{{{o.label_upload_file}}}"></a>
|
||||
</li>
|
||||
{[ } ]}
|
||||
{[ if (o.show_call_button) { ]}
|
||||
<li class="toggle-call fa fa-phone" title="{{{o.label_start_call}}}"></li>
|
||||
{[ } ]}
|
||||
|
@ -3,6 +3,12 @@
|
||||
<div class="emoji-picker dropdown-menu toolbar-menu"></div>
|
||||
</li>
|
||||
{[ } ]}
|
||||
{[ if (o.show_fileUpload_button) { ]}
|
||||
<input type="file" class="fileUpload_input" style="display:none"/>
|
||||
<li class="toggle-fileUpload">
|
||||
<a class="fa fa-paperclip" title="{{{o.label_upload_file}}}"></a>
|
||||
</li>
|
||||
{[ } ]}
|
||||
{[ if (o.show_call_button) { ]}
|
||||
<li class="toggle-call fa fa-phone" title="{{{o.label_start_call}}}"></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-httpFileUpload"]="builds/converse-httpFileUpload";
|
||||
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