Browse Source

Merge branch 'master' into plugins-refactor

JC Brand 10 years ago
parent
commit
334f095774

+ 8 - 1
.gitignore

@@ -15,7 +15,6 @@ analytics.js
 .sass-cache
 ruby
 bourbon
-Gemfile.lock
 
 Backbone.Overview
 tags
@@ -41,3 +40,11 @@ develop-eggs
 
 # OSX
 .DS_Store
+
+# Builds
+converse-no-locales-no-otr.js
+converse-no-locales-no-otr.min.js
+converse-no-otr.js
+converse-no-otr.min.js
+converse.nojquery.js
+converse.nojquery.min.js

+ 15 - 0
Gemfile.lock

@@ -0,0 +1,15 @@
+GEM
+  remote: https://rubygems.org/
+  specs:
+    bourbon (4.2.1)
+      sass (~> 3.4)
+      thor
+    sass (3.4.13)
+    thor (0.19.1)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  bourbon
+  sass (~> 3.3)

+ 3 - 3
Makefile

@@ -16,7 +16,7 @@ ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ./d
 # the i18n builder cannot share the environment and doctrees with the others
 I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ./docs/source
 
-.PHONY: all help clean html epub changes linkcheck gettext po pot po2json merge release css minjs build dev-ruby
+.PHONY: all help clean html epub changes linkcheck gettext po pot po2json merge release css minjs build
 
 help:
 	@echo "Please use \`make <target>' where <target> is one of the following:"
@@ -103,10 +103,10 @@ dev: stamp-bower stamp-bundler
 ########################################################################
 ## Builds
 
-css:: dev-ruby
+css:: stamp-bundler
 	$(SASS) -I .bundle/bin sass/converse.scss css/converse.css
 
-watch:: dev-ruby
+watch:: stamp-bundler
 	$(SASS) --watch -I .bundle/bin sass/converse.scss:css/converse.css
 
 jsmin:

+ 5 - 4
README.rst

@@ -26,15 +26,16 @@ It has the following features:
 * In-band registration `XEP 77 <http://xmpp.org/extensions/xep-0077.html>`_
 * Contact rosters and groups
 * Contact subscriptions
-* Accept or decline contact requests
 * Roster item exchange `XEP 144 <http://xmpp.org/extensions/tmp/xep-0144-1.1.html>`_
 * Chat statuses (online, busy, away, offline)
 * Custom status messages
+* Typing and state notifications `XEP 85 <http://xmpp.org/extensions/xep-0085.html>`_
 * Messages appear in all connnected chat clients `XEP 280 <http://xmpp.org/extensions/xep-0280.html>`_
-* Typing and chat state notifications `XEP 85 <http://xmpp.org/extensions/xep-0085.html>`_
-* Third person messages (/me )
-* Translated into 16 languages
+* Third person "/me" messages `XEP 245 <http://xmpp.org/extensions/xep-0245.html>`_
+* XMPP Ping `XEP 199 <http://xmpp.org/extensions/xep-0199.html>`_
+* Client state indication `XEP 352 <http://xmpp.org/extensions/xep-0352.html>`_
 * Off-the-record encryption
+* Translated into 16 languages
 
 -----------
 Screencasts

+ 1 - 1
bower.json

@@ -2,7 +2,7 @@
   "name": "converse.js",
   "description": "Web-based XMPP/Jabber chat client written in javascript",
   "version": "0.9.3",
-  "license": "MPL",
+  "license": "MPL-2.0",
   "devDependencies": {
     "jasmine": "https://github.com/jcbrand/jasmine.git#1_3_x",
     "otr": "0.2.12",

File diff suppressed because it is too large
+ 0 - 14555
builds/converse-no-locales-no-otr.js


File diff suppressed because it is too large
+ 0 - 203
builds/converse-no-locales-no-otr.min.js


File diff suppressed because it is too large
+ 0 - 14555
builds/converse-no-otr.js


File diff suppressed because it is too large
+ 0 - 203
builds/converse-no-otr.min.js


File diff suppressed because it is too large
+ 0 - 4221
builds/converse.nojquery.js


File diff suppressed because it is too large
+ 0 - 203
builds/converse.nojquery.min.js


+ 191 - 28
converse.js

@@ -156,6 +156,7 @@
         Strophe.addNamespace('REGISTER', 'jabber:iq:register');
         Strophe.addNamespace('ROSTERX', 'http://jabber.org/protocol/rosterx');
         Strophe.addNamespace('XFORM', 'jabber:x:data');
+        Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
 
         // Add Strophe Statuses
         var i = 0;
@@ -215,7 +216,36 @@
 
         // Translation machinery
         // ---------------------
-        this.i18n = settings.i18n ? settings.i18n : locales.en;
+        this.isAvailableLocale = function (locale) {
+            ret = null;
+            if (locales[locale]) {
+                ret = locales[locale];
+            } else{
+                sublocale=locale.split("-")[0];
+                if (sublocale!=locale && locales[sublocale]) {
+                    ret=locales[sublocale];
+                }
+            }
+            return ret;
+        };
+		
+        this.detectLocale = function () {
+            ret = null;
+            if (window.navigator.userLanguage) {
+                ret = this.isAvailableLocale(window.navigator.userLanguage);
+            } else if (window.navigator.languages && !ret) {
+                for (var i = 0; i < window.navigator.languages.length && !ret; i++) {
+                    ret = this.isAvailableLocale(window.navigator.languages[i]);
+                }
+            }
+            else if (window.navigator.browserLanguage && !ret) ret = this.isAvailableLocale(window.navigator.browserLanguage);
+            else if (window.navigator.language && !ret) ret = this.isAvailableLocale(window.navigator.language);
+            else if (window.navigator.systemLanguage && !ret) ret = this.isAvailableLocale(window.navigator.systemLanguage);
+            else { ret = locales.en; }
+            return ret;
+        };
+        this.i18n = settings.i18n ? settings.i18n : this.detectLocale();
+
         var __ = $.proxy(utils.__, this);
         var ___ = utils.___;
 
@@ -228,6 +258,8 @@
             allow_logout: true,
             allow_muc: true,
             allow_otr: true,
+            auto_away: 0, //in seconds
+            auto_xa: 0, //in seconds
             allow_registration: true,
             animate: true,
             auto_list_rooms: false,
@@ -247,6 +279,7 @@
             keepalive: false,
             message_carbons: false,
             no_trimming: false, // Set to true for phantomjs tests (where browser apparently has no width)
+            ping_interval: 180, //in seconds
             play_sounds: false,
             sounds_path: '/sounds/',
             password: undefined,
@@ -351,9 +384,60 @@
 
         // Module-level functions
         // ----------------------
+
+        this.sendCSI = function (stat) {
+            if (converse.features[Strophe.NS.CSI]) {
+                converse.connection.send($build(stat, {xmlns: Strophe.NS.CSI}));
+            }
+        };
+        this.autoAwayReset = function () {
+            if (converse._idleCounter > 0) {
+                converse._idleCounter = 0;
+                if (converse._autoAway > 0) {
+                    converse._autoAway = 0;
+                    converse.sendCSI(ACTIVE);
+                    converse.xmppstatus.setStatus('online');
+                }
+            }
+        };
+        this.registerAutoAwayHandler = function () {
+            // TODO: we should probably come up with a way to decouple CSI and auto-away
+            if (this.auto_away > 0 || this.auto_xa > 0) {
+                if (this.auto_xa > 0 && this.auto_xa < this.auto_away) {
+                    this.auto_xa = this.auto_away;
+                }
+                this._idleCounter = 0;
+                this._autoAway = 0;
+                $(window).on('click' , function () { converse.autoAwayReset(); });
+                $(window).on('mousemove' , function () { converse.autoAwayReset(); });
+                $(window).on('keypress' , function () { converse.autoAwayReset(); });
+                $(window).on('focus' , function () { converse.autoAwayReset(); });
+                $(window).on('beforeunload' , function () { converse.autoAwayReset(); });
+
+                window.setInterval(function () {
+                    if ((this._idleCounter <= this.auto_away || (this.auto_xa > 0 && this._idleCounter <= this.auto_xa)) &&
+                        (this.xmppstatus.get('status') == 'online' && this._autoAway === 0) || (this.xmppstatus.get('status') == 'away' && this._autoAway == 1) ){
+                        this._idleCounter++;
+                    }
+                    if (this.auto_away > 0 && this._autoAway != 1 && this._idleCounter > this.auto_away && this._idleCounter <= this.auto_xa){
+                        this.sendCSI(INACTIVE);
+                        this._autoAway = 1;
+                        this.xmppstatus.setStatus('away');
+                    }
+                    else if (this.auto_xa > 0 && this._autoAway != 2 && this._idleCounter > this.auto_xa){
+                        this.sendCSI(INACTIVE);
+                        this._autoAway = 2;
+                        this.xmppstatus.setStatus('xa');
+                    }
+                }.bind(this), 1000); //every seconds
+                return true;
+            }
+        };
+
+		
         this.playNotification = function () {
             var audio;
-            if (converse.play_sounds && typeof Audio !== "undefined"){
+            if (converse.play_sounds && typeof Audio !== "undefined") {
                 audio = new Audio(converse.sounds_path+"msg_received.ogg");
                 if (audio.canPlayType('/audio/ogg')) {
                     audio.play();
@@ -634,14 +718,69 @@
             },this), 200));
         };
 
