Merge branch 'httpFileUpload' of https://github.com/worlword/converse.js into worlword-httpFileUpload
This commit is contained in:
commit
2487d4d001
@ -1,5 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Http-File-Upload
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
- files can now be send via http-file-upload (XEP-0363)
|
||||||
|
- mp4 and mp3 files will now be playable directly in chat.
|
||||||
|
|
||||||
## 4.0.0 (Unreleased)
|
## 4.0.0 (Unreleased)
|
||||||
|
|
||||||
## UI changes
|
## UI changes
|
||||||
|
@ -145,6 +145,10 @@ msgstr "tippt nicht mehr"
|
|||||||
msgid "has gone away"
|
msgid "has gone away"
|
||||||
msgstr "ist jetzt abwesend"
|
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:14851
|
||||||
#: dist/converse-no-dependencies.js:23427
|
#: dist/converse-no-dependencies.js:23427
|
||||||
msgid "Remove messages"
|
msgid "Remove messages"
|
||||||
|
@ -416,7 +416,7 @@
|
|||||||
expect(view).toBeDefined();
|
expect(view).toBeDefined();
|
||||||
var $toolbar = $(view.el).find('ul.chat-toolbar');
|
var $toolbar = $(view.el).find('ul.chat-toolbar');
|
||||||
expect($toolbar.length).toBe(1);
|
expect($toolbar.length).toBe(1);
|
||||||
expect($toolbar.children('li').length).toBe(2);
|
expect($toolbar.children('li').length).toBe(3);
|
||||||
done();
|
done();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
206
spec/http-file-upload.js
Normal file
206
spec/http-file-upload.js
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
(function (root, factory) {
|
||||||
|
define([
|
||||||
|
"jasmine",
|
||||||
|
"jquery",
|
||||||
|
"converse-core",
|
||||||
|
"mock",
|
||||||
|
"test-utils"], factory);
|
||||||
|
} (this, function (jasmine, $, converse, mock, test_utils) {
|
||||||
|
"use strict";
|
||||||
|
var Strophe = converse.env.Strophe;
|
||||||
|
var $iq = converse.env.$iq;
|
||||||
|
var _ = converse.env._;
|
||||||
|
var f = converse.env.f;
|
||||||
|
|
||||||
|
describe("XEP-0363: HTTP File Upload", function () {
|
||||||
|
|
||||||
|
describe("Discovering support", function () {
|
||||||
|
|
||||||
|
it("is done automatically", mock.initConverseWithAsync(function (done, _converse) {
|
||||||
|
var IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
var IQ_ids = _converse.connection.IQ_ids;
|
||||||
|
|
||||||
|
test_utils.waitUntilDiscoConfirmed(_converse, _converse.bare_jid, [], []).then(function () {
|
||||||
|
test_utils.waitUntil(function () {
|
||||||
|
return _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||||
|
}).length > 0;
|
||||||
|
}, 300).then(function () {
|
||||||
|
/* <iq type='result'
|
||||||
|
* from='plays.shakespeare.lit'
|
||||||
|
* to='romeo@montague.net/orchard'
|
||||||
|
* id='info1'>
|
||||||
|
* <query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
|
* <identity
|
||||||
|
* category='server'
|
||||||
|
* type='im'/>
|
||||||
|
* <feature var='http://jabber.org/protocol/disco#info'/>
|
||||||
|
* <feature var='http://jabber.org/protocol/disco#items'/>
|
||||||
|
* </query>
|
||||||
|
* </iq>
|
||||||
|
*/
|
||||||
|
var stanza = _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||||
|
})[0];
|
||||||
|
var info_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
|
||||||
|
|
||||||
|
stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'localhost',
|
||||||
|
'to': 'dummy@localhost/resource',
|
||||||
|
'id': info_IQ_id
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', {
|
||||||
|
'category': 'server',
|
||||||
|
'type': 'im'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'http://jabber.org/protocol/disco#info'}).up()
|
||||||
|
.c('feature', {
|
||||||
|
'var': 'http://jabber.org/protocol/disco#items'});
|
||||||
|
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||||
|
|
||||||
|
_converse.api.disco.entities.get().then(function(entities) {
|
||||||
|
expect(entities.length).toBe(2);
|
||||||
|
expect(_.includes(entities.pluck('jid'), 'localhost')).toBe(true);
|
||||||
|
expect(_.includes(entities.pluck('jid'), 'dummy@localhost')).toBe(true);
|
||||||
|
|
||||||
|
expect(entities.get(_converse.domain).features.length).toBe(2);
|
||||||
|
expect(entities.get(_converse.domain).identities.length).toBe(1);
|
||||||
|
|
||||||
|
return test_utils.waitUntil(function () {
|
||||||
|
// Converse.js sees that the entity has a disco#items feature,
|
||||||
|
// so it will make a query for it.
|
||||||
|
return _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
|
||||||
|
}).length > 0;
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
}).then(function () {
|
||||||
|
/* <iq from='montague.tld'
|
||||||
|
* id='step_01'
|
||||||
|
* to='romeo@montague.tld/garden'
|
||||||
|
* type='result'>
|
||||||
|
* <query xmlns='http://jabber.org/protocol/disco#items'>
|
||||||
|
* <item jid='upload.montague.tld' name='HTTP File Upload' />
|
||||||
|
* <item jid='conference.montague.tld' name='Chatroom Service' />
|
||||||
|
* </query>
|
||||||
|
* </iq>
|
||||||
|
*/
|
||||||
|
var stanza = _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[to="localhost"] query[xmlns="http://jabber.org/protocol/disco#items"]');
|
||||||
|
})[0];
|
||||||
|
var items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
|
||||||
|
stanza = $iq({
|
||||||
|
'type': 'result',
|
||||||
|
'from': 'localhost',
|
||||||
|
'to': 'dummy@localhost/resource',
|
||||||
|
'id': items_IQ_id
|
||||||
|
}).c('query', {'xmlns': 'http://jabber.org/protocol/disco#items'})
|
||||||
|
.c('item', {
|
||||||
|
'jid': 'upload.localhost',
|
||||||
|
'name': 'HTTP File Upload'});
|
||||||
|
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||||
|
|
||||||
|
_converse.api.disco.entities.get().then(function (entities) {
|
||||||
|
expect(entities.length).toBe(2);
|
||||||
|
expect(entities.get('localhost').items.length).toBe(1);
|
||||||
|
return test_utils.waitUntil(function () {
|
||||||
|
// Converse.js sees that the entity has a disco#info feature,
|
||||||
|
// so it will make a query for it.
|
||||||
|
return _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||||
|
}).length > 0;
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
}).then(function () {
|
||||||
|
var stanza = _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[to="upload.localhost"] query[xmlns="http://jabber.org/protocol/disco#info"]');
|
||||||
|
})[0];
|
||||||
|
var IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
|
||||||
|
expect(stanza.toLocaleString()).toBe(
|
||||||
|
"<iq from='dummy@localhost/resource' to='upload.localhost' type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
|
||||||
|
"<query xmlns='http://jabber.org/protocol/disco#info'/>"+
|
||||||
|
"</iq>");
|
||||||
|
|
||||||
|
// Upload service responds and reports a maximum file size of 5MiB
|
||||||
|
/* <iq from='upload.montague.tld'
|
||||||
|
* id='step_02'
|
||||||
|
* to='romeo@montague.tld/garden'
|
||||||
|
* type='result'>
|
||||||
|
* <query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
|
* <identity category='store'
|
||||||
|
* type='file'
|
||||||
|
* name='HTTP File Upload' />
|
||||||
|
* <feature var='urn:xmpp:http:upload:0' />
|
||||||
|
* <x type='result' xmlns='jabber:x:data'>
|
||||||
|
* <field var='FORM_TYPE' type='hidden'>
|
||||||
|
* <value>urn:xmpp:http:upload:0</value>
|
||||||
|
* </field>
|
||||||
|
* <field var='max-file-size'>
|
||||||
|
* <value>5242880</value>
|
||||||
|
* </field>
|
||||||
|
* </x>
|
||||||
|
* </query>
|
||||||
|
* </iq>
|
||||||
|
*/
|
||||||
|
stanza = $iq({'type': 'result', 'to': 'dummy@localhost/resource', 'id': IQ_id, 'from': 'upload.localhost'})
|
||||||
|
.c('query', {'xmlns': 'http://jabber.org/protocol/disco#info'})
|
||||||
|
.c('identity', {'category':'store', 'type':'file', 'name':'HTTP File Upload'}).up()
|
||||||
|
.c('feature', {'var':'urn:xmpp:http:upload:0'}).up()
|
||||||
|
.c('x', {'type':'result', 'xmlns':'jabber:x:data'})
|
||||||
|
.c('field', {'var':'FORM_TYPE', 'type':'hidden'})
|
||||||
|
.c('value').t('urn:xmpp:http:upload:0').up().up()
|
||||||
|
.c('field', {'var':'max-file-size'})
|
||||||
|
.c('value').t('5242880');
|
||||||
|
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||||
|
|
||||||
|
_converse.api.disco.entities.get().then(function (entities) {
|
||||||
|
expect(entities.get('localhost').items.get('upload.localhost').identities.where({'category': 'store'}).length).toBe(1);
|
||||||
|
_converse.api.disco.supports(Strophe.NS.HTTPUPLOAD, _converse.domain).then(
|
||||||
|
function (result) {
|
||||||
|
console.log("in the test the service is supported");
|
||||||
|
expect(result.length).toBe(1);
|
||||||
|
expect(result[0].get('jid')).toBe('upload.localhost');
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("When supported", function () {
|
||||||
|
|
||||||
|
describe("A file upload toolbar button", function () {
|
||||||
|
|
||||||
|
it("appears in private chats", mock.initConverseWithAsync(function (done, _converse) {
|
||||||
|
test_utils.waitUntilDiscoConfirmed(
|
||||||
|
_converse, _converse.domain,
|
||||||
|
[{'category': 'server', 'type':'IM'}],
|
||||||
|
['http://jabber.org/protocol/disco#items'], [], 'info').then(function () {
|
||||||
|
|
||||||
|
test_utils.waitUntilDiscoConfirmed(_converse, _converse.domain, [], [], ['upload.localhost'], 'items').then(function () {
|
||||||
|
test_utils.waitUntilDiscoConfirmed(_converse, 'upload.localhost', [], [Strophe.NS.HTTPUPLOAD], []).then(function () {
|
||||||
|
test_utils.createContacts(_converse, 'current');
|
||||||
|
var contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||||
|
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||||
|
var view = _converse.chatboxviews.get(contact_jid);
|
||||||
|
test_utils.waitUntil(function () {
|
||||||
|
return view.el.querySelector('.upload-file');
|
||||||
|
}, 150).then(function () {
|
||||||
|
expect(view.el.querySelector('.chat-toolbar .upload-file')).not.toBe(null);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("appears in MUC chats", mock.initConverseWithAsync(function (done, _converse) {
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
@ -13,6 +13,7 @@
|
|||||||
"converse-dragresize": "builds/converse-dragresize",
|
"converse-dragresize": "builds/converse-dragresize",
|
||||||
"converse-fullscreen": "builds/converse-fullscreen",
|
"converse-fullscreen": "builds/converse-fullscreen",
|
||||||
"converse-headline": "builds/converse-headline",
|
"converse-headline": "builds/converse-headline",
|
||||||
|
"converse-http-file-upload":"builds/converse-http-file-upload",
|
||||||
"converse-mam": "builds/converse-mam",
|
"converse-mam": "builds/converse-mam",
|
||||||
"converse-minimize": "builds/converse-minimize",
|
"converse-minimize": "builds/converse-minimize",
|
||||||
"converse-modal": "builds/converse-modal",
|
"converse-modal": "builds/converse-modal",
|
||||||
|
@ -74,6 +74,7 @@ require.config({
|
|||||||
"converse-dragresize": "src/converse-dragresize",
|
"converse-dragresize": "src/converse-dragresize",
|
||||||
"converse-fullscreen": "src/converse-fullscreen",
|
"converse-fullscreen": "src/converse-fullscreen",
|
||||||
"converse-headline": "src/converse-headline",
|
"converse-headline": "src/converse-headline",
|
||||||
|
"converse-http-file-upload":"src/converse-http-file-upload",
|
||||||
"converse-mam": "src/converse-mam",
|
"converse-mam": "src/converse-mam",
|
||||||
"converse-minimize": "src/converse-minimize",
|
"converse-minimize": "src/converse-minimize",
|
||||||
"converse-modal": "src/converse-modal",
|
"converse-modal": "src/converse-modal",
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
}(this, function (converse, tpl_chatboxes) {
|
}(this, function (converse, tpl_chatboxes) {
|
||||||
"use strict";
|
"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', {
|
converse.plugins.add('converse-chatboxes', {
|
||||||
|
|
||||||
@ -50,7 +50,8 @@
|
|||||||
/* The initialize function gets called as soon as the plugin is
|
/* The initialize function gets called as soon as the plugin is
|
||||||
* loaded by converse.js's plugin machinery.
|
* loaded by converse.js's plugin machinery.
|
||||||
*/
|
*/
|
||||||
const { _converse } = this;
|
const { _converse } = this,
|
||||||
|
{ __ } = _converse;
|
||||||
|
|
||||||
_converse.api.promises.add([
|
_converse.api.promises.add([
|
||||||
'chatBoxesFetched',
|
'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) {
|
getMessageBody (message) {
|
||||||
const type = message.getAttribute('type');
|
const type = message.getAttribute('type');
|
||||||
return (type === 'error') ?
|
return (type === 'error') ?
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"tpl!spoiler_message",
|
"tpl!spoiler_message",
|
||||||
"tpl!status_message",
|
"tpl!status_message",
|
||||||
"tpl!toolbar",
|
"tpl!toolbar",
|
||||||
|
"converse-http-file-upload",
|
||||||
"converse-chatboxes"
|
"converse-chatboxes"
|
||||||
], factory);
|
], factory);
|
||||||
}(this, function (
|
}(this, function (
|
||||||
@ -50,7 +51,8 @@
|
|||||||
tpl_spoiler_button,
|
tpl_spoiler_button,
|
||||||
tpl_spoiler_message,
|
tpl_spoiler_message,
|
||||||
tpl_status_message,
|
tpl_status_message,
|
||||||
tpl_toolbar
|
tpl_toolbar,
|
||||||
|
filetransfer
|
||||||
) {
|
) {
|
||||||
"use strict";
|
"use strict";
|
||||||
const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
|
const { $msg, Backbone, Promise, Strophe, _, b64_sha1, f, sizzle, moment } = converse.env;
|
||||||
@ -237,7 +239,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
_converse.ChatBoxView = Backbone.NativeView.extend({
|
_converse.ChatBoxView = Backbone.NativeView.extend({
|
||||||
length: 200,
|
length: 200,
|
||||||
className: 'chatbox hidden',
|
className: 'chatbox hidden',
|
||||||
@ -649,7 +650,14 @@
|
|||||||
if (attrs.is_spoiler) {
|
if (attrs.is_spoiler) {
|
||||||
this.renderSpoilerMessage(msg, attrs)
|
this.renderSpoilerMessage(msg, attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
u.renderImageURLs(msg_content).then(this.scrollDown.bind(this));
|
||||||
|
}
|
||||||
return msg;
|
return msg;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -808,7 +816,7 @@
|
|||||||
return stanza;
|
return stanza;
|
||||||
},
|
},
|
||||||
|
|
||||||
sendMessage (message) {
|
sendMessage (message, file = null) {
|
||||||
/* Responsible for sending off a text message.
|
/* Responsible for sending off a text message.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
@ -816,7 +824,13 @@
|
|||||||
*/
|
*/
|
||||||
// TODO: We might want to send to specfic resources.
|
// TODO: We might want to send to specfic resources.
|
||||||
// Especially in the OTR case.
|
// 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);
|
_converse.connection.send(messageStanza);
|
||||||
if (_converse.forward_messages) {
|
if (_converse.forward_messages) {
|
||||||
// Forward the message, so that other connected resources are also aware of it.
|
// Forward the message, so that other connected resources are also aware of it.
|
||||||
@ -851,7 +865,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onMessageSubmitted (text, spoiler_hint) {
|
onMessageSubmitted (text, spoiler_hint, file = null) {
|
||||||
/* This method gets called once the user has typed a message
|
/* This method gets called once the user has typed a message
|
||||||
* and then pressed enter in a chat box.
|
* and then pressed enter in a chat box.
|
||||||
*
|
*
|
||||||
@ -870,9 +884,9 @@
|
|||||||
if (this.parseMessageForCommands(text)) {
|
if (this.parseMessageForCommands(text)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const attrs = this.getOutgoingMessageAttributes(text, spoiler_hint)
|
const attrs = this.getOutgoingMessageAttributes(text, spoiler_hint);
|
||||||
const message = this.model.messages.create(attrs);
|
const message = this.model.messages.create(attrs);
|
||||||
this.sendMessage(message);
|
this.sendMessage(message, file);
|
||||||
},
|
},
|
||||||
|
|
||||||
getOutgoingMessageAttributes (text, spoiler_hint) {
|
getOutgoingMessageAttributes (text, spoiler_hint) {
|
||||||
@ -1229,13 +1243,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
_converse.on('connected', () => {
|
_converse.on('connected', () => {
|
||||||
// Advertise that we support XEP-0382 Message Spoilers
|
// Advertise that we support XEP-0382 Message Spoilers
|
||||||
_converse.connection.disco.addFeature(Strophe.NS.SPOILER);
|
_converse.connection.disco.addFeature(Strophe.NS.SPOILER);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/************************ BEGIN API ************************/
|
/************************ BEGIN API ************************/
|
||||||
_.extend(_converse.api, {
|
_.extend(_converse.api, {
|
||||||
'chatviews': {
|
'chatviews': {
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
'converse-dropdown',
|
'converse-dropdown',
|
||||||
'converse-fullscreen',
|
'converse-fullscreen',
|
||||||
'converse-headline',
|
'converse-headline',
|
||||||
|
'converse-http-file-upload',
|
||||||
'converse-mam',
|
'converse-mam',
|
||||||
'converse-minimize',
|
'converse-minimize',
|
||||||
'converse-modal',
|
'converse-modal',
|
||||||
|
69
src/converse-http-file-upload.js
Normal file
69
src/converse-http-file-upload.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Adds Support for Http File Upload (XEP-0363)
|
||||||
|
*
|
||||||
|
* @see {@link http://xmpp.org/extensions/xep-0363.html}
|
||||||
|
*/
|
||||||
|
(function (root, factory) {
|
||||||
|
define([
|
||||||
|
"converse-core",
|
||||||
|
"tpl!toolbar_fileupload"
|
||||||
|
], factory);
|
||||||
|
}(this, function (
|
||||||
|
converse,
|
||||||
|
tpl_toolbar_fileupload
|
||||||
|
) {
|
||||||
|
"use strict";
|
||||||
|
const { $msg, Backbone, Strophe, _, b64_sha1, moment, utils } = converse.env;
|
||||||
|
Strophe.addNamespace('HTTPUPLOAD', 'urn:xmpp:http:upload');
|
||||||
|
|
||||||
|
converse.plugins.add('converse-http-file-upload', {
|
||||||
|
|
||||||
|
dependencies: ["converse-chatboxes", "converse-chatview", "converse-muc-views"],
|
||||||
|
|
||||||
|
overrides: {
|
||||||
|
ChatBoxView: {
|
||||||
|
events: {
|
||||||
|
'click .toggle-fileUpload': 'toggleFileUpload',
|
||||||
|
'change .fileUpload_input': 'handleFileSelect'
|
||||||
|
},
|
||||||
|
|
||||||
|
addFileUploadButton (options) {
|
||||||
|
const { __ } = this.__super__._converse;
|
||||||
|
this.el.querySelector('.chat-toolbar').insertAdjacentHTML(
|
||||||
|
'beforeend',
|
||||||
|
tpl_toolbar_fileupload({'label_upload_file': __('Choose a file to send')}));
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleFileUpload (ev) {
|
||||||
|
this.el.querySelector('.fileUpload_input').click();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleFileSelect (evt) {
|
||||||
|
var files = evt.target.files;
|
||||||
|
var file = files[0];
|
||||||
|
this.model.sendFile(file, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderToolbar (toolbar, options) {
|
||||||
|
const result = this.__super__.renderToolbar.apply(this, arguments);
|
||||||
|
this.addFileUploadButton();
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ChatRoomView: {
|
||||||
|
events: {
|
||||||
|
'click .toggle-fileUpload': 'toggleFileUpload',
|
||||||
|
'change .fileUpload_input': 'handleFileSelect'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize () {
|
||||||
|
const { _converse } = this,
|
||||||
|
{ __ } = _converse;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return converse;
|
||||||
|
}));
|
@ -826,13 +826,18 @@
|
|||||||
this.showErrorMessage(__("Error: could not execute the command"), true);
|
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
|
/* Gets called when the user presses enter to send off a
|
||||||
* message in a chat room.
|
* message in a chat room.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* (String) text - The message text.
|
* (String) text - The message text.
|
||||||
*/
|
*/
|
||||||
|
if (file !== null) {
|
||||||
|
return this.model.sendChatRoomFile(text,this.model.get('jid'));
|
||||||
|
}
|
||||||
if (_converse.muc_disable_moderator_commands) {
|
if (_converse.muc_disable_moderator_commands) {
|
||||||
return this.sendChatRoomMessage(text);
|
return this.sendChatRoomMessage(text);
|
||||||
}
|
}
|
||||||
|
@ -336,6 +336,18 @@
|
|||||||
return jid + (nick !== null ? `/${nick}` : "");
|
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) {
|
directInvite (recipient, reason) {
|
||||||
/* Send a direct invitation as per XEP-0249
|
/* Send a direct invitation as per XEP-0249
|
||||||
*
|
*
|
||||||
|
@ -24,6 +24,7 @@ if (typeof define !== 'undefined') {
|
|||||||
"converse-minimize", // Allows chat boxes to be minimized
|
"converse-minimize", // Allows chat boxes to be minimized
|
||||||
"converse-dragresize", // Allows chat boxes to be resized by dragging them
|
"converse-dragresize", // Allows chat boxes to be resized by dragging them
|
||||||
"converse-headline", // Support for headline messages
|
"converse-headline", // Support for headline messages
|
||||||
|
"converse-http-file-upload", // Support for XEP-0363
|
||||||
"converse-fullscreen"
|
"converse-fullscreen"
|
||||||
/* END: Removable components */
|
/* END: Removable components */
|
||||||
], function (converse) {
|
], function (converse) {
|
||||||
|
@ -25,6 +25,7 @@ if (typeof define !== 'undefined') {
|
|||||||
"converse-register", // XEP-0077 In-band registration
|
"converse-register", // XEP-0077 In-band registration
|
||||||
"converse-roomslist", // Show currently open chat rooms
|
"converse-roomslist", // Show currently open chat rooms
|
||||||
"converse-vcard", // XEP-0054 VCard-temp
|
"converse-vcard", // XEP-0054 VCard-temp
|
||||||
|
"converse-http-file-upload", // Support for XEP-0363
|
||||||
/* END: Removable components */
|
/* END: Removable components */
|
||||||
|
|
||||||
"converse-inverse", // Inverse plugin for converse.js
|
"converse-inverse", // Inverse plugin for converse.js
|
||||||
|
4
src/templates/toolbar_fileupload.html
Normal file
4
src/templates/toolbar_fileupload.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<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>
|
@ -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) {
|
u.slideInAllElements = function (elements, duration=300) {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
_.map(
|
_.map(
|
||||||
|
@ -24,6 +24,7 @@ config.paths["converse-core"] = "builds/converse-core";
|
|||||||
config.paths["converse-disco"] = "builds/converse-disco";
|
config.paths["converse-disco"] = "builds/converse-disco";
|
||||||
config.paths["converse-dragresize"] = "builds/converse-dragresize";
|
config.paths["converse-dragresize"] = "builds/converse-dragresize";
|
||||||
config.paths["converse-headline"] = "builds/converse-headline";
|
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-fullscreen"] = "builds/converse-fullscreen";
|
||||||
config.paths["converse-mam"] = "builds/converse-mam";
|
config.paths["converse-mam"] = "builds/converse-mam";
|
||||||
config.paths["converse-minimize"] = "builds/converse-minimize";
|
config.paths["converse-minimize"] = "builds/converse-minimize";
|
||||||
|
Loading…
Reference in New Issue
Block a user