Decouple automatic away and XEP-0352 support.

- Add new config option csi_waiting_time for CSI support.
- The auto_away and auto_xa options won't send out CSI stanzas if csi_waiting_time is 0
- Update docs and add tests for both features.
This commit is contained in:
JC Brand 2015-06-22 00:01:31 +02:00
parent 7551c629bd
commit 868435173f
4 changed files with 153 additions and 63 deletions

View File

@ -287,8 +287,8 @@
allow_logout: true,
allow_muc: true,
allow_otr: true,
auto_away: 0, //in seconds
auto_xa: 0, //in seconds
auto_away: 0, // Seconds after which user status is set to 'away'
auto_xa: 0, // Seconds after which user status is set to 'xa'
allow_registration: true,
animate: true,
auto_list_rooms: false,
@ -297,6 +297,7 @@
auto_subscribe: false,
bosh_service_url: undefined, // The BOSH connection manager URL.
cache_otr_key: false,
csi_waiting_time: 0, // Support for XEP-0352. Seconds before client is considered idle and CSI is sent out.
debug: false,
domain_placeholder: __(" e.g. conversejs.org"), // Placeholder text shown in the domain input on the registration form
default_box_height: 400, // The default height, in pixels, for the control box, chat boxes and chatrooms.
@ -306,7 +307,7 @@
hide_offline_users: false,
jid: undefined,
keepalive: false,
message_carbons: false,
message_carbons: false, // Support for XEP-280
no_trimming: false, // Set to true for phantomjs tests (where browser apparently has no width)
ping_interval: 180, //in seconds
play_sounds: false,
@ -337,6 +338,8 @@
xhr_user_search: false,
xhr_user_search_url: ''
};
_.extend(this, this.default_settings);
// Allow only whitelisted configuration attributes to be overwritten
_.extend(this, _.pick(settings, Object.keys(this.default_settings)));
@ -415,54 +418,56 @@
// ----------------------
this.sendCSI = function (stat) {
if (converse.features[Strophe.NS.CSI]) {
/* Send out a Chat Status Notification (XEP-0352) */
if (converse.features[Strophe.NS.CSI] || true) {
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(unloadevent , 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.inactive = (stat === INACTIVE) ? true : false;
}
};
this.onUserActivity = function () {
/* Reset counters and flags relating to user activity. */
if (this.idle_seconds > 0) {
this.idle_seconds = 0;
}
if (this.inactive) {
this.sendCSI(ACTIVE);
}
if (this.auto_changed_status === true) {
this.auto_changed_status = false;
this.xmppstatus.setStatus('online');
}
};
this.onEverySecond = function () {
/* An interval handler running every second */
var stat = this.xmppstatus.getStatus();
this.idle_seconds++;
if (this.idle_seconds > this.csi_waiting_time && !this.inactive) {
this.sendCSI(INACTIVE);
}
if (this.auto_away > 0 && this.idle_seconds > this.auto_away && stat !== 'away' && stat !== 'xa') {
this.auto_changed_status = true;
this.xmppstatus.setStatus('away');
} else if (this.auto_xa > 0 && this.idle_seconds > this.auto_xa && stat !== 'xa') {
this.auto_changed_status = true;
this.xmppstatus.setStatus('xa');
}
};
this.registerIntervalHandler = function () {
/* Set an interval of one second and register a handler for it.
* Required for the auto_away, auto_xa and csi_waiting_time features.
*/
if (this.auto_away < 1 && this.auto_xa < 1 && this.csi_waiting_time < 1) {
// Waiting time of less then one second means features aren't used.
return;
}
this.idle_seconds = 0;
this.auto_changed_status = false; // Was the user's status changed by converse.js?
$(window).on('click mousemove keypress focus'+unloadevent , this.onUserActivity.bind(this));
window.setInterval(this.onEverySecond.bind(this), 1000);
};
this.playNotification = function () {
var audio;
@ -842,7 +847,7 @@
this.enableCarbons();
this.initStatus($.proxy(function () {
this.registerPingHandler();
this.registerAutoAwayHandler();
this.registerIntervalHandler();
this.chatboxes.onConnected();
this.giveFeedback(__('Contacts'));
if (this.callback) {
@ -1206,9 +1211,7 @@
);
this.renderToolbar().renderAvatar();
converse.emit('chatBoxOpened', this);
setTimeout(function () {
converse.refreshWebkit();
}, 50);
setTimeout(converse.refreshWebkit, 50);
return this.showStatusMessage();
},
@ -2543,9 +2546,7 @@
this.$el.attr('id', this.model.get('box_id'))
.html(converse.templates.chatroom(this.model.toJSON()));
this.renderChatArea();
setTimeout(function () {
converse.refreshWebkit();
}, 50);
setTimeout(converse.refreshWebkit, 50);
return this;
},
@ -5720,7 +5721,7 @@
*/
if (this.keepalive) {
try {
return this.connection.restore(null, this.onConnectStatusChanged);
return this.connection.restore(undefined, this.onConnectStatusChanged);
} catch (e) {
converse.log("Could not restore sessions. Error message: "+e.message);
}
@ -5749,7 +5750,7 @@
throw new Error("initConnection: you must supply a value for either the bosh_service_url or websocket_url or both.");
}
if (('WebSocket' in window || 'MozWebSocket' in window) && this.websocket_url) {
this.connection = new Strophe.Connection(this.websocket_url, {'keepalive': this.keepalive});
this.connection = new Strophe.Connection(this.websocket_url);
} else if (this.bosh_service_url) {
this.connection = new Strophe.Connection(this.bosh_service_url, {'keepalive': this.keepalive});
} else {

View File

@ -23,6 +23,7 @@ Changelog
* Refactored in order to remove the strophe.roster.js dependency. [jcbrand]
* Refactored the plugin architecture. Add `overrides` convention for
automatically overriding converse.js's methods and Backbone views and models. [jcbrand]
* Decouple automatic away and XEP-0352 support. [jcbrand]
0.9.3 (2015-05-01)
------------------

View File

@ -180,21 +180,22 @@ auto_away
* Default: ``0``
This option can be used to let converse.js automatically change user presence
The amount of seconds after which the user's presence status should
automatically become ``away``.
This set the number a seconds before user presence become ``away``
If the value if negative or ``0``, the function is disabled.
If the user's status is ``extended away``, it won't be changed to ``away``.
If the given value is negative or ``0``, this option is disabled.
auto_xa
-------
* Default: ``0``
This option can be used to let converse.js automatically change user presence
The amount of seconds after which the user's presence status should
automatically become ``extended away``.
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.
If the value is negative or ``0``, the function is disabled.
auto_reconnect
--------------
@ -253,6 +254,20 @@ This setting can only be used together with ``allow_otr = true``.
to retrieve your private key and read your all the chat messages in your
current session. Previous sessions however cannot be decrypted.
csi_waiting_time
----------------
* Default: ``0``
This option adds support for **XEP-0085 Chat State Indication**.
If converse.js is idle for the configured amount of seconds, a chat state
indication of ``inactive`` will be sent out to the XMPP server (if the server
supports CSI).
Afterwards, ss soon as there is any activity (for example, the mouse moves),
a chat state indication of ``active`` will be sent out.
debug
-----

View File

@ -57,6 +57,79 @@
});
});
describe("A chat state indication", function () {
it("are sent out when the client becomes or stops being idle", function () {
spyOn(converse, 'sendCSI').andCallThrough();
var sent_stanza;
spyOn(converse.connection, 'send').andCallFake(function (stanza) {
sent_stanza = stanza;
});
var i = 0;
converse.idle_seconds = 0; // Usually initialized by registerIntervalHandler
converse.features['urn:xmpp:csi:0'] = true; // Mock that the server supports CSI
converse.csi_waiting_time = 3; // The relevant config option
while (i <= converse.csi_waiting_time) {
expect(converse.sendCSI).not.toHaveBeenCalled();
converse.onEverySecond();
i++;
}
expect(converse.sendCSI).toHaveBeenCalledWith('inactive');
expect(sent_stanza.toLocaleString()).toBe(
"<inactive xmlns='urn:xmpp:csi:0'/>"
);
converse.onUserActivity();
expect(converse.sendCSI).toHaveBeenCalledWith('active');
expect(sent_stanza.toLocaleString()).toBe(
"<active xmlns='urn:xmpp:csi:0'/>"
);
// Reset values
converse.csi_waiting_time = 0;
converse.features['urn:xmpp:csi:0'] = false;
});
});
describe("Automatic status change", function () {
it("happens when the client is idle for long enough", function () {
var i = 0;
// Usually initialized by registerIntervalHandler
converse.idle_seconds = 0;
converse.auto_changed_status = false;
// The relevant config options
converse.auto_away = 3;
converse.auto_xa = 6;
expect(converse.xmppstatus.getStatus()).toBe('online');
while (i <= converse.auto_away) {
converse.onEverySecond();
i++;
}
expect(converse.auto_changed_status).toBe(true);
while (i <= converse.auto_xa) {
expect(converse.xmppstatus.getStatus()).toBe('away');
converse.onEverySecond();
i++;
}
expect(converse.xmppstatus.getStatus()).toBe('xa');
expect(converse.auto_changed_status).toBe(true);
converse.onUserActivity();
expect(converse.xmppstatus.getStatus()).toBe('online');
expect(converse.auto_changed_status).toBe(false);
// Reset values
converse.auto_away = 0;
converse.auto_xa = 0;
converse.auto_changed_status = false;
});
});
describe("The \"tokens\" API", $.proxy(function () {
beforeEach(function () {
test_utils.closeAllChatBoxes();