+        this.ping = function (jid, success, error, timeout) {
+            // XXX: We could first check here if the server advertised that it supports PING.
+            // However, some servers don't advertise while still keeping the
+            // connection option due to pings.
+            //
+            // var feature = converse.features.findWhere({'var': Strophe.NS.PING});
+            converse.lastStanzaDate = new Date();
+            if (typeof jid === 'undefined' || jid === null) {
+                jid = Strophe.getDomainFromJid(converse.bare_jid);
+            }
+            if (typeof timeout === 'undefined' ) { timeout = null; }
+            if (typeof success === 'undefined' ) { success = null; }
+            if (typeof error === 'undefined' ) { error = null; }
+            if (converse.connection) {
+                converse.connection.ping.ping(jid, success, error, timeout);
+                return true;
+            }
+            return false;
+        };
+		
+        this.pong = function (ping) {
+            converse.lastStanzaDate = new Date();
+            converse.connection.ping.pong(ping);
+            return true;
+        };
+
+        this.registerPongHandler = function () {
+            converse.connection.disco.addFeature(Strophe.NS.PING);
+            converse.connection.ping.addPingHandler(this.pong);
+        };
+
+        this.registerPingHandler = function () {
+            this.registerPongHandler();
+            if (this.ping_interval > 0) {
+                this.connection.addHandler(function () {
+                    /* Handler on each stanza, saves the received date
+                     * in order to ping only when needed.
+                     */
+                    this.lastStanzaDate = new Date();
+                    return true;
+                }.bind(converse));
+                this.connection.addTimedHandler(1000, function () {
+                    now = new Date();
+                    if (!this.lastStanzaDate) {
+                        this.lastStanzaDate = now;
+                    }
+                    if ((now - this.lastStanzaDate)/1000 > this.ping_interval) {
+                        return this.ping();
+                    }
+                    return true;
+                });
+            }
+        };
+
         this.onReconnected = function () {
             // We need to re-register all the event handlers on the newly
             // created connection.
             this.initStatus($.proxy(function () {
-                this.registerRosterXHandler();
-                this.registerPresenceHandler();
+                this.registerPingHandler();
+                this.rosterview.registerRosterXHandler();
+                this.rosterview.registerPresenceHandler();
                 this.chatboxes.registerMessageHandler();
-                converse.xmppstatus.sendPresence();
+                this.xmppstatus.sendPresence();
                 this.giveFeedback(__('Contacts'));
             }, this));
         };
