diff options
author | sualko <github@spam.herberth.eu> | 2013-12-10 20:41:38 +0400 |
---|---|---|
committer | sualko <github@spam.herberth.eu> | 2013-12-10 20:41:38 +0400 |
commit | bb5569d03fcaf7069bc7f2555f693b26e3c4addc (patch) | |
tree | 6745398e2890983a9213b81aa94898515693367f | |
parent | 5eb22f0a3613b884e952fcc561402944a5eeb6f0 (diff) |
bump version
-rw-r--r-- | CHANGELOG.md | 18 | ||||
-rw-r--r-- | README.md | 107 | ||||
-rwxr-xr-x | appinfo/info.xml | 6 | ||||
-rwxr-xr-x | appinfo/version | 2 | ||||
-rw-r--r-- | build/appinfo/app.php | 2 | ||||
-rw-r--r-- | build/appinfo/info.xml | 6 | ||||
-rw-r--r-- | build/appinfo/version | 2 | ||||
-rw-r--r-- | build/css/main.css | 2 | ||||
-rw-r--r-- | build/css/webrtc.css | 3 | ||||
-rw-r--r-- | build/js/lib/jsxc.lib.js | 269 | ||||
-rw-r--r-- | build/js/lib/jsxc.lib.webrtc.js | 142 | ||||
-rw-r--r-- | build/js/ojsxc.js | 6 | ||||
-rw-r--r-- | css/webrtc.css | 3 | ||||
-rw-r--r-- | documentation/screenshot_1.png | bin | 0 -> 156755 bytes | |||
-rw-r--r-- | documentation/screenshot_2.png | bin | 0 -> 30489 bytes | |||
-rw-r--r-- | documentation/screenshot_3.png | bin | 0 -> 191292 bytes | |||
-rwxr-xr-x | js/lib/jsxc.lib.js | 2 | ||||
-rw-r--r-- | js/lib/jsxc.lib.webrtc.js | 126 | ||||
-rw-r--r-- | js/ojsxc.js | 6 |
19 files changed, 425 insertions, 277 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d281282..46c889d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +v0.4 / 2013-12-10 +=== +- display notification request only for incoming messages +- update ui if we lost the trust state +- display allow dialog +- fix chrome notification issue +- fix ringing dialog +- init grunt/jshint +- lot of code clean up and commenting +- set focus to password field +- display minimized roster if no connection is found +- porting to OC6 (replace fancybox with colorbox) +- add webrtc info dialog (ip, fingerprint) +- use git submodules for OTR and strophe.jingle +- update README + v0.3 / 2013-10-28 === - use lowercase jid @@ -7,4 +23,4 @@ v0.3 / 2013-10-28 - fix notification with multiple tabs - reorganize files - add MIT license -- minor fixes
\ No newline at end of file +- minor fixes @@ -1,13 +1,102 @@ -Owncloud JavaScript Xmpp Client -===== +# Owncloud JavaScript Xmpp Client -User notes --- +__Beware! This is a beta software.__ -Developer notes --- +## General -You need the following libraries in the "/js" directory: +_TODO insert short description_ -- https://github.com/sualko/otr -- https://github.com/ESTOS/strophe.jingle
\ No newline at end of file +### Features +- integration into existing ui +- one-to-one conversation (XMPP) +- encrypted one-to-one conversation (OTR) +.- use of whitespace tags to start a OTR session +- user verification (SMP) +- encrypted one-to-one video call (WebRTC) +.- [TURN REST API](http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00) +.- fullscreen mode +.- snapshots +- auto link-detection +- emotions +- roster management +- multi-language support (de, en) +- multi tab support + +### Supported protocols +- XMPP Core (RFC6120) +- XMPP IM (RFC6121) +- Bidirectional-streams Over Synchronous HTTP (XEP-0124) +- XMPP Over BOSH (XEP-0206) +- Service Discovery (XEP-0030) +- CAP (XEP-0127) +- Jingle (XEP-0166) +- Jingle RTP Sessions (XEP-0167) + +### Supported browsers +- Full support for __Chrome__ and __Firefox__. +- __IE__ doesn't support multi tabs, WebRTC and Notifications. +- __Safari__ doesn't support WebRTC and Notifications. + +### Planned features +- multi user chat +- video conference +- encrypted file transfer + +## User notes + +Please download the latest version from https://github.com/sualko/ojsxc/releases and copy the "build" folder to your app directory and rename it to "ojsxc". Now go into your app menu and enable the "JavaScript Xmpp Chat". + +### Configuration + +You can oJSXC in the admin panel of owncloud. + +<dl> + <dt>BOSH url</dt> + <dd>The url to your bosh server. Please beware of the SOP. Use the Apache ProxyRequest or modify the CSP.</dd> + + <dt>XMPP domain</dt> + <dd>The domain of your Jabber ID.</dd> + + <dt>XMPP resource</dt> + <dd>The resource of your JID. If you leaf this field blank a random resource is generated.</dd> + + <dt>TURN url</dt> + <dd>The url to your TURN server. You get a free account on http://numb.viagenie.ca</dd> + + <dt>TURN username</dt> + <dd>If no username is set, the TURN REST API is used.</dd> + + <dt>TURN credential</dt> + <dd>If no credential is set, the TURN REST API is used.</dd> + + <dt>TURN secret</dt> + <dd>Secret for TURN REST API.</dd> + + <dt>TURN ttl</dt> + <dd>Lifetime of credentials.</dd> +</dl> + +### Screenshots + +![Screenshot 1](https://raw.github.com/sualko/ojsxc/master/documentation/screenshot_1.png) +![Screenshot 2](https://raw.github.com/sualko/ojsxc/master/documentation/screenshot_2.png) +![Screenshot 3](https://raw.github.com/sualko/ojsxc/master/documentation/screenshot_3.png) + +## Developer notes + +Please execude the following commands to get a copy of the code: + +``` +git clone https://github.com/sualko/ojsxc/ +git submodule update --init +``` + +### Libaries +- jQuery (http://jquery.com/) +- Strophe.js (http://strophe.im/strophejs/) +- Strophe.js Plugins (https://github.com/strophe/strophejs-plugins) +- OTR (https://github.com/arlolra/otr) +- strophe.jingle (https://github.com/ESTOS/strophe.jingle) + +### Events +coming soon... diff --git a/appinfo/info.xml b/appinfo/info.xml index 4308c90..4f8ebd8 100755 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -3,8 +3,8 @@ <id>ojsxc</id> <name>JavaScript XMPP Chat</name> <description>XMPP Chat with OTR</description> - <version>0.1</version> - <licence>AGPL</licence> + <version>0.4</version> + <licence>MIT</licence> <author>Klaus Herberth</author> - <require>4</require> + <require>6</require> </info> diff --git a/appinfo/version b/appinfo/version index 49d5957..bd73f47 100755 --- a/appinfo/version +++ b/appinfo/version @@ -1 +1 @@ -0.1 +0.4 diff --git a/build/appinfo/app.php b/build/appinfo/app.php index db35529..4660319 100644 --- a/build/appinfo/app.php +++ b/build/appinfo/app.php @@ -31,7 +31,7 @@ OCP\Util::addScript ( 'ojsxc', 'otr/build/dep/eventemitter' ); OCP\Util::addScript ( 'ojsxc', 'otr/build/otr' ); OCP\Util::addScript ( 'ojsxc', 'lib/jsxc.lib' ); OCP\Util::addScript ( 'ojsxc', 'lib/jsxc.lib.webrtc' ); -OCP\Util::addScript ( 'ojsxc', 'lib/jsxc.lib.muc' ); +// OCP\Util::addScript ( 'ojsxc', 'lib/jsxc.lib.muc' ); OCP\Util::addScript ( 'ojsxc', 'ojsxc' ); diff --git a/build/appinfo/info.xml b/build/appinfo/info.xml index 4308c90..4f8ebd8 100644 --- a/build/appinfo/info.xml +++ b/build/appinfo/info.xml @@ -3,8 +3,8 @@ <id>ojsxc</id> <name>JavaScript XMPP Chat</name> <description>XMPP Chat with OTR</description> - <version>0.1</version> - <licence>AGPL</licence> + <version>0.4</version> + <licence>MIT</licence> <author>Klaus Herberth</author> - <require>4</require> + <require>6</require> </info> diff --git a/build/appinfo/version b/build/appinfo/version index 49d5957..bd73f47 100644 --- a/build/appinfo/version +++ b/build/appinfo/version @@ -1 +1 @@ -0.1 +0.4 diff --git a/build/css/main.css b/build/css/main.css index c667b8a..d02b510 100644 --- a/build/css/main.css +++ b/build/css/main.css @@ -474,7 +474,7 @@ div.jsxc_transfer.jsxc_enc.jsxc_trust{ #jsxc_alt{ text-align:right; - margin:10px; + margin:15px; opacity:0.5; font-style:italic; padding-top:5px; diff --git a/build/css/webrtc.css b/build/css/webrtc.css index 4cbc58a..50ef20b 100644 --- a/build/css/webrtc.css +++ b/build/css/webrtc.css @@ -73,6 +73,9 @@ div:fullscreen.jsxc_localvideo{ border: 1px solid white; } +.jsxc_multi > div{ + display:none; +} .jsxc_snapshotbar{ width:100%; display:none; diff --git a/build/js/lib/jsxc.lib.js b/build/js/lib/jsxc.lib.js index 0c7a51f..1727017 100644 --- a/build/js/lib/jsxc.lib.js +++ b/build/js/lib/jsxc.lib.js @@ -6,7 +6,7 @@ * * @file Mainscript of the javascript xmpp client * @author Klaus Herberth <klaus@jsxc.org> - * @version 0.3 + * @version 0.4 * @requires [1] {@link https://github.com/sualko/strophejs/|Strophe.js} * @requires [2] {@link https://github.com/arlolra/otr/|OTR} */ @@ -41,7 +41,7 @@ var jsxc; keepalive: null, /** list of otr objects */ - buddyList: [], + buddyList: {}, /** True if last activity was 10 min ago */ restore: false, @@ -165,8 +165,7 @@ var jsxc; jsxc.gui.showWaitAlert(jsxc.l.please_wait_until_we_logged_you_in); - jsxc.options.xmpp.jid = jsxc.options.loginForm.preJid($(jsxc.options.loginForm.jid) - .val()); + jsxc.options.xmpp.jid = jsxc.options.loginForm.preJid($(jsxc.options.loginForm.jid).val()); jsxc.options.xmpp.password = $(jsxc.options.loginForm.pass).val(); jsxc.triggeredFromForm = true; @@ -598,14 +597,7 @@ var jsxc; */ jsxc.gui = { /** Smilie token to file mapping */ - emotions: [ - [ ':-) :)', 'smile.png' ], [ ':-D :D', 'grin.png' ], [ ':-( :(', 'sad.png' ], - [ ';-) ;)', 'wink.png' ], [ ':-P :P', 'tonguesmile.png' ], [ '=-O', 'surprised.png' ], - [ ':kiss: :-*', 'kiss.png' ], [ '8-) :cool:', 'sunglassess.png' ], - [ ':\'-(', 'crysad.png' ], [ ':-/', 'doubt.png' ], [ 'O:-) O:)', 'angel.png' ], - [ ':-X :X', 'zip.png' ], [ '>:o', 'angry.png' ], [ ':yes:', 'thumbsup.png' ], - [ ':beer:', 'beer.png' ], [ ':devil:', 'devil.png' ], [ ':kissing:', 'kissing.png' ], - [ ':love:', 'love.png' ], [ ':zzz:', 'tired.png' ] ], + emotions: [ [ ':-) :)', 'smile.png' ], [ ':-D :D', 'grin.png' ], [ ':-( :(', 'sad.png' ], [ ';-) ;)', 'wink.png' ], [ ':-P :P', 'tonguesmile.png' ], [ '=-O', 'surprised.png' ], [ ':kiss: :-*', 'kiss.png' ], [ '8-) :cool:', 'sunglassess.png' ], [ ':\'-(', 'crysad.png' ], [ ':-/', 'doubt.png' ], [ 'O:-) O:)', 'angel.png' ], [ ':-X :X', 'zip.png' ], [ '>:o', 'angry.png' ], [ ':yes:', 'thumbsup.png' ], [ ':beer:', 'beer.png' ], [ ':devil:', 'devil.png' ], [ ':kissing:', 'kissing.png' ], [ ':love:', 'love.png' ], [ ':zzz:', 'tired.png' ] ], /** * Creates application skeleton. @@ -620,7 +612,7 @@ var jsxc; // prepare regexp for emotions $.each(jsxc.gui.emotions, function(i, val) { var reg = val[0].replace(/(\/|\||\*|\.|\+|\?|\^|\$|\(|\)|\[|\]|\{|\})/g, '\\$1'); - reg = '\\(' + reg.split(' ').join('\\)\\|\\(') + '\\)'; + reg = '(' + reg.split(' ').join(')|(') + ')'; jsxc.gui.emotions[i][2] = new RegExp(reg, 'g'); }); @@ -650,45 +642,40 @@ var jsxc; ri.data(data); // Add online status - ue.removeClass('jsxc_' + jsxc.CONST.STATUS.join(' jsxc_')) - .addClass('jsxc_' + jsxc.CONST.STATUS[data.status]); + ue.removeClass('jsxc_' + jsxc.CONST.STATUS.join(' jsxc_')).addClass('jsxc_' + jsxc.CONST.STATUS[data.status]); // Change name and add title - ue.find('.jsxc_name').text(data.name) - .attr('title', 'is ' + jsxc.CONST.STATUS[data.status]); + ue.find('.jsxc_name').text(data.name).attr('title', 'is ' + jsxc.CONST.STATUS[data.status]); // Update gui according to encryption state switch (data.msgstate) { case 0: - we.find('.jsxc_transfer').removeClass('jsxc_enc jsxc_fin') - .attr('title', jsxc.l.your_connection_is_unencrypted); + we.find('.jsxc_transfer').removeClass('jsxc_enc jsxc_fin').attr('title', jsxc.l.your_connection_is_unencrypted); we.find('.jsxc_settings .jsxc_verification').addClass('jsxc_disabled'); we.find('.jsxc_settings .jsxc_transfer').text(jsxc.l.start_private); break; case 1: - we.find('.jsxc_transfer').addClass('jsxc_enc') - .attr('title', jsxc.l.your_connection_is_encrypted); + we.find('.jsxc_transfer').addClass('jsxc_enc').attr('title', jsxc.l.your_connection_is_encrypted); we.find('.jsxc_settings .jsxc_verification').removeClass('jsxc_disabled'); we.find('.jsxc_settings .jsxc_transfer').text(jsxc.l.close_private); break; case 2: we.find('.jsxc_settings .jsxc_verification').addClass('jsxc_disabled'); - we.find('.jsxc_transfer').removeClass('jsxc_enc').addClass('jsxc_fin') - .attr('title', jsxc.l.your_buddy_closed_the_private_connection); + we.find('.jsxc_transfer').removeClass('jsxc_enc').addClass('jsxc_fin').attr('title', jsxc.l.your_buddy_closed_the_private_connection); we.find('.jsxc_settings .jsxc_transfer').text(jsxc.l.close_private); break; } // update gui according to verification state if (data.trust) { - we.find('.jsxc_transfer').addClass('jsxc_trust') - .attr('title', jsxc.l.your_buddy_is_verificated); + we.find('.jsxc_transfer').addClass('jsxc_trust').attr('title', jsxc.l.your_buddy_is_verificated); + } else { + we.find('.jsxc_transfer').removeClass('jsxc_trust').attr('title', ''); } // update gui according to subscription state if (data.sub && data.sub !== 'both') { - ri.addClass('jsxc_oneway').find('.jsxc_name') - .attr('title', jsxc.l.you_have_only_a_subscription_in_one_way); + ri.addClass('jsxc_oneway').find('.jsxc_name').attr('title', jsxc.l.you_have_only_a_subscription_in_one_way); } else { ri.removeClass('jsxc_oneway'); } @@ -785,7 +772,11 @@ var jsxc; $('#jsxc_facebox > div:gt(0)').hide(); $('#jsxc_facebox select').change(function() { $('#jsxc_facebox > div:gt(0)').hide(); - $('#jsxc_facebox > div:eq(' + $(this).prop('selectedIndex') + ')').slideDown(); + $('#jsxc_facebox > div:eq(' + $(this).prop('selectedIndex') + ')').slideDown({ + complete: function() { + jsxc.gui.dialog.resize(); + } + }); }); // Manual @@ -1005,7 +996,12 @@ var jsxc; }); if (confirm) { - $('#jsxc_dialog .creation').click(confirm); + $('#jsxc_dialog .creation').click(function() { + confirm.call(); + jsxc.gui.dialog.open(jsxc.gui.template.get('pleaseAccept'), { + noClose: true + }); + }); } if (dismiss) { @@ -1063,8 +1059,7 @@ var jsxc; */ add: function(cid) { var data = jsxc.storage.getUserItem('buddy_' + cid); - var bud = jsxc.gui.buddyTemplate.clone().attr('id', cid) - .attr('data-type', data.type || 'chat'); + var bud = jsxc.gui.buddyTemplate.clone().attr('id', cid).attr('data-type', data.type || 'chat'); jsxc.gui.roster.insert(cid, bud); @@ -1107,19 +1102,18 @@ var jsxc; // Insert buddy with no mutual friendship to the end var status = (data.sub === 'both') ? data.status : -1; - listElements - .each(function() { + listElements.each(function() { - var thisStatus = ($(this).data('sub') === 'both') ? $(this).data('status') : -1; + var thisStatus = ($(this).data('sub') === 'both') ? $(this).data('status') : -1; - if (($(this).data('name').toLowerCase() > data.name.toLowerCase() && thisStatus === status) || thisStatus < status) { + if (($(this).data('name').toLowerCase() > data.name.toLowerCase() && thisStatus === status) || thisStatus < status) { - $(this).before(li); - insert = true; + $(this).before(li); + insert = true; - return false; - } - }); + return false; + } + }); if (!insert) { li.appendTo('#jsxc_buddylist'); @@ -1260,11 +1254,9 @@ var jsxc; $('#jsxc_roster .slimScrollDiv').remove(); $('#jsxc_menu').remove(); - $('#jsxc_roster').append($(document.createElement('p')).text(jsxc.l.no_connection) - .append($(document.createElement('a')).attr('href', '#').text(jsxc.l.relogin) - .click(function() { - jsxc.gui.showLoginBox(); - }))); + $('#jsxc_roster').append($(document.createElement('p')).text(jsxc.l.no_connection).append($(document.createElement('a')).attr('href', '#').text(jsxc.l.relogin).click(function() { + jsxc.gui.showLoginBox(); + }))); } }; @@ -1326,6 +1318,13 @@ var jsxc; close: function() { jsxc.debug('close dialog'); $.colorbox.close(); + }, + + /** + * Resizes current dialog. + */ + resize: function() { + $.colorbox.resize(); } }; @@ -1347,8 +1346,7 @@ var jsxc; return jsxc.gui.getWindow(cid); } - var win = jsxc.gui.windowTemplate.clone().attr('id', 'jsxc_window_' + cid).hide() - .appendTo('#jsxc_windowList > ul').show('slow'); + var win = jsxc.gui.windowTemplate.clone().attr('id', 'jsxc_window_' + cid).hide().appendTo('#jsxc_windowList > ul').show('slow'); var data = jsxc.storage.getUserItem('buddy_' + cid); // Attach jid to window @@ -1537,7 +1535,7 @@ var jsxc; win.find('.jsxc_textinput').focus(); - win.trigger('show'); + win.trigger('show.window.jsxc'); }, /** @@ -1558,7 +1556,7 @@ var jsxc; */ _hide: function(cid) { $('#jsxc_window_' + cid + ' .jsxc_window').slideUp(); - jsxc.gui.getWindow(cid).trigger('hide'); + jsxc.gui.getWindow(cid).trigger('hide.window.jsxc'); }, /** @@ -1666,14 +1664,11 @@ var jsxc; return '<a href="' + href + '" target="_blank">' + url + '</a>'; }); - $ - .each(jsxc.gui.emotions, function(i, val) { - msg = msg - .replace(val[2], '<img alt="$1" title="$1" src="' + jsxc.options.root + '/img/emotions/' + val[1] + '"/>'); - }); + $.each(jsxc.gui.emotions, function(i, val) { + msg = msg.replace(val[2], '<img alt="$1" title="$1" src="' + jsxc.options.root + '/img/emotions/' + val[1] + '"/>'); + }); - $('#jsxc_window_' + cid + ' .jsxc_textarea') - .append("<div class='jsxc_chatmessage jsxc_" + direction + "'>" + msg + "</div>"); + $('#jsxc_window_' + cid + ' .jsxc_textarea').append("<div class='jsxc_chatmessage jsxc_" + direction + "'>" + msg + "</div>"); jsxc.gui.window.scrollDown(cid); @@ -1741,8 +1736,7 @@ var jsxc; // common placeholder var ph = { - my_priv_fingerprint: jsxc.storage.getUserItem('priv_fingerprint') ? jsxc.storage - .getUserItem('priv_fingerprint').replace(/(.{8})/g, '$1 ') : jsxc.l.no_available, + my_priv_fingerprint: jsxc.storage.getUserItem('priv_fingerprint') ? jsxc.storage.getUserItem('priv_fingerprint').replace(/(.{8})/g, '$1 ') : jsxc.l.no_available, my_jid: jsxc.storage.getItem('jid'), root: jsxc.options.root }; @@ -1751,13 +1745,11 @@ var jsxc; if (cid) { var data = jsxc.storage.getUserItem('buddy_' + cid); - $ - .extend(ph, { - cid_priv_fingerprint: data.fingerprint ? data.fingerprint - .replace(/(.{8})/g, '$1 ') : jsxc.l.no_available, - cid_jid: data.jid, - cid_name: data.name - }); + $.extend(ph, { + cid_priv_fingerprint: data.fingerprint ? data.fingerprint.replace(/(.{8})/g, '$1 ') : jsxc.l.no_available, + cid_jid: data.jid, + cid_name: data.name + }); } // placeholder depending on msg @@ -1794,7 +1786,7 @@ var jsxc; <option>%%Secret%%</option>\ </select>\ </div>\ - <div>\ + <div style="display:none">\ <p class=".jsxc_explanation">%%To_verify_the_fingerprint_%%</p>\ <p><strong>%%Your_fingerprint%%</strong><br />\ <span style="text-transform:uppercase">{{my_priv_fingerprint}}</span></p>\ @@ -1802,13 +1794,13 @@ var jsxc; <span style="text-transform:uppercase">{{cid_priv_fingerprint}}</span></p><br />\ <p class="jsxc_right"><a href="#" class="jsxc_close button">%%Close%%</a> <a href="#" class="button creation">%%Compared%%</a></p>\ </div>\ - <div>\ + <div style="display:none">\ <p class=".jsxc_explanation">%%To_authenticate_using_a_question_%%</p>\ <p><label for="jsxc_quest">%%Question%%:</label><input type="text" name="quest" id="jsxc_quest" /></p>\ <p><label for="jsxc_secret2">%%Secret%%:</label><input type="text" name="secret2" id="jsxc_secret2" /></p>\ <p class="jsxc_right"><a href="#" class="button jsxc_close">%%Close%%</a> <a href="#" class="button creation">%%Ask%%</a></p>\ </div>\ - <div>\ + <div style="display:none">\ <p class=".jsxc_explanation">%%To_authenticate_pick_a_secret_%%</p>\ <p><label for="jsxc_secret">%%Secret%%:</label><input type="text" name="secret" id="jsxc_secret" /></p>\ <p class="jsxc_right"><a href="#" class="button jsxc_close">%%Close%%</a> <a href="#" class="button creation">%%Compare%%</a></p>\ @@ -1905,7 +1897,8 @@ var jsxc; <p class="jsxc_right">\ <button class="button jsxc_cancel jsxc_close">%%Dismiss%%</button>\ <button class="button creation">%%Confirm%%</button>\ - </p>' + </p>', + pleaseAccept: '<p>%%Please_accept_%%</p>' }; /** @@ -2641,15 +2634,13 @@ var jsxc; if (typeof (variable) === 'object') { - $ - .each(variable, function(key, val) { - if (typeof (data[key]) === 'undefined') { - jsxc - .debug('Variable ' + key + ' doesn\'t exist in ' + variable + '. It was created.'); - } + $.each(variable, function(key, val) { + if (typeof (data[key]) === 'undefined') { + jsxc.debug('Variable ' + key + ' doesn\'t exist in ' + variable + '. It was created.'); + } - data[key] = val; - }); + data[key] = val; + }); } else { if (typeof (data[variable]) === 'undefined') { jsxc.debug('Variable ' + variable + ' doesn\'t exist. It was created.'); @@ -2908,9 +2899,7 @@ var jsxc; // reset timeout window.clearTimeout(jsxc.to); - jsxc.to = window - .setTimeout(jsxc.checkChief, ((key === 'alive') ? jsxc.options.timeout : jsxc.options.busyTimeout) + jsxc - .random(60)); + jsxc.to = window.setTimeout(jsxc.checkChief, ((key === 'alive') ? jsxc.options.timeout : jsxc.options.busyTimeout) + jsxc.random(60)); // only call the first time if (!jsxc.role_allocation) { @@ -2996,48 +2985,42 @@ var jsxc; jsxc.buddyList[cid] = new OTR(jsxc.options.otr); - jsxc.buddyList[cid] - .on('status', function(status) { - switch (status) { - case OTR.CONST.STATUS_SEND_QUERY: - jsxc.gui.window - .postMessage(cid, 'sys', jsxc.l.trying_to_start_private_conversation); - break; - case OTR.CONST.STATUS_AKE_SUCCESS: - jsxc.storage - .updateUserItem('buddy_' + cid, 'fingerprint', jsxc.buddyList[cid].their_priv_pk - .fingerprint()); - jsxc.storage.updateUserItem('buddy_' + cid, 'msgstate', 1); - jsxc.gui.window - .postMessage(cid, 'sys', (jsxc.buddyList[cid].trust ? jsxc.l.Verified : jsxc.l.Unverified) + ' ' + jsxc.l.private_conversation_started); - break; - case OTR.CONST.STATUS_END_OTR: - jsxc.storage.updateUserItem('buddy_' + cid, 'fingerprint', null); - - if (jsxc.buddyList[cid].msgstate === 0) { // we - // abort the private conversation - - jsxc.storage.updateUserItem('buddy_' + cid, 'msgstate', 0); - jsxc.gui.window - .postMessage(cid, 'sys', jsxc.l.private_conversation_aborted); - - } else { // the buddy abort the private conversation - - jsxc.storage.updateUserItem('buddy_' + cid, 'msgstate', 2); - jsxc.gui.window - .postMessage(cid, 'sys', jsxc.l.your_buddy_closed_the_private_conversation_you_should_do_the_same); - } - break; - case OTR.CONST.STATUS_SMP_HANDLE: - jsxc.keepBusyAlive(); - break; + jsxc.buddyList[cid].on('status', function(status) { + switch (status) { + case OTR.CONST.STATUS_SEND_QUERY: + jsxc.gui.window.postMessage(cid, 'sys', jsxc.l.trying_to_start_private_conversation); + break; + case OTR.CONST.STATUS_AKE_SUCCESS: + jsxc.storage.updateUserItem('buddy_' + cid, 'fingerprint', jsxc.buddyList[cid].their_priv_pk.fingerprint()); + jsxc.storage.updateUserItem('buddy_' + cid, 'msgstate', 1); + jsxc.gui.window.postMessage(cid, 'sys', (jsxc.buddyList[cid].trust ? jsxc.l.Verified : jsxc.l.Unverified) + ' ' + jsxc.l.private_conversation_started); + break; + case OTR.CONST.STATUS_END_OTR: + jsxc.storage.updateUserItem('buddy_' + cid, 'fingerprint', null); + + if (jsxc.buddyList[cid].msgstate === 0) { // we + // abort the private conversation + + jsxc.storage.updateUserItem('buddy_' + cid, 'msgstate', 0); + jsxc.gui.window.postMessage(cid, 'sys', jsxc.l.private_conversation_aborted); + + } else { // the buddy abort the private conversation + + jsxc.storage.updateUserItem('buddy_' + cid, 'msgstate', 2); + jsxc.gui.window.postMessage(cid, 'sys', jsxc.l.your_buddy_closed_the_private_conversation_you_should_do_the_same); } + break; + case OTR.CONST.STATUS_SMP_HANDLE: + jsxc.keepBusyAlive(); + break; + } - // for encryption and verification state - jsxc.gui.update(cid); - }); + // for encryption and verification state + jsxc.gui.update(cid); + }); - jsxc.buddyList[cid].on('smp', function(type, data) { + jsxc.buddyList[cid].on('smp', function(type, data, data2) { + console.log(type, data, data2); switch (type) { case 'question': // verification request received jsxc.otr.onSmpQuestion(cid, data); @@ -3046,10 +3029,12 @@ var jsxc; }); break; case 'trust': // verification completed - if (jsxc.buddyList[cid].trust) { - jsxc.otr.backup(cid); - jsxc.storage.updateUserItem('buddy_' + cid, 'trust', true); - jsxc.gui.update(cid); + jsxc.buddyList[cid].trust = data; + jsxc.storage.updateUserItem('buddy_' + cid, 'trust', data); + jsxc.otr.backup(cid); + jsxc.gui.update(cid); + + if (data) { jsxc.gui.window.postMessage(cid, 'sys', jsxc.l.conversation_is_now_verified); } else { jsxc.gui.window.postMessage(cid, 'sys', jsxc.l.verification_fails); @@ -3093,16 +3078,14 @@ var jsxc; $('#jsxc_facebox select').prop('selectedIndex', (data ? 2 : 3)).change(); $('#jsxc_facebox > div:eq(0)').hide(); + console.log(data); + if (data) { $('#jsxc_facebox > div:eq(2)').find('#jsxc_quest').val(data).prop('disabled', true); $('#jsxc_facebox > div:eq(2)').find('.creation').text('Answer'); - $('#jsxc_facebox > div:eq(2)') - .find('.jsxc_explanation') - .text(jsxc.l.your_buddy_is_attempting_to_determine_ + ' ' + jsxc.l.to_authenticate_to_your_buddy + jsxc.l.enter_the_answer_and_click_answer); + $('#jsxc_facebox > div:eq(2)').find('.jsxc_explanation').text(jsxc.l.your_buddy_is_attempting_to_determine_ + ' ' + jsxc.l.to_authenticate_to_your_buddy + jsxc.l.enter_the_answer_and_click_answer); } else { - $('#jsxc_facebox > div:eq(3)') - .find('.jsxc_explanation') - .text(jsxc.l.your_buddy_is_attempting_to_determine_ + ' ' + jsxc.l.to_authenticate_to_your_buddy + jsxc.l.enter_the_secret); + $('#jsxc_facebox > div:eq(3)').find('.jsxc_explanation').text(jsxc.l.your_buddy_is_attempting_to_determine_ + ' ' + jsxc.l.to_authenticate_to_your_buddy + jsxc.l.enter_the_secret); } $('#jsxc_facebox a[rel=close]').click(function() { @@ -3124,6 +3107,7 @@ var jsxc; */ sendSmpReq: function(cid, sec, quest) { jsxc.keepBusyAlive(); + console.log("Sec: ", sec); jsxc.buddyList[cid].smpSecret(sec, quest); }, @@ -3186,11 +3170,7 @@ var jsxc; } // all variables which should be saved - var savekey = [ - 'our_instance_tag', 'msgstate', 'authstate', 'fragment', 'their_y', 'their_old_y', - 'their_keyid', 'their_instance_tag', 'our_dh', 'our_old_dh', 'our_keyid', - 'sessKeys', 'storedMgs', 'oldMacKeys', 'trust', 'transmittedRS', 'ssid', - 'receivedPlaintext', 'authstate', 'send_interval' ]; + var savekey = [ 'our_instance_tag', 'msgstate', 'authstate', 'fragment', 'their_y', 'their_old_y', 'their_keyid', 'their_instance_tag', 'our_dh', 'our_old_dh', 'our_keyid', 'sessKeys', 'storedMgs', 'oldMacKeys', 'trust', 'transmittedRS', 'ssid', 'receivedPlaintext', 'authstate', 'send_interval' ]; var i; for (i = 0; i < savekey.length; i++) { @@ -3278,14 +3258,7 @@ var jsxc; // start worker worker.postMessage({ - imports: [ - jsxc.options.root + '/js/otr/vendor/salsa20.js', - jsxc.options.root + '/js/otr/vendor/bigint.js', - jsxc.options.root + '/js/otr/vendor/crypto.js', - jsxc.options.root + '/js/otr/vendor/eventemitter.js', - jsxc.options.root + '/js/otr/lib/const.js', - jsxc.options.root + '/js/otr/lib/helpers.js', - jsxc.options.root + '/js/otr/lib/dsa.js' ], + imports: [ jsxc.options.root + '/js/otr/vendor/salsa20.js', jsxc.options.root + '/js/otr/vendor/bigint.js', jsxc.options.root + '/js/otr/vendor/crypto.js', jsxc.options.root + '/js/otr/vendor/eventemitter.js', jsxc.options.root + '/js/otr/lib/const.js', jsxc.options.root + '/js/otr/lib/helpers.js', jsxc.options.root + '/js/otr/lib/dsa.js' ], seed: BigInt.getSeed() }); @@ -3415,6 +3388,10 @@ var jsxc; } window.Notification.permission = permission; + window.Notification.requestPermission = function(func) { + window.webkitNotifications.requestPermission(func); + }; + return true; } else if (Notification) { return true; @@ -3429,7 +3406,7 @@ var jsxc; */ prepareRequest: function() { - $(document).one('message.jsxc', function() { + $(document).one('postmessagein.jsxc', function() { jsxc.switchEvents({ 'notificationready.jsxc': function() { jsxc.gui.dialog.close(); @@ -3442,6 +3419,7 @@ var jsxc; jsxc.storage.setUserItem('notification', false); } }); + setTimeout(function() { jsxc.gui.showConfirmDialog(jsxc.translate("%%Should we notify you_%%"), function() { jsxc.notification.requestPermission(); @@ -3461,7 +3439,7 @@ var jsxc; window.Notification.permission = status; } - if (jsxc.Notification.hasPermission()) { + if (jsxc.notification.hasPermission()) { $(document).trigger('notificationready.jsxc'); } else { $(document).trigger('notificationfailure.jsxc'); @@ -3556,7 +3534,8 @@ var jsxc; Retry: 'Retry', clear_history: 'Clear history', New_message_from: 'New message from', - Should_we_notify_you_: 'Should we notify you about new messages in the future?' + Should_we_notify_you_: 'Should we notify you about new messages in the future?', + Please_accept_: 'Please click the "Allow" button at the top.' }, de: { please_wait_until_we_logged_you_in: 'Bitte warte bis wir dich eingeloggt haben.', diff --git a/build/js/lib/jsxc.lib.webrtc.js b/build/js/lib/jsxc.lib.webrtc.js index f369f14..41b86c1 100644 --- a/build/js/lib/jsxc.lib.webrtc.js +++ b/build/js/lib/jsxc.lib.webrtc.js @@ -4,46 +4,48 @@ * * @file WebRTC Plugin for the javascript xmpp client * @author Klaus Herberth - * @version 0.3 + * @version 0.4 */ /* jsxc, Strophe, SDPUtil, getUserMediaWithConstraints, setupRTC, jQuery */ var RTC = null, RTCPeerconnection = null; -jsxc.gui.template.incomingCall = '<h3>%%Incoming_call%%</h3>\n\ - <p>%%Do_you_want_to_accept_the_call_from%% %%cid_name%%?</p>\n\ - <p class="jsxc_right">\n\ - <a href="#" class="button jsxc_reject">%%Reject%%</a> <a href="#" class="button creation jsxc_accept">%%Accept%%</a>\n\ +jsxc.gui.template.incomingCall = '<h3>%%Incoming_call%%</h3>\ + <p>%%Do_you_want_to_accept_the_call_from%% {{cid_name}}?</p>\ + <p class="jsxc_right">\ + <a href="#" class="button jsxc_reject">%%Reject%%</a> <a href="#" class="button creation jsxc_accept">%%Accept%%</a>\ </p>'; -jsxc.gui.template.allowAccess = '<p>%%Please_allow_access_to_microphone_and_camera%%</p>'; - -jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ - <div class="jsxc_videoContainer">\n\ - <video class="jsxc_localvideo" autoplay></video>\n\ - <video class="jsxc_remotevideo" autoplay></video>\n\ - <div class="jsxc_status"></div>\n\ - </div>\n\ - <div class="jsxc_controlbar">\n\ - <button type="button" class="jsxc_hangUp">%%hang_up%%</button>\n\ - <input type="range" class="jsxc_volume" min="0.0" max="1.0" step="0.05" value="0.5" />\n\ - <div class="jsxc_buttongroup">\n\ - <button type="button" class="jsxc_snapshot">%%snapshot%%</button><button type="button" class="jsxc_snapshots">▼</button>\n\ - </div>\n\ - <!-- <button type="button" class="jsxc_mute_local">%%mute_my_audio%%</button>\n\ - <button type="button" class="jsxc_pause_local">%%pause_my_video%%</button> --> \n\ - <button type="button" class="jsxc_chat">%%chat%%</button>\n\ - <button type="button" class="jsxc_fullscreen">%%fullscreen%%</button>\n\ - <button type="button" class="jsxc_info">%%Info%%</button>\n\ - </div>\n\ - <div class="jsxc_snapshotbar">\n\ - <p>No pictures yet!</p>\n\ - </div>\n\ - <div class="jsxc_chatarea">\n\ - <ul></ul>\n\ - </div>\n\ - <div class="jsxc_infobar"></div>\n\ +jsxc.gui.template.allowMediaAccess = '<p>%%Please_allow_access_to_microphone_and_camera%%</p>'; + +jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\ + <div class="jsxc_videoContainer">\ + <video class="jsxc_localvideo" autoplay></video>\ + <video class="jsxc_remotevideo" autoplay></video>\ + <div class="jsxc_status"></div>\ + </div>\ + <div class="jsxc_controlbar">\ + <button type="button" class="jsxc_hangUp">%%hang_up%%</button>\ + <input type="range" class="jsxc_volume" min="0.0" max="1.0" step="0.05" value="0.5" />\ + <div class="jsxc_buttongroup">\ + <button type="button" class="jsxc_snapshot">%%snapshot%%</button><button type="button" class="jsxc_snapshots">▼</button>\ + </div>\ + <!-- <button type="button" class="jsxc_mute_local">%%mute_my_audio%%</button>\ + <button type="button" class="jsxc_pause_local">%%pause_my_video%%</button> --> \ + <button type="button" class="jsxc_chat">%%chat%%</button>\ + <button type="button" class="jsxc_fullscreen">%%fullscreen%%</button>\ + <button type="button" class="jsxc_info">%%Info%%</button>\ + </div>\ + <div class="jsxc_multi">\ + <div class="jsxc_snapshotbar">\ + <p>No pictures yet!</p>\ + </div>\n\ + <div class="jsxc_chatarea">\ + <ul></ul>\ + </div>\ + <div class="jsxc_infobar"></div>\ + </div>\ </div>'; (function($) { @@ -249,7 +251,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ */ setStatus: function(txt, d) { var status = $('.jsxc_webrtc .jsxc_status'); - var duration = d || 4000; + var duration = (typeof d === 'undefined' || d === null) ? 4000 : d; if (status.html()) { // attach old messages @@ -271,6 +273,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ clearTimeout(status.data('timeout')); if (duration === 0) { + console.log('return'); return; } @@ -322,12 +325,12 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ var i; for (i = 0; i < stream.getAudioTracks().length; i++) { - this.setStatus((stream.getAudioTracks().length > 0) ? 'Use remote audio device.' : 'No remote audio device'); + self.setStatus((stream.getAudioTracks().length > 0) ? 'Use local audio device.' : 'No local audio device.'); jsxc.debug('using audio device "' + stream.getAudioTracks()[i].label + '"'); } for (i = 0; i < stream.getVideoTracks().length; i++) { - this.setStatus((stream.getVideoTracks().length > 0) ? 'Use remote video device.' : 'No remote video device'); + self.setStatus((stream.getVideoTracks().length > 0) ? 'Use local video device.' : 'No local video device.'); jsxc.debug('using video device "' + stream.getVideoTracks()[i].label + '"'); } @@ -371,7 +374,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ jsxc.switchEvents({ 'mediaready.jingle': function(event, stream) { - this.setStatus('Accept call'); + self.setStatus('Accept call'); sess.localStream = stream; sess.peerconnection.addStream(stream); @@ -390,7 +393,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ return; } - var dialog = jsxc.gui.dialog.open(jsxc.gui.template.get('incomingCall', jid)); + var dialog = jsxc.gui.dialog.open(jsxc.gui.template.get('incomingCall', jsxc.jidToCid(jid))); dialog.find('.jsxc_accept').click(function() { self.reqUserMedia(); @@ -528,7 +531,14 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ } } - $('.jsxc_info').attr('title', jsxc.translate('%%Local IP%%: ') + sess.local_ip + '\n' + jsxc.translate('%%Remote IP%%: ') + sess.remote_ip + '\n' + jsxc.translate('%%Local Fingerprint%%: ') + sess.local_fp + '\n' + jsxc.translate('%%Remote Fingerprint%%: ') + sess.remote_fp); + var text = '<p>'; + text += '<b>' + jsxc.translate('%%Local IP%%: ') + '</b>' + sess.local_ip + '<br />'; + text += '<b>' + jsxc.translate('%%Remote IP%%: ') + '</b>' + sess.remote_ip + '<br />'; + text += '<b>' + jsxc.translate('%%Local Fingerprint%%: ') + '</b>' + sess.local_fp + '<br />'; + text += '<b>' + jsxc.translate('%%Remote Fingerprint%%: ') + '</b>' + sess.remote_fp; + text += '</p>'; + + $('#jsxc_dialog .jsxc_infobar').html(text); } }, @@ -584,7 +594,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ this.reqUserMedia(); }, - + /** * Hang up the current call. * @@ -593,10 +603,10 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ hangUp: function() { $(document).off('cleanup.dialog.jsxc'); - this.conn.jingle.terminate(); + jsxc.webrtc.conn.jingle.terminate(null); $(document).trigger('callterminated.jingle'); }, - + /** * Request video and audio from local user. * @@ -607,17 +617,19 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ $(document).trigger('mediaready.jingle', [ this.localStream ]); return; } - - jsxc.gui.dialog.open(jsxc.gui.template.get('allowAccess')); + + jsxc.gui.dialog.open(jsxc.gui.template.get('allowMediaAccess'), { + noClose: true + }); this.setStatus('please allow access to microphone and camera'); - + getUserMediaWithConstraints([ 'video', 'audio' ]); }, - + /** * Make a snapshot from a video stream and display it. * - * @memberOf + * @memberOf * @param video Video stream */ snapshot: function(video) { @@ -695,30 +707,44 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ RTC.attachMediaStream(rv, self.remoteStream); } + var toggleMulti = function(elem, open) { + $('#jsxc_dialog .jsxc_multi > div').not(elem).slideUp(); + + var opt = { + complete: jsxc.gui.dialog.resize + }; + + if (open) { + elem.slideDown(opt); + } else { + elem.slideToggle(opt); + } + }; + var win = jsxc.gui.window.open(jsxc.jidToCid(jid)); + var winId = win.attr('id'); $('#jsxc_dialog .jsxc_chatarea ul').append(win.detach()); - $(document).one('cleanup.dialog.jsxc', function() { - $('#jsxc_windowList > ul').prepend(win.detach()); - }); - $('#jsxc_dialog .jsxc_hangUp').click(function() { + $('#jsxc_windowList > ul').prepend($('#' + winId).detach()); jsxc.webrtc.hangUp(); }); $('#jsxc_dialog .jsxc_snapshot').click(function() { jsxc.webrtc.snapshot(rv); - $('#jsxc_dialog .jsxc_snapshots').click(); + toggleMulti($('#jsxc_dialog .jsxc_snapshotbar'), true); }); $('#jsxc_dialog .jsxc_snapshots').click(function() { - $('#jsxc_dialog .jsxc_chatarea').slideUp(); - $('#jsxc_dialog .jsxc_snapshotbar').slideToggle(); + toggleMulti($('#jsxc_dialog .jsxc_snapshotbar')); }); $('#jsxc_dialog .jsxc_chat').click(function() { - $('#jsxc_dialog .jsxc_snapshotbar').slideUp(); - $('#jsxc_dialog .jsxc_chatarea').slideToggle(); + toggleMulti($('#jsxc_dialog .jsxc_chatarea')); + }); + + $('#jsxc_dialog .jsxc_info').click(function() { + toggleMulti($('#jsxc_dialog .jsxc_infobar')); }); $('#jsxc_dialog .jsxc_fullscreen').click(function() { @@ -730,18 +756,18 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ }); $('#jsxc_dialog .jsxc_videoContainer').fullscreen(); - } + } }); $('#jsxc_dialog .jsxc_volume').change(function() { rv[0].volume = $(this).val(); }); - + $('#jsxc_dialog .jsxc_volume').dblclick(function() { $(this).val(0.5); }); }); - + jsxc.gui.dialog.open(jsxc.gui.template.get('videoWindow'), { noClose: true }); diff --git a/build/js/ojsxc.js b/build/js/ojsxc.js index 519ceff..bd38b06 100644 --- a/build/js/ojsxc.js +++ b/build/js/ojsxc.js @@ -3,7 +3,7 @@ * Released under the MIT license * * @author Klaus Herberth - * @version 0.3 + * @version 0.4 */ /* global jsxc, oc_appswebroots, OC, $ */ @@ -96,6 +96,10 @@ $(function() { turnCredentialsPath: OC.filePath('ojsxc', 'ajax', 'getturncredentials.php'), displayRosterMinimized: function() { return OC.currentUser != null; + }, + otr: { + SEND_WHITESPACE_TAG: true, + WHITESPACE_START_AKE: true } }); diff --git a/css/webrtc.css b/css/webrtc.css index 4cbc58a..50ef20b 100644 --- a/css/webrtc.css +++ b/css/webrtc.css @@ -73,6 +73,9 @@ div:fullscreen.jsxc_localvideo{ border: 1px solid white; } +.jsxc_multi > div{ + display:none; +} .jsxc_snapshotbar{ width:100%; display:none; diff --git a/documentation/screenshot_1.png b/documentation/screenshot_1.png Binary files differnew file mode 100644 index 0000000..6e1fead --- /dev/null +++ b/documentation/screenshot_1.png diff --git a/documentation/screenshot_2.png b/documentation/screenshot_2.png Binary files differnew file mode 100644 index 0000000..3790a6c --- /dev/null +++ b/documentation/screenshot_2.png diff --git a/documentation/screenshot_3.png b/documentation/screenshot_3.png Binary files differnew file mode 100644 index 0000000..d381676 --- /dev/null +++ b/documentation/screenshot_3.png diff --git a/js/lib/jsxc.lib.js b/js/lib/jsxc.lib.js index 4530bcf..1727017 100755 --- a/js/lib/jsxc.lib.js +++ b/js/lib/jsxc.lib.js @@ -6,7 +6,7 @@ * * @file Mainscript of the javascript xmpp client * @author Klaus Herberth <klaus@jsxc.org> - * @version 0.3 + * @version 0.4 * @requires [1] {@link https://github.com/sualko/strophejs/|Strophe.js} * @requires [2] {@link https://github.com/arlolra/otr/|OTR} */ diff --git a/js/lib/jsxc.lib.webrtc.js b/js/lib/jsxc.lib.webrtc.js index 192e4c7..41b86c1 100644 --- a/js/lib/jsxc.lib.webrtc.js +++ b/js/lib/jsxc.lib.webrtc.js @@ -4,46 +4,48 @@ * * @file WebRTC Plugin for the javascript xmpp client * @author Klaus Herberth - * @version 0.3 + * @version 0.4 */ /* jsxc, Strophe, SDPUtil, getUserMediaWithConstraints, setupRTC, jQuery */ var RTC = null, RTCPeerconnection = null; -jsxc.gui.template.incomingCall = '<h3>%%Incoming_call%%</h3>\n\ - <p>%%Do_you_want_to_accept_the_call_from%% {{cid_name}}?</p>\n\ - <p class="jsxc_right">\n\ - <a href="#" class="button jsxc_reject">%%Reject%%</a> <a href="#" class="button creation jsxc_accept">%%Accept%%</a>\n\ +jsxc.gui.template.incomingCall = '<h3>%%Incoming_call%%</h3>\ + <p>%%Do_you_want_to_accept_the_call_from%% {{cid_name}}?</p>\ + <p class="jsxc_right">\ + <a href="#" class="button jsxc_reject">%%Reject%%</a> <a href="#" class="button creation jsxc_accept">%%Accept%%</a>\ </p>'; jsxc.gui.template.allowMediaAccess = '<p>%%Please_allow_access_to_microphone_and_camera%%</p>'; -jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ - <div class="jsxc_videoContainer">\n\ - <video class="jsxc_localvideo" autoplay></video>\n\ - <video class="jsxc_remotevideo" autoplay></video>\n\ - <div class="jsxc_status"></div>\n\ - </div>\n\ - <div class="jsxc_controlbar">\n\ - <button type="button" class="jsxc_hangUp">%%hang_up%%</button>\n\ - <input type="range" class="jsxc_volume" min="0.0" max="1.0" step="0.05" value="0.5" />\n\ - <div class="jsxc_buttongroup">\n\ - <button type="button" class="jsxc_snapshot">%%snapshot%%</button><button type="button" class="jsxc_snapshots">▼</button>\n\ - </div>\n\ - <!-- <button type="button" class="jsxc_mute_local">%%mute_my_audio%%</button>\n\ - <button type="button" class="jsxc_pause_local">%%pause_my_video%%</button> --> \n\ - <button type="button" class="jsxc_chat">%%chat%%</button>\n\ - <button type="button" class="jsxc_fullscreen">%%fullscreen%%</button>\n\ - <button type="button" class="jsxc_info">%%Info%%</button>\n\ - </div>\n\ - <div class="jsxc_snapshotbar">\n\ - <p>No pictures yet!</p>\n\ - </div>\n\ - <div class="jsxc_chatarea">\n\ - <ul></ul>\n\ - </div>\n\ - <div class="jsxc_infobar"></div>\n\ +jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\ + <div class="jsxc_videoContainer">\ + <video class="jsxc_localvideo" autoplay></video>\ + <video class="jsxc_remotevideo" autoplay></video>\ + <div class="jsxc_status"></div>\ + </div>\ + <div class="jsxc_controlbar">\ + <button type="button" class="jsxc_hangUp">%%hang_up%%</button>\ + <input type="range" class="jsxc_volume" min="0.0" max="1.0" step="0.05" value="0.5" />\ + <div class="jsxc_buttongroup">\ + <button type="button" class="jsxc_snapshot">%%snapshot%%</button><button type="button" class="jsxc_snapshots">▼</button>\ + </div>\ + <!-- <button type="button" class="jsxc_mute_local">%%mute_my_audio%%</button>\ + <button type="button" class="jsxc_pause_local">%%pause_my_video%%</button> --> \ + <button type="button" class="jsxc_chat">%%chat%%</button>\ + <button type="button" class="jsxc_fullscreen">%%fullscreen%%</button>\ + <button type="button" class="jsxc_info">%%Info%%</button>\ + </div>\ + <div class="jsxc_multi">\ + <div class="jsxc_snapshotbar">\ + <p>No pictures yet!</p>\ + </div>\n\ + <div class="jsxc_chatarea">\ + <ul></ul>\ + </div>\ + <div class="jsxc_infobar"></div>\ + </div>\ </div>'; (function($) { @@ -249,7 +251,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ */ setStatus: function(txt, d) { var status = $('.jsxc_webrtc .jsxc_status'); - var duration = (typeof d === 'undefined' || d === null)? 4000: d; + var duration = (typeof d === 'undefined' || d === null) ? 4000 : d; if (status.html()) { // attach old messages @@ -270,7 +272,8 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ clearTimeout(status.data('timeout')); - if (duration === 0) { console.log('return'); + if (duration === 0) { + console.log('return'); return; } @@ -528,7 +531,14 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ } } - $('.jsxc_info').attr('title', jsxc.translate('%%Local IP%%: ') + sess.local_ip + '\n' + jsxc.translate('%%Remote IP%%: ') + sess.remote_ip + '\n' + jsxc.translate('%%Local Fingerprint%%: ') + sess.local_fp + '\n' + jsxc.translate('%%Remote Fingerprint%%: ') + sess.remote_fp); + var text = '<p>'; + text += '<b>' + jsxc.translate('%%Local IP%%: ') + '</b>' + sess.local_ip + '<br />'; + text += '<b>' + jsxc.translate('%%Remote IP%%: ') + '</b>' + sess.remote_ip + '<br />'; + text += '<b>' + jsxc.translate('%%Local Fingerprint%%: ') + '</b>' + sess.local_fp + '<br />'; + text += '<b>' + jsxc.translate('%%Remote Fingerprint%%: ') + '</b>' + sess.remote_fp; + text += '</p>'; + + $('#jsxc_dialog .jsxc_infobar').html(text); } }, @@ -584,7 +594,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ this.reqUserMedia(); }, - + /** * Hang up the current call. * @@ -596,7 +606,7 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ jsxc.webrtc.conn.jingle.terminate(null); $(document).trigger('callterminated.jingle'); }, - + /** * Request video and audio from local user. * @@ -607,19 +617,19 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ $(document).trigger('mediaready.jingle', [ this.localStream ]); return; } - + jsxc.gui.dialog.open(jsxc.gui.template.get('allowMediaAccess'), { noClose: true }); this.setStatus('please allow access to microphone and camera'); - + getUserMediaWithConstraints([ 'video', 'audio' ]); }, - + /** * Make a snapshot from a video stream and display it. * - * @memberOf + * @memberOf * @param video Video stream */ snapshot: function(video) { @@ -697,30 +707,44 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ RTC.attachMediaStream(rv, self.remoteStream); } + var toggleMulti = function(elem, open) { + $('#jsxc_dialog .jsxc_multi > div').not(elem).slideUp(); + + var opt = { + complete: jsxc.gui.dialog.resize + }; + + if (open) { + elem.slideDown(opt); + } else { + elem.slideToggle(opt); + } + }; + var win = jsxc.gui.window.open(jsxc.jidToCid(jid)); + var winId = win.attr('id'); $('#jsxc_dialog .jsxc_chatarea ul').append(win.detach()); - $(document).one('cleanup.dialog.jsxc', function() { - $('#jsxc_windowList > ul').prepend(win.detach()); - }); - $('#jsxc_dialog .jsxc_hangUp').click(function() { + $('#jsxc_windowList > ul').prepend($('#' + winId).detach()); jsxc.webrtc.hangUp(); }); $('#jsxc_dialog .jsxc_snapshot').click(function() { jsxc.webrtc.snapshot(rv); - $('#jsxc_dialog .jsxc_snapshots').click(); + toggleMulti($('#jsxc_dialog .jsxc_snapshotbar'), true); }); $('#jsxc_dialog .jsxc_snapshots').click(function() { - $('#jsxc_dialog .jsxc_chatarea').slideUp(); - $('#jsxc_dialog .jsxc_snapshotbar').slideToggle(); + toggleMulti($('#jsxc_dialog .jsxc_snapshotbar')); }); $('#jsxc_dialog .jsxc_chat').click(function() { - $('#jsxc_dialog .jsxc_snapshotbar').slideUp(); - $('#jsxc_dialog .jsxc_chatarea').slideToggle(); + toggleMulti($('#jsxc_dialog .jsxc_chatarea')); + }); + + $('#jsxc_dialog .jsxc_info').click(function() { + toggleMulti($('#jsxc_dialog .jsxc_infobar')); }); $('#jsxc_dialog .jsxc_fullscreen').click(function() { @@ -732,18 +756,18 @@ jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\n\ }); $('#jsxc_dialog .jsxc_videoContainer').fullscreen(); - } + } }); $('#jsxc_dialog .jsxc_volume').change(function() { rv[0].volume = $(this).val(); }); - + $('#jsxc_dialog .jsxc_volume').dblclick(function() { $(this).val(0.5); }); }); - + jsxc.gui.dialog.open(jsxc.gui.template.get('videoWindow'), { noClose: true }); diff --git a/js/ojsxc.js b/js/ojsxc.js index 519ceff..bd38b06 100644 --- a/js/ojsxc.js +++ b/js/ojsxc.js @@ -3,7 +3,7 @@ * Released under the MIT license * * @author Klaus Herberth - * @version 0.3 + * @version 0.4 */ /* global jsxc, oc_appswebroots, OC, $ */ @@ -96,6 +96,10 @@ $(function() { turnCredentialsPath: OC.filePath('ojsxc', 'ajax', 'getturncredentials.php'), displayRosterMinimized: function() { return OC.currentUser != null; + }, + otr: { + SEND_WHITESPACE_TAG: true, + WHITESPACE_START_AKE: true } }); |