@@ -683,7 +822,8 @@
             this.features = new this.Features();
             this.enableCarbons();
             this.initStatus($.proxy(function () {
-
+                this.registerPingHandler();
+                this.registerAutoAwayHandler();				
                 this.chatboxes.onConnected();
                 this.giveFeedback(__('Contacts'));
                 if (this.callback) {
@@ -1004,7 +1144,7 @@
                 'mousedown .dragresize-tm': 'onDragResizeStart'
             },
 
-            initialize: function (){
+            initialize: function () {
                 this.model.messages.on('add', this.onMessageAdded, this);
                 this.model.on('show', this.show, this);
                 this.model.on('destroy', this.hide, this);
@@ -1486,8 +1626,13 @@
             },
 
             maximize: function () {
+                var chatboxviews = converse.chatboxviews;
                 // Restores a minimized chat box
-                this.$el.insertAfter(converse.chatboxviews.get("controlbox").$el).show('fast', $.proxy(function () {
+                this.$el.insertAfter(chatboxviews.get("controlbox").$el).show('fast', $.proxy(function () {
+                    /* Now that the chat box is visible, we can call trimChats
+                     * to make space available if need be.
+                     */
+                    chatboxviews.trimChats(this);
                     converse.refreshWebkit();
                     this.setChatState(ACTIVE).focus();
                     converse.emit('chatBoxMaximized', this);
@@ -1530,11 +1675,11 @@
                 var msgs = [];
                 if (data.otr_status == UNENCRYPTED) {
                     msgs.push(__("Your messages are not encrypted anymore"));
-                } else if (data.otr_status == UNVERIFIED){
+                } else if (data.otr_status == UNVERIFIED) {
                     msgs.push(__("Your messages are now encrypted but your contact's identity has not been verified."));
-                } else if (data.otr_status == VERIFIED){
+                } else if (data.otr_status == VERIFIED) {
                     msgs.push(__("Your contact's identify has been verified."));
-                } else if (data.otr_status == FINISHED){
+                } else if (data.otr_status == FINISHED) {
                     msgs.push(__("Your contact has ended encryption on their end, you should do the same."));
                 }
                 return this.showHelpMessages(msgs, 'info', false);
@@ -1545,11 +1690,11 @@
                     var data = this.model.toJSON();
                     if (data.otr_status == UNENCRYPTED) {
                         data.otr_tooltip = __('Your messages are not encrypted. Click here to enable OTR encryption.');
-                    } else if (data.otr_status == UNVERIFIED){
+                    } else if (data.otr_status == UNVERIFIED) {
                         data.otr_tooltip = __('Your messages are encrypted, but your contact has not been verified.');
-                    } else if (data.otr_status == VERIFIED){
+                    } else if (data.otr_status == VERIFIED) {
                         data.otr_tooltip = __('Your messages are encrypted and your contact verified.');
-                    } else if (data.otr_status == FINISHED){
+                    } else if (data.otr_status == FINISHED) {
                         data.otr_tooltip = __('Your contact has closed their end of the private session, you should do the same');
                     }
                     this.$el.find('.chat-toolbar').html(
@@ -2329,6 +2474,7 @@
                 'click .toggle-smiley': 'toggleEmoticonMenu',
                 'click .toggle-smiley ul li': 'insertEmoticon',
                 'click .toggle-clear': 'clearChatRoomMessages',
+                'click .toggle-call': 'toggleCall',
                 'click .toggle-participants a': 'toggleOccupants',
                 'keypress textarea.chat-textarea': 'keyPressed',
                 'mousedown .dragresize-tm': 'onDragResizeStart'
@@ -2398,7 +2544,7 @@
                 this.toggleOccupants();
                 return this;
             },
-
+			
             toggleOccupants: function (ev) {
                 if (ev) {
                     ev.preventDefault();
@@ -3018,6 +3164,11 @@
                 this.fetch({
                     add: true,
                     success: $.proxy(function (collection, resp) {
+                        collection.each(function (chatbox) {
+                            if (chatbox.get('id') !== 'controlbox' && !chatbox.get('minimized')) {
+                                chatbox.trigger('show');
+                            }
+                        });
                         if (!_.include(_.pluck(resp, 'id'), 'controlbox')) {
                             this.add({
                                 id: 'controlbox',
@@ -3171,10 +3322,13 @@
             initialize: function () {
                 this.model.on("add", this.onChatBoxAdded, this);
                 this.model.on("change:minimized", function (item) {
-                    if (item.get('minimized') === false) {
-                         this.trimChats(this.get(item.get('id')));
+                    if (item.get('minimized') === true) {
+                        /* When a chat is minimized in trimChats, trimChats needs to be
+                        * called again (in case the minimized chats toggle is newly shown).
+                        */
+                        this.trimChats();
                     } else {
-                         this.trimChats();
+                        this.trimChats(this.get(item.get('id')));
                     }
                 }, this);
             },
@@ -3247,7 +3401,7 @@
                     }
                 });
 
-                if ((minimized_width + boxes_width + controlbox_width) > this.$el.outerWidth(true)) {
+                if ((minimized_width + boxes_width + controlbox_width) > $('body').outerWidth(true)) {
                     oldest_chat = this.getOldestMaximizedChat();
                     if (oldest_chat && oldest_chat.get('id') !== new_id) {
                         oldest_chat.minimize();
@@ -3270,17 +3424,19 @@
             },
 
             closeAllChatBoxes: function (include_controlbox) {
-                var i, chatbox;
                 // TODO: once Backbone.Overview has been refactored, we should
                 // be able to call .each on the views themselves.
-                this.model.each($.proxy(function (model) {
+                var ids = [];
+                this.model.each(function (model) {
                     var id = model.get('id');
                     if (include_controlbox || id !== 'controlbox') {
-                        if (this.get(id)) { // Should always resolve, but shit happens
-                            this.get(id).close();
-                        }
+                        ids.push(id);
                     }
-                }, this));
+                });
+                ids.forEach(function(id) {
+                    var chatbox = this.get(id);
+                    if (chatbox) { chatbox.close(); }
+                }, this);
                 return this;
             },
 
@@ -4687,7 +4843,7 @@
                 this.save({'status': value});
             },
 
-            getStatus: function() {
+            getStatus: function () {
                 return this.get('status') || 'online';
             },
 
@@ -4741,7 +4897,7 @@
                             'desc_change_status': __('Click to change your chat status')
                             }));
                 // iterate through all the <option> elements and add option values
-                options.each(function (){
+                options.each(function () {
                     options_list.push(converse.templates.status_option({
                         'value': $(this).val(),
                         'text': this.text
@@ -4798,6 +4954,8 @@
                     pretty_status = __('away for long');
                 } else if (stat === 'away') {
                     pretty_status = __('away');
+                } else if (stat === 'offline') {
+                    pretty_status = __('offline');
                 } else {
                     pretty_status = __(stat) || __('online');
                 }
@@ -4888,8 +5046,10 @@
                     return;
                 }
                 $stanza.find('feature').each($.proxy(function (idx, feature) {
+                    var namespace = $(feature).attr('var');
+                    this[namespace] = true;
                     this.create({
-                        'var': $(feature).attr('var'),
+                        'var': namespace,
                         'from': $stanza.attr('from')
                     });
                 }, this));
@@ -5853,6 +6013,9 @@
         'send': function (stanza) {
             converse.connection.send(stanza);
         },
+        'ping': function (jid) {
+            converse.ping(jid);
+        },
         'plugins': {
             'add': function (name, plugin) {
                 converse.plugins[name] = plugin;

+ 8 - 5
css/converse.css

@@ -32,11 +32,12 @@
   bottom: 0;
   direction: ltr;
   height: 35px;
-  left: 0;
+  left: auto;
   position: fixed;
-  right: 0;
+  right: 15px;
   z-index: 30;
   display: block;
+  width: auto;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
@@ -286,7 +287,8 @@
     content: "\2369"; }
   #conversejs .icon-wrench:before {
     content: "\e024"; }
-  #conversejs .icon-xa:before,
+  #conversejs .icon-xa:before {
+    content: "\e602"; }
   #conversejs .icon-unavailable:before,
   #conversejs .icon-offline:before {
     content: "\e002"; }
@@ -762,7 +764,8 @@
     display: block;
     margin-left: 5px; }
   #conversejs div.room-info {
-    clear: left; }
+    clear: left;
+    width: 100%; }
   #conversejs p.room-info {
     margin: 0;
     padding: 0;
@@ -793,7 +796,7 @@
     #conversejs dd.available-chatroom:hover {
       background-color: #E3C9C1; }
       #conversejs dd.available-chatroom:hover .room-info {
-        display: inline-block;
+        display: block;
         font-size: 14px; }
   #conversejs #converse-roster dd {
     border: none;

File diff suppressed because it is too large
+ 0 - 0
css/converse.css.map


File diff suppressed because it is too large
+ 0 - 0
css/converse.min.css


+ 0 - 1
dev.html

@@ -53,7 +53,6 @@
     require(['converse'], function (converse) {
         converse.initialize({
             bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
-            i18n: locales['en'], // Refer to ./locale/locales.js to see which locales are supported
             keepalive: true,
             message_carbons: true,
             play_sounds: true,

+ 12 - 3
docs/CHANGES.rst

@@ -4,12 +4,21 @@ Changelog
 0.9.4 (Unreleased)
 ------------------
 
-* Refactored in order to remove the strophe.roster.js dependency. [jcbrand]
+* #144 Add Ping funcionnality and Pong Handler [thierrytiti]
+* #389 Allow login panel placeholders and roster item 'Name' translations. [gbonvehi]
+* #415 closeAllChatBoxes is giving ReferenceError when 2 chats are open [nevcos, jcbrand]
+* Add automatic Away mode and XEP-0352 support [thierrytiti]
+* Add icon for XA status [thierrytiti]
+* Allow offline pretty status and placeholder for "Insert a smiley" to be translated [thierrytiti]
 * Bugfix. Manual login doesn't work when only websocket_url is set and not bosh_service_url. [jcbrand]
 * Bugfix. clearSessions during unload event would throw an error when not logged in. [gbonvehi]
 * Bugfix. wrong callback argument mapping in XmppStatus initialize: fullname is null [thierrytiti]
-* #389 Allow login panel placeholders and roster item 'Name' translations. [gbonvehi]
-* Add placeholder for "Insert a smiley" translation [thierrytiti]
+* CSS fix: position and width of the div #conversejs [thierrytiti]
+* CSS fix: room-info bug on hover after room description loaded [thierrytiti]
+* CSS: Fonts Path: editabable $font-path via sass/variables.scss [thierrytiti]
+* I18N: Autodetection of User Locale if no i18n setting is set. [thierrytiti]
+* MUC: missing toggle call handler and updated documentation about call. [thierrytiti]
+* Refactored in order to remove the strophe.roster.js dependency. [jcbrand]
 * Updated French translation [thierrytiti]
 
 0.9.3 (2015-05-01)

+ 36 - 1
docs/source/configuration.rst

@@ -175,6 +175,27 @@ It should be used either with ``authentication`` set to ``anonymous`` or to
 If ``authentication`` is set to ``login``, then you will also need to provide a
 valid ``jid`` and ``password`` values.
 
+auto_away
+---------
+
+* Default:  ``0``
+
+This option can be used to let converse.js automatically change user presence
+
+This set the number a seconds before user presence become ``away``
+If the value if negative or ``0``, the function is disabled.
+
+auto_xa
+-------
+
+* Default:  ``0``
+
+This option can be used to let converse.js automatically change user presence
+
+This set the number a seconds before user presence become ``xa`` (eXtended Away)
+The value must be greater than ``auto_away``
+If the value if negative or ``0``, the function is disabled.
+
 auto_reconnect
 --------------
 
@@ -360,11 +381,25 @@ If set to ``true``, then don't show offline users.
 i18n
 ----
 
+* Default:  Auto-detection of the User/Browser language
+
+If no locale is matching available locales, the default is ``en``.
 Specify the locale/language. The language must be in the ``locales`` object. Refer to
 ``./locale/locales.js`` to see which locales are supported.
 
 .. _`play-sounds`:
 
+ping_interval
+-------------
+
+* Default:  ``300``
+
+Make ping to server in order to keep connection with server killing sessions after idle timeout.
+The ping are sent only if no messages are sent in the last ``ping_interval`` seconds
+You need to set the value to any positive value to enable this functionality.
+
+If you set this value to ``0`` or any negative value, il will disable this functionality.
+
 play_sounds
 -----------
 
@@ -525,7 +560,7 @@ Allows you to show or hide buttons on the chat boxes' toolbars.
     Provides a button with a picture of a telephone on it.
     When the call button is pressed, it will emit an event that can be used by a third-party library to initiate a call.::
 
-        converse.on('callButtonClicked', function(event, data) {
+        converse.listen.on('callButtonClicked', function(event, data) {
             console.log('Strophe connection is', data.connection);
             console.log('Bare buddy JID is', data.model.get('jid'));
             // ... Third-party library code ...

+ 1 - 3
fonticons/demo-files/demo.css

@@ -108,9 +108,6 @@ p {
 .pvs, .pts {
 	padding-top: .25em;
 }
-.clearfix {
-	zoom: 1;
-}
 .unit {
 	float: left;
 }
@@ -141,6 +138,7 @@ p {
 	height: 1.5em;
 }
 #testDrive {
+	display: block;
 	padding-top: 24px;
 	line-height: 1.5;
 }

File diff suppressed because it is too large
+ 475 - 187
fonticons/demo.html


BIN
fonticons/fonts/icomoon.eot


File diff suppressed because it is too large
+ 0 - 0
fonticons/fonts/icomoon.svg


BIN
fonticons/fonts/icomoon.ttf


BIN
fonticons/fonts/icomoon.woff


File diff suppressed because it is too large
+ 3 - 0
fonticons/selection.json


+ 99 - 96
fonticons/style.css

@@ -1,10 +1,10 @@
 @font-face {
 	font-family: 'icomoon';
-	src:url('fonts/icomoon.eot?-mnoxh0');
-	src:url('fonts/icomoon.eot?#iefix-mnoxh0') format('embedded-opentype'),
-		url('fonts/icomoon.woff?-mnoxh0') format('woff'),
-		url('fonts/icomoon.ttf?-mnoxh0') format('truetype'),
-		url('fonts/icomoon.svg?-mnoxh0#icomoon') format('svg');
+	src:url('fonts/icomoon.eot?dvaucx');
+	src:url('fonts/icomoon.eot?#iefixdvaucx') format('embedded-opentype'),
+		url('fonts/icomoon.ttf?dvaucx') format('truetype'),
+		url('fonts/icomoon.woff?dvaucx') format('woff'),
+		url('fonts/icomoon.svg?dvaucx#icomoon') format('svg');
 	font-weight: normal;
 	font-style: normal;
 }
@@ -23,276 +23,279 @@
 	-moz-osx-font-smoothing: grayscale;
 }
 
-#conversejs .icon-conversejs:before {
+.icon-xa:before {
+	content: "\e602";
+}
+.icon-conversejs:before {
 	content: "\e600";
 }
-#conversejs .icon-closed:before {
+.icon-closed:before {
 	content: "\25ba";
 }
-#conversejs .icon-opened:before {
+.icon-opened:before {
 	content: "\25bc";
 }
-#conversejs .icon-checkmark:before {
+.icon-checkmark:before {
 	content: "\2713";
 }
-#conversejs .icon-home:before {
+.icon-home:before {
 	content: "\e000";
 }
-#conversejs .icon-pencil:before {
+.icon-pencil:before {
 	content: "\270e";
 }
-#conversejs .icon-camera:before {
+.icon-camera:before {
 	content: "\e003";
 }
-#conversejs .icon-camera-2:before {
+.icon-camera-2:before {
 	content: "\2616";
 }
-#conversejs .icon-play:before {
+.icon-play:before {
 	content: "\25d9";
 }
-#conversejs .icon-music:before {
+.icon-music:before {
 	content: "\266b";
 }
-#conversejs .icon-headphones:before {
+.icon-headphones:before {
 	content: "\266c";
 }
-#conversejs .icon-phone:before {
+.icon-phone:before {
 	content: "\260f";
 }
-#conversejs .icon-phone-hang-up:before {
+.icon-phone-hang-up:before {
 	content: "\260e";
 }
-#conversejs .icon-address-book:before {
+.icon-address-book:before {
 	content: "\270f";
 }
-#conversejs .icon-notebook:before {
+.icon-notebook:before {
 	content: "\2710";
 }
-#conversejs .icon-envelop:before {
+.icon-envelop:before {
 	content: "\2709";
 }
-#conversejs .icon-pushpin:before {
+.icon-pushpin:before {
 	content: "\e012";
 }
-#conversejs .icon-online:before {
+.icon-online:before {
 	content: "\25fc";
 }
-#conversejs .icon-away:before {
+.icon-away:before {
 	content: "\25fb";
 }
-#conversejs .icon-bubbles:before {
+.icon-bubbles:before {
 	content: "\e015";
 }
-#conversejs .icon-bubbles2:before {
+.icon-bubbles2:before {
 	content: "\e016";
 }
-#conversejs .icon-bubbles3:before {
+.icon-bubbles3:before {
 	content: "\e017";
 }
-#conversejs .icon-user:before {
+.icon-user:before {
 	content: "\e01a";
 }
-#conversejs .icon-hide-users:before {
+.icon-hide-users:before {
 	content: "\e01c";
 }
-#conversejs .icon-show-users:before {
+.icon-show-users:before {
 	content: "\e01e";
 }
-#conversejs .icon-users:before {
+.icon-users:before {
 	content: "\e01b";
 }
-#conversejs .icon-quotes-left:before {
+.icon-quotes-left:before {
 	content: "\e01d";
 }
-#conversejs .icon-spinner:before {
+.icon-spinner:before {
 	content: "\231b";
 }
-#conversejs .icon-search:before {
+.icon-search:before {
 	content: "\e021";
 }
-#conversejs .icon-cogs:before {
+.icon-cogs:before {
 	content: "\e022";
 }
-#conversejs .icon-wrench:before {
+.icon-wrench:before {
 	content: "\e024";
 }
-#conversejs .icon-unlocked:before {
+.icon-unlocked:before {
 	content: "\e025";
 }
-#conversejs .icon-lock:before {
+.icon-lock:before {
 	content: "\e026";
 }
-#conversejs .icon-lock-2:before {
+.icon-lock-2:before {
 	content: "\e027";
 }
-#conversejs .icon-key:before {
+.icon-key:before {
 	content: "\e028";
 }
-#conversejs .icon-key-2:before {
+.icon-key-2:before {
 	content: "\e029";
 }
-#conversejs .icon-zoomout:before {
+.icon-zoomout:before {
 	content: "\e02a";
 }
-#conversejs .icon-zoomin:before {
+.icon-zoomin:before {
 	content: "\e02b";
 }
-#conversejs .icon-cog:before {
+.icon-cog:before {
 	content: "\e02f";
 }
-#conversejs .icon-remove:before {
+.icon-remove:before {
 	content: "\e02d";
 }
-#conversejs .icon-eye:before {
+.icon-eye:before {
 	content: "\e030";
 }
-#conversejs .icon-eye-blocked:before {
+.icon-eye-blocked:before {
 	content: "\e031";
 }
-#conversejs .icon-attachment:before {
+.icon-attachment:before {
 	content: "\e032";
 }
-#conversejs .icon-globe:before {
+.icon-globe:before {
 	content: "\e033";
 }
-#conversejs .icon-heart:before {
+.icon-heart:before {
 	content: "\2764";
 }
-#conversejs .icon-happy:before {
+.icon-happy:before {
 	content: "\263b";
 }
-#conversejs .icon-thumbs-up:before {
+.icon-thumbs-up:before {
 	content: "\261d";
 }
-#conversejs .icon-smiley:before {
+.icon-smiley:before {
 	content: "\263a";
 }
-#conversejs .icon-tongue:before {
+.icon-tongue:before {
 	content: "\e038";
 }
-#conversejs .icon-sad:before {
+.icon-sad:before {
 	content: "\2639";
 }
-#conversejs .icon-wink:before {
+.icon-wink:before {
 	content: "\e03a";
 }
-#conversejs .icon-wondering:before {
+.icon-wondering:before {
 	content: "\2369";
 }
-#conversejs .icon-confused:before {
+.icon-confused:before {
 	content: "\2368";
 }
-#conversejs .icon-shocked:before {
+.icon-shocked:before {
 	content: "\2364";
 }
-#conversejs .icon-evil:before {
+.icon-evil:before {
 	content: "\261f";
 }
-#conversejs .icon-angry:before {
+.icon-angry:before {
 	content: "\e03f";
 }
-#conversejs .icon-cool:before {
+.icon-cool:before {
 	content: "\e040";
 }
-#conversejs .icon-grin:before {
+.icon-grin:before {
 	content: "\e041";
 }
-#conversejs .icon-info:before {
+.icon-info:before {
 	content: "\2360";
 }
-#conversejs .icon-notification:before {
+.icon-notification:before {
 	content: "\e01f";
 }
-#conversejs .icon-warning:before {
+.icon-warning:before {
 	content: "\26a0";
 }
-#conversejs .icon-spell-check:before {
+.icon-spell-check:before {
 	content: "\e045";
 }
-#conversejs .icon-volume-high:before {
+.icon-volume-high:before {
 	content: "\e046";
 }
-#conversejs .icon-volume-medium:before {
+.icon-volume-medium:before {
 	content: "\e047";
 }
-#conversejs .icon-volume-low:before {
+.icon-volume-low:before {
 	content: "\e048";
 }
-#conversejs .icon-volume-mute:before {
+.icon-volume-mute:before {
 	content: "\e049";
 }
-#conversejs .icon-volume-mute2:before {
+.icon-volume-mute2:before {
 	content: "\e04a";
 }
-#conversejs .icon-volume-decrease:before {
+.icon-volume-decrease:before {
 	content: "\e04b";
 }
-#conversejs .icon-volume-increase:before {
+.icon-volume-increase:before {
 	content: "\e04c";
 }
-#conversejs .icon-bold:before {
+.icon-bold:before {
 	content: "\e04d";
 }
-#conversejs .icon-underline:before {
+.icon-underline:before {
 	content: "\e04e";
 }
-#conversejs .icon-italic:before {
+.icon-italic:before {
 	content: "\e04f";
 }
-#conversejs .icon-strikethrough:before {
+.icon-strikethrough:before {
 	content: "\e050";
 }
-#conversejs .icon-newtab:before {
+.icon-newtab:before {
 	content: "\e053";
 }
-#conversejs .icon-youtube:before {
+.icon-youtube:before {
 	content: "\e055";
 }
-#conversejs .icon-close:before {
+.icon-close:before {
 	content: "\2715";
 }
-#conversejs .icon-blocked:before {
+.icon-blocked:before {
 	content: "\2718";
 }
-#conversejs .icon-cancel-circle:before {
+.icon-cancel-circle:before {
 	content: "\e058";
 }
-#conversejs .icon-minus:before {
+.icon-minus:before {
 	content: "\e05a";
 }
-#conversejs .icon-plus:before {
+.icon-plus:before {
 	content: "\271a";
 }
-#conversejs .icon-checkbox-checked:before {
+.icon-checkbox-checked:before {
 	content: "\2611";
 }
-#conversejs .icon-checkbox-unchecked:before {
+.icon-checkbox-unchecked:before {
 	content: "\2b27";
 }
-#conversejs .icon-checkbox-partial:before {
+.icon-checkbox-partial:before {
 	content: "\2b28";
 }
-#conversejs .icon-radio-checked:before {
+.icon-radio-checked:before {
 	content: "\2b26";
 }
-#conversejs .icon-radio-unchecked:before {
+.icon-radio-unchecked:before {
 	content: "\2b25";
 }
-#conversejs .icon-room-info:before {
+.icon-room-info:before {
 	content: "\e059";
 }
-#conversejs .icon-newspaper:before {
+.icon-newspaper:before {
 	content: "\e001";
 }
-#conversejs .icon-image:before {
+.icon-image:before {
 	content: "\2b14";
 }
-#conversejs .icon-offline:before {
+.icon-offline:before {
 	content: "\e002";
 }
-#conversejs .icon-busy:before {
+.icon-busy:before {
 	content: "\e004";
 }
-#conversejs .icon-exit:before {
+.icon-exit:before {
 	content: "\e601";
 }

+ 8 - 5
index.html

@@ -144,18 +144,22 @@
                         <ul class="features">
                             <li>Single-user chat</li>
                             <li>Multi-user chatrooms (<a href="http://xmpp.org/extensions/xep-0045.html" target="_blank">XEP 45</a>)</li>
+                            <li>Direct invitations to chat rooms (<a href="http://xmpp.org/extensions/xep-0249.html" target="_blank">XEP 249</a>)</li>
                             <li>vCard support (<a href="http://xmpp.org/extensions/xep-0054.html" target="_blank">XEP 54</a>)</li>
                             <li>Service discovery (<a href="http://xmpp.org/extensions/xep-0030.html" target="_blank">XEP 30</a>)</li>
+                            <li>In-band registration (<a href="http://xmpp.org/extensions/xep-0077.html" target="_blank">XEP 77</a>)</li>
                             <li>Contact rosters and groups</li>
                             <li>Contact subscriptions</li>
-                            <li>Accept or decline contact requests</li>
                             <li>Roster item exchange (<a href="http://xmpp.org/extensions/tmp/xep-0144-1.1.html" target="_blank">XEP 144</a>)</li>
                             <li>Chat statuses (online, busy, away, offline)</li>
                             <li>Custom status messages</li>
-                            <li>Typing notifications</li>
-                            <li>Third person messages (/me )</li>
+                            <li>Typing and state notifications (<a href="http://xmpp.org/extensions/xep-0085.html" target="_blank">XEP 85</a>)</li>
+                            <li>Messages appear in all connected chat clients (<a href="http://xmpp.org/extensions/xep-0280.html" target="_blank">XEP 280</a>)</li>
+                            <li>Third person "/me" messages (<a href="http://xmpp.org/extensions/xep-0245.html" target="_blank">XEP 245</a>)</li>
+                            <li>XMPP Ping (<a href="http://xmpp.org/extensions/xep-0199.html" target="_blank">XEP 199</a>)</li>
+                            <li>Client state indication (<a href="http://xmpp.org/extensions/xep-0352.html" target="_blank">XEP 352</a>)</li>A
+                            <li>Off-the-record encryption</li>
                             <li>Translated into 16 languages</li>
-                            <li>Off-the-record encryption
                         </ul>
                 </div>
                 <div class="col-lg-4">
@@ -251,7 +255,6 @@
         })();
         converse.initialize({
             bosh_service_url: 'https://conversejs.org/http-bind/', // Please use this connection manager only for testing purposes
-            i18n: locales['en'], // Refer to ./locale/locales.js to see which locales are supported
             keepalive: true,
             message_carbons: true,
             play_sounds: true,

+ 106 - 50
locale/de/LC_MESSAGES/converse.json

@@ -17,11 +17,11 @@
          ],
          "unverified": [
             null,
-            "unbestätigt"
+            "nicht verifiziert"
          ],
          "verified": [
             null,
-            "bestätigt"
+            "verifiziert"
          ],
          "finished": [
             null,
@@ -29,7 +29,7 @@
          ],
          "This contact is busy": [
             null,
-            "Dieser Kontakt ist beschäfticht"
+            "Dieser Kontakt ist beschäftigt"
          ],
          "This contact is online": [
             null,
@@ -45,7 +45,7 @@
          ],
          "This contact is away for an extended period": [
             null,
-            "Dieser Kontakt is für längere Zeit abwesend"
+            "Dieser Kontakt ist für längere Zeit abwesend"
          ],
          "This contact is away": [
             null,
@@ -53,7 +53,7 @@
          ],
          "Click to hide these contacts": [
             null,
-            "Hier klicken um diesen Kontakte zu verstecken"
+            "Hier klicken um diesen Kontakt zu verstecken"
          ],
          "My contacts": [
             null,
@@ -69,7 +69,7 @@
          ],
          "Ungrouped": [
             null,
-            ""
+            "Ungruppiert"
          ],
          "Contacts": [
             null,
@@ -77,7 +77,11 @@
          ],
          "Groups": [
             null,
-            ""
+            "Gruppen"
+         ],
+         "Reconnecting": [
+            null,
+            "Verbindung wiederherstellen …"
          ],
          "Error": [
             null,
@@ -97,36 +101,52 @@
          ],
          "Re-establishing encrypted session": [
             null,
-            ""
+            "Verschlüsselte Sitzung wiederherstellen"
          ],
          "Generating private key.": [
             null,
-            ""
+            "Generiere privaten Schlüssel."
          ],
          "Your browser might become unresponsive.": [
             null,
-            ""
+            "Ihr Browser könnte langsam reagieren."
          ],
          "Authentication request from %1$s\n\nYour chat contact is attempting to verify your identity, by asking you the question below.\n\n%2$s": [
             null,
-            ""
+            "Authentifizierungsanfrage von %1$s\n\nIhr Kontakt möchte durch die folgende Frage Ihre Identität verifizieren.\n\n%2$s"
          ],
          "Could not verify this user's identify.": [
             null,
-            ""
+            "Die Identität des Benutzers konnte nicht verifiziert werden."
          ],
          "Exchanging private key with contact.": [
             null,
-            ""
+            "Tausche private Schlüssel mit Kontakt aus."
          ],
          "Personal message": [
             null,
             "Persönliche Nachricht"
          ],
+         "Are you sure you want to clear the messages from this room?": [
+            null,
+            "Sind Sie sicher, dass Sie alle Nachrichten in diesem Raum löschen möchten?"
+         ],
          "me": [
             null,
             "Ich"
          ],
+         "is typing": [
+            null,
+            "%1$s tippt"
+         ],
+         "has stopped typing": [
+            null,
+            "%1$s tippt nicht mehr"
+         ],
+         "has gone away": [
+            null,
+            "ist jetzt abwesend"
+         ],
          "Show this menu": [
             null,
             "Dieses Menü anzeigen"
@@ -141,19 +161,19 @@
          ],
          "Are you sure you want to clear the messages from this chat box?": [
             null,
-            ""
+            "Sind Sie sicher, dass Sie alle Nachrichten dieses Chats löschen möchten?"
          ],
          "Your message could not be sent": [
             null,
-            ""
+            "Ihre Nachricht konnte nicht gesendet werden"
          ],
          "We received an unencrypted message": [
             null,
-            ""
+            "Wir haben eine unverschlüsselte Nachricht empfangen"
          ],
          "We received an unreadable encrypted message": [
             null,
-            ""
+            "Wir haben eine unlesbare Nachricht empfangen"
          ],
          "Here are the fingerprints, please confirm them with %1$s, outside of this chat.\n\nFingerprint for you, %2$s: %3$s\n\nFingerprint for %1$s: %4$s\n\nIf you have confirmed that the fingerprints match, click OK, otherwise click Cancel.": [
             null,
@@ -213,7 +233,7 @@
          ],
          "Hide the list of participants": [
             null,
-            ""
+            "Teilnehmerliste ausblenden"
          ],
          "Refresh encrypted conversation": [
             null,
@@ -237,7 +257,7 @@
          ],
          "What's this?": [
             null,
-            ""
+            "Was ist das?"
          ],
          "Online": [
             null,
@@ -245,7 +265,7 @@
          ],
          "Busy": [
             null,
-            "Beschäfticht"
+            "Beschäftigt"
          ],
          "Away": [
             null,
@@ -273,11 +293,11 @@
          ],
          "Click to add new chat contacts": [
             null,
-            "Klicken Sie, um einen neuen Kontakt hinzuzufügen"
+            "Hier klicken um neuen Kontakt hinzuzufügen"
          ],
          "Add a contact": [
             null,
-            "Kontakte hinzufügen"
+            "Kontakt hinzufügen"
          ],
          "No users found": [
             null,
@@ -393,7 +413,7 @@
          ],
          "Invite...": [
             null,
-            ""
+            "Einladen..."
          ],
          "Occupants": [
             null,
@@ -413,7 +433,7 @@
          ],
          "Error: could not execute the command": [
             null,
-            ""
+            "Fehler: konnte den Befehl nicht ausführen"
          ],
          "Change user's affiliation to admin": [
             null,
@@ -425,7 +445,7 @@
          ],
          "Change user role to participant": [
             null,
-            ""
+            "Benutzerrolle zu Teilnehmer ändern"
          ],
          "Kick user from room": [
             null,
@@ -445,12 +465,16 @@
          ],
          "Change your nickname": [
             null,
-            ""
+            "Spitznamen ändern"
          ],
          "Grant moderator role to user": [
             null,
             ""
          ],
+         "Grant ownership of this room": [
+            null,
+            "Besitzrechte an diesem Raum vergeben"
+         ],
          "Revoke user's membership": [
             null,
             ""
@@ -473,11 +497,11 @@
          ],
          "An error occurred while trying to save the form.": [
             null,
-            "Beim Speichern der Formular is ein Fehler aufgetreten."
+            "Beim Speichern des Formulars ist ein Fehler aufgetreten."
          ],
          "This chatroom requires a password": [
             null,
-            "Passwort wird für die Anmeldung benötigt."
+            "Dieser Raum erfordert ein Passwort"
          ],
          "Password: ": [
             null,
@@ -485,7 +509,7 @@
          ],
          "Submit": [
             null,
-            "Einreichen"
+            "Abschicken"
          ],
          "This room is not anonymous": [
             null,
@@ -493,23 +517,23 @@
          ],
          "This room now shows unavailable members": [
             null,
-            "Dieser Raum zeigt jetzt unferfügbare Mitglieder"
+            "Dieser Raum zeigt jetzt nicht verfügbare Mitglieder an"
          ],
          "This room does not show unavailable members": [
             null,
-            "Dieser Raum zeigt nicht unverfügbare Mitglieder"
+            "Dieser Raum zeigt jetzt nicht verfügbare Mitglieder nicht an"
          ],
          "Non-privacy-related room configuration has changed": [
             null,
-            "Die Konfiguration, die nicht auf die Privatsphäre bezogen ist, hat sich geändert"
+            "Raumkonfiguration, nicht Privatsphäre relevant, hat sich geändert"
          ],
          "Room logging is now enabled": [
             null,
-            "Zukünftige Nachrichten dieses Raums werden protokolliert."
+            "Nachrichten in diesem Raums werden ab jetzt protokolliert."
          ],
          "Room logging is now disabled": [
             null,
-            "Zukünftige Nachrichten dieses Raums werden nicht protokolliert."
+            "Nachrichten in diesem Raums werden nicht mehr protokolliert."
          ],
          "This room is now non-anonymous": [
             null,
@@ -525,7 +549,7 @@
          ],
          "A new room has been created": [
             null,
-            "Einen neuen Raum ist erstellen"
+            "Einen neuer Raum wurde erstellt"
          ],
          "You have been banned from this room": [
             null,
@@ -541,19 +565,23 @@
          ],
          "You have been removed from this room because the room has changed to members-only and you're not a member": [
             null,
-            "Sie wurden aus diesem Raum entfernt da Sie kein Mitglied sind."
+            "Sie wurden aus diesem Raum entfernt, da Sie kein Mitglied sind."
          ],
          "You have been removed from this room because the MUC (Multi-user chat) service is being shut down.": [
             null,
-            "Sie werden aus diesem Raum entfernt da der MUC (Muli-user chat) Dienst gerade abgeschalten wird."
+            "Sie wurden aus diesem Raum entfernt, da der MUC (Multi-User Chat) Dienst gerade heruntergefahren wird."
          ],
          "<strong>%1$s</strong> has been banned": [
             null,
-            "<strong>%1$s</strong> ist verbannt"
+            "<strong>%1$s</strong> ist verbannt worden"
+         ],
+         "<strong>%1$s</strong>'s nickname has changed": [
+            null,
+            "<strong>%1$s</strong> hat den Spitznamen geändert"
          ],
          "<strong>%1$s</strong> has been kicked out": [
             null,
-            "<strong>%1$s</strong> ist hinausgeworfen"
+            "<strong>%1$s</strong> wurde hinausgeworfen"
          ],
          "<strong>%1$s</strong> has been removed because of an affiliation change": [
             null,
@@ -563,9 +591,13 @@
             null,
             "<strong>%1$s</strong> ist kein Mitglied und wurde daher entfernt"
          ],
+         "Your nickname has been automatically changed to: <strong>%1$s</strong>": [
+            null,
+            "Ihr Spitzname wurde automatisiert geändert zu: <strong>%1$s</strong>"
+         ],
          "The reason given is: \"": [
             null,
-            ""
+            "Die angegebene Begründung lautet: \""
          ],
          "You are not on the member list of this room": [
             null,
@@ -577,7 +609,7 @@
          ],
          "You are not allowed to create new rooms": [
             null,
-            "Es ist Ihnen nicht erlaubt, neue Räume anzulegen"
+            "Es ist Ihnen nicht erlaubt neue Räume anzulegen"
          ],
          "Your nickname doesn't conform to this room's policies": [
             null,
@@ -597,31 +629,51 @@
          ],
          "Topic set by %1$s to: %2$s": [
             null,
-            "%1$s hat das Thema zu \"%2$s\" abgeändert"
+            "%1$s hat das Thema zu \"%2$s\" geändert"
          ],
          "%1$s has invited you to join a chat room: %2$s": [
             null,
-            ""
+            "%1$s hat Sie in den Raum \"%2$s\" eingeladen"
          ],
          "%1$s has invited you to join a chat room: %2$s, and left the following reason: \"%3$s\"": [
             null,
-            ""
+            "%1$s hat Sie in den Raum \"%2$s\" eingeladen. Begründung: \"%3$s\""
+         ],
+         "Click to restore this chat": [
+            null,
+            "Hier klicken um diesen Chat wiederherzustellen"
          ],
          "Minimized": [
             null,
-            ""
+            "Minimiert"
          ],
          "Click to remove this contact": [
             null,
             "Hier klicken um diesen Kontakt zu entfernen"
          ],
+         "Click to accept this contact request": [
+            null,
+            "Hier klicken um diesen Kontaktanfrage zu akzeptieren"
+         ],
+         "Click to decline this contact request": [
+            null,
+            "Hier klicken um diesen Kontaktanfrage zu abzulehnen"
+         ],
          "Click to chat with this contact": [
             null,
             "Hier klicken um mit diesem Kontakt zu chatten"
          ],
+         "Are you sure you want to remove this contact?": [
+            null,
+            "Wollen Sie diesen Kontakt wirklich entfernen?"
+         ],
+         "Are you sure you want to decline this contact request?": [
+            null,
+            "Wollen Sie diese Kontaktanfrage wirklich ablehnen?"
+         ],
          "Type to filter": [
             null,
-            ""
+            "Tippen um zu filtern"
          ],
          "I am %1$s": [
             null,
@@ -629,11 +681,11 @@
          ],
          "Click here to write a custom status message": [
             null,
-            "Klicken Sie hier, um ihrer Status-Nachricht to ändern"
+            "Hier klicken um Status-Nachricht zu ändern"
          ],
          "Click to change your chat status": [
             null,
-            "Klicken Sie, um ihrer Status to ändern"
+            "Hier klicken um Status zu ändern"
          ],
          "Custom status": [
             null,
@@ -645,7 +697,7 @@
          ],
          "busy": [
             null,
-            "beschäfticht"
+            "beschäftigt"
          ],
          "away for long": [
             null,
@@ -711,6 +763,10 @@
             null,
             "Passwort:"
          ],
+         "Click here to log in anonymously": [
+            null,
+            "Hier klicken um anonym anzumelden"
+         ],
          "Log In": [
             null,
             "Anmelden"
@@ -721,7 +777,7 @@
          ],
          "Toggle chat": [
             null,
-            ""
+            "Chat ein-/ausblenden"
          ]
       }
    }

+ 76 - 115
locale/de/LC_MESSAGES/converse.po

@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Converse.js 0.4\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2015-05-01 12:26+0200\n"
-"PO-Revision-Date: 2015-05-01 12:25+0200\n"
+"PO-Revision-Date: 2015-06-04 10:11+0200\n"
 "Last-Translator: JC Brand <jc@opkode.com>\n"
 "Language-Team: German\n"
 "Language: de\n"
@@ -30,11 +30,11 @@ msgstr "unverschlüsselt"
 
 #: converse.js:332
 msgid "unverified"
-msgstr "unbestätigt"
+msgstr "nicht verifiziert"
 
 #: converse.js:333
 msgid "verified"
-msgstr "bestätigt"
+msgstr "verifiziert"
 
 #: converse.js:334
 msgid "finished"
@@ -42,7 +42,7 @@ msgstr "erledigt"
 
 #: converse.js:337
 msgid "This contact is busy"
-msgstr "Dieser Kontakt ist beschäfticht"
+msgstr "Dieser Kontakt ist beschäftigt"
 
 #: converse.js:338
 msgid "This contact is online"
@@ -58,7 +58,7 @@ msgstr "Dieser Kontakt ist nicht verfügbar"
 
 #: converse.js:341
 msgid "This contact is away for an extended period"
-msgstr "Dieser Kontakt is für längere Zeit abwesend"
+msgstr "Dieser Kontakt ist für längere Zeit abwesend"
 
 #: converse.js:342
 msgid "This contact is away"
@@ -82,7 +82,7 @@ msgstr "Kontaktanfragen"
 
 #: converse.js:349
 msgid "Ungrouped"
-msgstr ""
+msgstr "Ungruppiert"
 
 #: converse.js:351 converse.js:648 converse.js:691
 msgid "Contacts"
@@ -90,12 +90,11 @@ msgstr "Kontakte"
 
 #: converse.js:352
 msgid "Groups"
-msgstr ""
+msgstr "Gruppen"
 
 #: converse.js:452
-#, fuzzy
 msgid "Reconnecting"
-msgstr "Verbindungsaufbau …"
+msgstr "Verbindung wiederherstellen …"
 
 #: converse.js:495
 msgid "Error"
@@ -115,15 +114,15 @@ msgstr "Authentifizierung gescheitert"
 
 #: converse.js:807
 msgid "Re-establishing encrypted session"
-msgstr ""
+msgstr "Verschlüsselte Sitzung wiederherstellen"
 
 #: converse.js:819
 msgid "Generating private key."
-msgstr ""
+msgstr "Generiere privaten Schlüssel."
 
 #: converse.js:820
 msgid "Your browser might become unresponsive."
-msgstr ""
+msgstr "Ihr Browser könnte langsam reagieren."
 
 #: converse.js:855
 msgid ""
@@ -134,42 +133,44 @@ msgid ""
 "\n"
 "%2$s"
 msgstr ""
+"Authentifizierungsanfrage von %1$s\n"
+"\n"
+"Ihr Kontakt möchte durch die folgende Frage "
+"Ihre Identität verifizieren.\n"
+"\n"
+"%2$s"
 
 #: converse.js:864
 msgid "Could not verify this user's identify."
-msgstr ""
+msgstr "Die Identität des Benutzers konnte nicht verifiziert werden."
 
 #: converse.js:903
 msgid "Exchanging private key with contact."
-msgstr ""
+msgstr "Tausche private Schlüssel mit Kontakt aus."
 
 #: converse.js:1049
 msgid "Personal message"
 msgstr "Persönliche Nachricht"
 
 #: converse.js:1081
-#, fuzzy
 msgid "Are you sure you want to clear the messages from this room?"
-msgstr "Sie sind nicht auf der Mitgliederliste dieses Raums"
+msgstr "Sind Sie sicher, dass Sie alle Nachrichten in diesem Raum löschen möchten?"
 
 #: converse.js:1103
 msgid "me"
 msgstr "Ich"
 
 #: converse.js:1158
-#, fuzzy
 msgid "is typing"
 msgstr "%1$s tippt"
 
 #: converse.js:1161
-#, fuzzy
 msgid "has stopped typing"
-msgstr "%1$s tippt"
+msgstr "%1$s tippt nicht mehr"
 
 #: converse.js:1167 converse.js:1447
-#, fuzzy
 msgid "has gone away"
-msgstr "Dieser Kontakt ist abwesend"
+msgstr "ist jetzt abwesend"
 
 #: converse.js:1212 converse.js:2531
 msgid "Show this menu"
@@ -185,19 +186,19 @@ msgstr "Nachrichten entfernen"
 
 #: converse.js:1340
 msgid "Are you sure you want to clear the messages from this chat box?"
-msgstr ""
+msgstr "Sind Sie sicher, dass Sie alle Nachrichten dieses Chats löschen möchten?"
 
 #: converse.js:1375
 msgid "Your message could not be sent"
-msgstr ""
+msgstr "Ihre Nachricht konnte nicht gesendet werden"
 
 #: converse.js:1378
 msgid "We received an unencrypted message"
-msgstr ""
+msgstr "Wir haben eine unverschlüsselte Nachricht empfangen"
 
 #: converse.js:1381
 msgid "We received an unreadable encrypted message"
-msgstr ""
+msgstr "Wir haben eine unlesbare Nachricht empfangen"
 
 #: converse.js:1407
 msgid ""
@@ -239,9 +240,8 @@ msgid "has gone offline"
 msgstr "Dieser Kontakt ist offline"
 
 #: converse.js:1449
-#, fuzzy
 msgid "is busy"
-msgstr "beschäfticht"
+msgstr "ist beschäftigt"
 
 #: converse.js:1537
 msgid "Your messages are not encrypted anymore"
@@ -280,9 +280,8 @@ msgid ""
 msgstr ""
 
 #: converse.js:1568
-#, fuzzy
 msgid "Clear all messages"
-msgstr "Persönliche Nachricht"
+msgstr "Alle Nachrichten löschen"
 
 #: converse.js:1569
 msgid "End encrypted conversation"
@@ -290,7 +289,7 @@ msgstr ""
 
 #: converse.js:1570
 msgid "Hide the list of participants"
-msgstr ""
+msgstr "Teilnehmerliste ausblenden"
 
 #: converse.js:1571
 msgid "Refresh encrypted conversation"
@@ -314,7 +313,7 @@ msgstr ""
 
 #: converse.js:1576
 msgid "What's this?"
-msgstr ""
+msgstr "Was ist das?"
 
 #: converse.js:1668
 msgid "Online"
@@ -322,7 +321,7 @@ msgstr "Online"
 
 #: converse.js:1669
 msgid "Busy"
-msgstr "Beschäfticht"
+msgstr "Beschäftigt"
 
 #: converse.js:1670
 msgid "Away"
@@ -333,9 +332,8 @@ msgid "Offline"
 msgstr "Abgemeldet"
 
 #: converse.js:1672
-#, fuzzy
 msgid "Log out"
-msgstr "Anmelden"
+msgstr "Abmelden"
 
 #: converse.js:1678
 msgid "Contact name"
@@ -355,11 +353,11 @@ msgstr "Hinzufügen"
 
 #: converse.js:1689
 msgid "Click to add new chat contacts"
-msgstr "Klicken Sie, um einen neuen Kontakt hinzuzufügen"
+msgstr "Hier klicken um neuen Kontakt hinzuzufügen"
 
 #: converse.js:1690
 msgid "Add a contact"
-msgstr "Kontakte hinzufügen"
+msgstr "Kontakt hinzufügen"
 
 #: converse.js:1714
 msgid "No users found"
@@ -382,9 +380,8 @@ msgid "Server"
 msgstr "Server"
 
 #: converse.js:1787
-#, fuzzy
 msgid "Join Room"
-msgstr "Beitreten"
+msgstr "Raum betreten"
 
 #: converse.js:1788
 msgid "Show rooms"
@@ -483,7 +480,7 @@ msgstr "Dieser Benutzer kann keine Nachrichten in diesem Raum verschicken"
 
 #: converse.js:2221
 msgid "Invite..."
-msgstr ""
+msgstr "Einladen..."
 
 #: converse.js:2222
 msgid "Occupants"
@@ -505,7 +502,7 @@ msgstr "Nachricht"
 
 #: converse.js:2452
 msgid "Error: could not execute the command"
-msgstr ""
+msgstr "Fehler: konnte den Befehl nicht ausführen"
 
 #: converse.js:2527
 msgid "Change user's affiliation to admin"
@@ -517,7 +514,7 @@ msgstr "Verbanne einen Benutzer aus dem Raum."
 
 #: converse.js:2530
 msgid "Change user role to participant"
-msgstr ""
+msgstr "Benutzerrolle zu Teilnehmer ändern"
 
 #: converse.js:2532
 msgid "Kick user from room"
@@ -537,16 +534,15 @@ msgstr ""
 
 #: converse.js:2536
 msgid "Change your nickname"
-msgstr ""
+msgstr "Spitznamen ändern"
 
 #: converse.js:2537
 msgid "Grant moderator role to user"
 msgstr ""
 
 #: converse.js:2538
-#, fuzzy
 msgid "Grant ownership of this room"
-msgstr "Sie sind nicht auf der Mitgliederliste dieses Raums"
+msgstr "Besitzrechte an diesem Raum vergeben"
 
 #: converse.js:2539
 msgid "Revoke user's membership"
@@ -570,11 +566,11 @@ msgstr "Abbrechen"
 
 #: converse.js:2730
 msgid "An error occurred while trying to save the form."
-msgstr "Beim Speichern der Formular is ein Fehler aufgetreten."
+msgstr "Beim Speichern des Formulars ist ein Fehler aufgetreten."
 
 #: converse.js:2777
 msgid "This chatroom requires a password"
-msgstr "Passwort wird für die Anmeldung benötigt."
+msgstr "Dieser Raum erfordert ein Passwort"
 
 #: converse.js:2778
 msgid "Password: "
@@ -582,7 +578,7 @@ msgstr "Passwort: "
 
 #: converse.js:2779
 msgid "Submit"
-msgstr "Einreichen"
+msgstr "Abschicken"
 
 #: converse.js:2814
 msgid "This room is not anonymous"
@@ -590,25 +586,23 @@ msgstr "Dieser Raum ist nicht anonym"
 
 #: converse.js:2815
 msgid "This room now shows unavailable members"
-msgstr "Dieser Raum zeigt jetzt unferfügbare Mitglieder"
+msgstr "Dieser Raum zeigt jetzt nicht verfügbare Mitglieder an"
 
 #: converse.js:2816
 msgid "This room does not show unavailable members"
-msgstr "Dieser Raum zeigt nicht unverfügbare Mitglieder"
+msgstr "Dieser Raum zeigt jetzt nicht verfügbare Mitglieder nicht an"
 
 #: converse.js:2817
 msgid "Non-privacy-related room configuration has changed"
-msgstr ""
-"Die Konfiguration, die nicht auf die Privatsphäre bezogen ist, hat sich "
-"geändert"
+msgstr "Raumkonfiguration, nicht Privatsphäre relevant, hat sich geändert"
 
 #: converse.js:2818
 msgid "Room logging is now enabled"
-msgstr "Zukünftige Nachrichten dieses Raums werden protokolliert."
+msgstr "Nachrichten in diesem Raums werden ab jetzt protokolliert."
 
 #: converse.js:2819
 msgid "Room logging is now disabled"
-msgstr "Zukünftige Nachrichten dieses Raums werden nicht protokolliert."
+msgstr "Nachrichten in diesem Raums werden nicht mehr protokolliert."
 
 #: converse.js:2820
 msgid "This room is now non-anonymous"
@@ -624,7 +618,7 @@ msgstr "Dieser Raum ist jetzt anonym"
 
 #: converse.js:2823
 msgid "A new room has been created"
-msgstr "Einen neuen Raum ist erstellen"
+msgstr "Einen neuer Raum wurde erstellt"
 
 #: converse.js:2827 converse.js:2926
 msgid "You have been banned from this room"
@@ -642,51 +636,47 @@ msgstr "Sie wurden wegen einer Zugehörigkeitsänderung entfernt"
 msgid ""
 "You have been removed from this room because the room has changed to members-"
 "only and you're not a member"
-msgstr "Sie wurden aus diesem Raum entfernt da Sie kein Mitglied sind."
+msgstr "Sie wurden aus diesem Raum entfernt, da Sie kein Mitglied sind."
 
 #: converse.js:2831
 msgid ""
 "You have been removed from this room because the MUC (Multi-user chat) "
 "service is being shut down."
 msgstr ""
-"Sie werden aus diesem Raum entfernt da der MUC (Muli-user chat) Dienst "
-"gerade abgeschalten wird."
+"Sie wurden aus diesem Raum entfernt, da der MUC (Multi-User Chat) Dienst "
+"gerade heruntergefahren wird."
 
 #: converse.js:2845
 msgid "<strong>%1$s</strong> has been banned"
-msgstr "<strong>%1$s</strong> ist verbannt"
+msgstr "<strong>%1$s</strong> ist verbannt worden"
 
 #: converse.js:2846
-#, fuzzy
 msgid "<strong>%1$s</strong>'s nickname has changed"
-msgstr "<strong>%1$s</strong> ist verbannt"
+msgstr "<strong>%1$s</strong> hat den Spitznamen geändert"
 
 #: converse.js:2847
 msgid "<strong>%1$s</strong> has been kicked out"
-msgstr "<strong>%1$s</strong> ist hinausgeworfen"
+msgstr "<strong>%1$s</strong> wurde hinausgeworfen"
 
 #: converse.js:2848
 msgid "<strong>%1$s</strong> has been removed because of an affiliation change"
-msgstr ""
-"<strong>%1$s</strong> wurde wegen einer Zugehörigkeitsänderung entfernt"
+msgstr "<strong>%1$s</strong> wurde wegen einer Zugehörigkeitsänderung entfernt"
 
 #: converse.js:2849
 msgid "<strong>%1$s</strong> has been removed for not being a member"
 msgstr "<strong>%1$s</strong> ist kein Mitglied und wurde daher entfernt"
 
 #: converse.js:2853
-#, fuzzy
 msgid "Your nickname has been automatically changed to: <strong>%1$s</strong>"
-msgstr "Spitzname festgelegen"
+msgstr "Ihr Spitzname wurde automatisiert geändert zu: <strong>%1$s</strong>"
 
 #: converse.js:2854
-#, fuzzy
 msgid "Your nickname has been changed to: <strong>%1$s</strong>"
-msgstr "Spitzname festgelegen"
+msgstr "Ihr Spitzname wurde geändert zu: <strong>%1$s</strong>"
 
 #: converse.js:2902 converse.js:2912
 msgid "The reason given is: \""
-msgstr ""
+msgstr "Die angegebene Begründung lautet: \""
 
 #: converse.js:2924
 msgid "You are not on the member list of this room"
@@ -698,7 +688,7 @@ msgstr "Kein Spitzname festgelegt"
 
 #: converse.js:2934
 msgid "You are not allowed to create new rooms"
-msgstr "Es ist Ihnen nicht erlaubt, neue Räume anzulegen"
+msgstr "Es ist Ihnen nicht erlaubt neue Räume anzulegen"
 
 #: converse.js:2936
 msgid "Your nickname doesn't conform to this room's policies"
@@ -718,58 +708,55 @@ msgstr "Dieser Raum hat die maximale Mitgliederanzahl erreicht"
 
 #: converse.js:2988
 msgid "Topic set by %1$s to: %2$s"
-msgstr "%1$s hat das Thema zu \"%2$s\" abgeändert"
+msgstr "%1$s hat das Thema zu \"%2$s\" geändert"
 
 #: converse.js:3066
 msgid "%1$s has invited you to join a chat room: %2$s"
-msgstr ""
+msgstr "%1$s hat Sie in den Raum \"%2$s\" eingeladen"
 
 #: converse.js:3070
 msgid ""
 "%1$s has invited you to join a chat room: %2$s, and left the following "
 "reason: \"%3$s\""
 msgstr ""
+"%1$s hat Sie in den Raum \"%2$s\" eingeladen. "
+"Begründung: \"%3$s\""
 
 #: converse.js:3339
-#, fuzzy
 msgid "Click to restore this chat"
-msgstr "Hier klicken um diesen Kontakt zu entfernen"
+msgstr "Hier klicken um diesen Chat wiederherzustellen"
 
 #: converse.js:3481
 msgid "Minimized"
-msgstr ""
+msgstr "Minimiert"
 
 #: converse.js:3582 converse.js:3600
 msgid "Click to remove this contact"
 msgstr "Hier klicken um diesen Kontakt zu entfernen"
 
 #: converse.js:3589
-#, fuzzy
 msgid "Click to accept this contact request"
-msgstr "Hier klicken um diesen Kontakt zu entfernen"
+msgstr "Hier klicken um diesen Kontaktanfrage zu akzeptieren"
 
 #: converse.js:3590
-#, fuzzy
 msgid "Click to decline this contact request"
-msgstr "Hier klicken um diesen Kontakt zu entfernen"
+msgstr "Hier klicken um diesen Kontaktanfrage zu abzulehnen"
 
 #: converse.js:3599
 msgid "Click to chat with this contact"
 msgstr "Hier klicken um mit diesem Kontakt zu chatten"
 
 #: converse.js:3616
-#, fuzzy
 msgid "Are you sure you want to remove this contact?"
-msgstr "Hier klicken um diesen Kontakt zu entfernen"
+msgstr "Wollen Sie diesen Kontakt wirklich entfernen?"
 
 #: converse.js:3639
-#, fuzzy
 msgid "Are you sure you want to decline this contact request?"
-msgstr "Hier klicken um diesen Kontakt zu entfernen"
+msgstr "Wollen Sie diese Kontaktanfrage wirklich ablehnen?"
 
 #: converse.js:4166
 msgid "Type to filter"
-msgstr ""
+msgstr "Tippen um zu filtern"
 
 #. For translators: the %1$s part gets replaced with the status
 #. Example, I am online
@@ -779,11 +766,11 @@ msgstr "Ich bin %1$s"
 
 #: converse.js:4602 converse.js:4678
 msgid "Click here to write a custom status message"
-msgstr "Klicken Sie hier, um ihrer Status-Nachricht to ändern"
+msgstr "Hier klicken um Status-Nachricht zu ändern"
 
 #: converse.js:4603 converse.js:4679
 msgid "Click to change your chat status"
-msgstr "Klicken Sie, um ihrer Status to ändern"
+msgstr "Hier klicken um Status zu ändern"
 
 #: converse.js:4628
 msgid "Custom status"
@@ -795,7 +782,7 @@ msgstr "online"
 
 #: converse.js:4658
 msgid "busy"
-msgstr "beschäfticht"
+msgstr "beschäftigt"
 
 #: converse.js:4660
 msgid "away for long"
@@ -866,9 +853,8 @@ msgid "Password:"
 msgstr "Passwort:"
 
 #: converse.js:5202
-#, fuzzy
 msgid "Click here to log in anonymously"
-msgstr "Dieser Raum ist nicht anonym"
+msgstr "Hier klicken um anonym anzumelden"
 
 #: converse.js:5203
 msgid "Log In"
@@ -880,29 +866,4 @@ msgstr "Anmelden"
 
 #: converse.js:5291
 msgid "Toggle chat"
-msgstr ""
-
-#~ msgid "Online Contacts"
-#~ msgstr "Online-Kontakte"
-
-#~ msgid "Disconnected"
-#~ msgstr "Verbindung unterbrochen."
-
-#~ msgid "Connection Failed"
-#~ msgstr "Entfernte Verbindung fehlgeschlagen"
-
-#~ msgid "Disconnecting"
-#~ msgstr "Trenne Verbindung"
-
-#, fuzzy
-#~ msgid "Decline"
-#~ msgstr "Online"
-
-#~ msgid "BOSH Service URL:"
-#~ msgstr "BOSH "
-
-#~ msgid "Connected"
-#~ msgstr "Verbunden"
-
-#~ msgid "Attached"
-#~ msgstr "Angehängt"
+msgstr "Chat ein-/ausblenden"

+ 3 - 1
main.js

@@ -38,6 +38,7 @@ require.config({
         "strophe.disco":            "components/strophejs-plugins/disco/strophe.disco",
         "strophe.roster":           "src/strophe.roster",
         "strophe.vcard":            "src/strophe.vcard",
+        "strophe.ping":             "src/strophe.ping",
         "text":                     'components/requirejs-text/text',
         "tpl":                      'components/requirejs-tpl-jcbrand/tpl',
         "typeahead":                "components/typeahead.js/index",
@@ -170,7 +171,8 @@ require.config({
         'strophe.disco':        { deps: ['strophe'] },
         'strophe.register':     { deps: ['strophe'] },
         'strophe.roster':       { deps: ['strophe'] },
-        'strophe.vcard':        { deps: ['strophe'] }
+        'strophe.vcard':        { deps: ['strophe'] },
+        'strophe.ping':         { deps: ['strophe'] }
     }
 });
 

+ 1 - 0
non_amd.html

@@ -35,6 +35,7 @@
     <script type="text/javascript" src="src/strophe.roster.js"></script>
     <script type="text/javascript" src="components/strophejs-plugins/vcard/strophe.vcard.js"></script>
     <script type="text/javascript" src="components/strophejs-plugins/disco/strophe.disco.js"></script>
+	<script type="text/javascript" src="src/strophe.ping.js"></script>
     <script type="text/javascript" src="components/underscore/underscore.js"></script>
     <script type="text/javascript" src="components/backbone//backbone.js"></script>
     <script type="text/javascript" src="components/backbone.browserStorage/backbone.browserStorage.js"></script>

+ 10 - 6
sass/converse.scss

@@ -8,10 +8,12 @@
 
 @import "../ruby/1.9.1/gems/bourbon-4.2.1/app/assets/stylesheets/_bourbon";
 
+@import "variables";
+
 @font-face {
   font-family: 'Converse-js';
-  src: url('../fonticons/fonts/icomoon.eot?-mnoxh0');
-  src: url('../fonticons/fonts/icomoon.eot?#iefix-mnoxh0') format("embedded-opentype"), url('../fonticons/fonts/icomoon.woff?-mnoxh0') format("woff"), url('../fonticons/fonts/icomoon.ttf?-mnoxh0') format("truetype"), url('../fonticons/fonts/icomoon.svg?-mnoxh0#icomoon') format("svg");
+  src: url($font-path + 'icomoon.eot?-mnoxh0');
+  src: url($font-path + 'icomoon.eot?#iefix-mnoxh0') format("embedded-opentype"), url($font-path + 'icomoon.woff?-mnoxh0') format("woff"), url($font-path + 'icomoon.ttf?-mnoxh0') format("truetype"), url($font-path + 'icomoon.svg?-mnoxh0#icomoon') format("svg");
   font-weight: normal;
   font-style: normal;
 }
@@ -46,11 +48,12 @@
   bottom: 0;
   direction: ltr;
   height: $bottom-gutter-height;
-  left: 0;
+  left: auto;
   position: fixed;
-  right: 0;
+  right: 15px;
   z-index: 30;
   display: block;
+  width: auto;
 
   @include box-sizing(border-box);
   *, *:before, *:after {
@@ -227,7 +230,7 @@
   .icon-wink:before               { content: "\e03a"; }
   .icon-wondering:before          { content: "\2369"; }
   .icon-wrench:before             { content: "\e024"; }
-  .icon-xa:before,
+  .icon-xa:before                 { content: "\e602"; }
   .icon-unavailable:before,
   .icon-offline:before            { content: "\e002"; }
   .icon-youtube:before            { content: "\e055"; }
@@ -856,6 +859,7 @@
 
   div.room-info {
     clear: left;
+	width: 100%;
   }
 
   p.room-info {
@@ -896,7 +900,7 @@
     &:hover {
       background-color: $highlight-color;
       .room-info {
-        display: inline-block;
+        display: block;
         font-size: 14px;
       }
     }

+ 1 - 0
sass/variables.scss

@@ -37,3 +37,4 @@
   $mobile-chat-width: 100%;
   $mobile-chat-height: 400px;
 
+  $font-path: "../fonticons/fonts/";

+ 1 - 0
src/deps-full.js

@@ -6,6 +6,7 @@ define("converse-dependencies", [
     "strophe",
     "strophe.vcard",
     "strophe.disco",
+    "strophe.ping",
     "backbone.browserStorage",
     "backbone.overview",
     "jquery.browser",

+ 1 - 0
src/deps-no-otr.js

@@ -5,6 +5,7 @@ define("converse-dependencies", [
     "strophe",
     "strophe.vcard",
     "strophe.disco",
+    "strophe.ping",
     "backbone.browserStorage",
     "backbone.overview",
     "jquery.browser",

+ 1 - 0
src/deps-website-no-otr.js

@@ -5,6 +5,7 @@ define("converse-dependencies", [
     "strophe",
     "strophe.vcard",
     "strophe.disco",
+    "strophe.ping",
     "bootstrapJS", // XXX: Can be removed, only for https://conversejs.org
     "backbone.browserStorage",
     "backbone.overview",

+ 1 - 0
src/deps-website.js

@@ -7,6 +7,7 @@ define("converse-dependencies", [
     "strophe",
     "strophe.vcard",
     "strophe.disco",
+    "strophe.ping",
     "bootstrapJS", // XXX: Only for https://conversejs.org
     "backbone.browserStorage",
     "backbone.overview",

+ 100 - 0
src/strophe.ping.js

@@ -0,0 +1,100 @@
+/*
+* Based on Ping Strophejs plugins (https://github.com/metajack/strophejs-plugins/tree/master/ping)
+* This plugin is distributed under the terms of the MIT licence.
+* Please see the LICENCE file for details.
+*
+* Copyright (c) Markus Kohlhase, 2010
+* Refactored by Pavel Lang, 2011
+*/
+/**
+* File: strophe.ping.js
+* A Strophe plugin for XMPP Ping ( http://xmpp.org/extensions/xep-0199.html )
+*/
+/* 
+* AMD Support added by Thierry
+* 
+*/
+
+(function (root, factory) {
+    if (typeof define === 'function' && define.amd) {
+        // AMD. Register as an anonymous module.
+        define([
+            "strophe"
+        ], function (Strophe) {
+            factory(
+                Strophe.Strophe,
+                Strophe.$build,
+                Strophe.$iq ,
+                Strophe.$msg,
+                Strophe.$pres
+            );
+            return Strophe;
+        });
+    } else {
+        // Browser globals
+        factory(
+            root.Strophe,
+            root.$build,
+            root.$iq ,
+            root.$msg,
+            root.$pres
+        );
+    }
+}(this, function (Strophe, $build, $iq, $msg, $pres) {
+Strophe.addConnectionPlugin('ping', {
+        _c: null,
+
+        // called by the Strophe.Connection constructor
+        init: function(conn)
+        {
+                this._c = conn;
+                Strophe.addNamespace('PING', "urn:xmpp:ping");
+        },
+
+        /**
+         * Function: ping
+         *
+         * Parameters:
+         * (String) to - The JID you want to ping
+         * (Function) success - Callback function on success
+         * (Function) error - Callback function on error
+         * (Integer) timeout - Timeout in milliseconds
+         */
+        ping: function(jid, success, error, timeout)
+        {
+                var id = this._c.getUniqueId('ping');
+                var iq = $iq({type: 'get', to: jid, id: id}).c(
+                                'ping', {xmlns: Strophe.NS.PING});
+                this._c.sendIQ(iq, success, error, timeout);
+        },
+
+        /**
+         * Function: pong
+         *
+         * Parameters:
+         * (Object) ping - The ping stanza from the server.
+         */
+        pong: function(ping)
+        {
+                var from = ping.getAttribute('from');
+                var id = ping.getAttribute('id');
+                var iq = $iq({type: 'result', to: from,id: id});
+                this._c.sendIQ(iq);
+        },
+
+        /**
+         * Function: addPingHandler
+         *
+         * Parameters:
+         * (Function) handler - Ping handler
+         *
+         * Returns:
+         * A reference to the handler that can be used to remove it.
+         */
+        addPingHandler: function(handler)
+        {
+                return this._c.addHandler(handler, Strophe.NS.PING, "iq", "get");
+        }
+});
+
+}));

Some files were not shown because too many files changed in this diff