Commit 6100aaf1 authored by JC Brand's avatar JC Brand

Refactor the API. updates #46

API methods now consist of simple accessors and mutators that are logically
grouped.
parent 36db4c8b
...@@ -4713,78 +4713,150 @@ ...@@ -4713,78 +4713,150 @@
'initiateOTR': $.proxy(chatbox.initiateOTR, chatbox), 'initiateOTR': $.proxy(chatbox.initiateOTR, chatbox),
'maximize': $.proxy(chatbox.maximize, chatbox), 'maximize': $.proxy(chatbox.maximize, chatbox),
'minimize': $.proxy(chatbox.minimize, chatbox), 'minimize': $.proxy(chatbox.minimize, chatbox),
'set': $.proxy(chatbox.set, chatbox) 'set': $.proxy(chatbox.set, chatbox),
'open': chatbox.trigger.bind(chatbox, 'show')
}; };
}; };
return { return {
'getBuddy': function (jid) { 'initialize': function (settings, callback) {
var contact = converse.roster.get(Strophe.getBareJidFromJid(jid)); converse.initialize(settings, callback);
if (contact) { },
return contact.attributes; 'contacts': {
'get': function (jids) {
var _transform = function (jid) {
var contact = converse.roster.get(Strophe.getBareJidFromJid(jid));
if (contact) {
return contact.attributes;
}
return null;
};
if (typeof jids === "string") {
return _transform(jids);
}
return _.map(jids, _transform);
} }
}, },
'getChatBox': function (jid) { 'chats': {
var chatbox = converse.chatboxes.get(jid); 'get': function (jids) {
if (chatbox) { var _transform = function (jid) {
return wrappedChatBox(chatbox); var chatbox = converse.chatboxes.get(jid);
if (!chatbox) {
var roster_item = converse.roster.get(jid);
if (roster_item === undefined) {
converse.log('Could not get roster item for JID '+jid, 'error');
return null;
}
chatbox = converse.chatboxes.create({
'id': jid,
'jid': jid,
'fullname': _.isEmpty(roster_item.get('fullname'))? jid: roster_item.get('fullname'),
'image_type': roster_item.get('image_type'),
'image': roster_item.get('image'),
'url': roster_item.get('url')
});
}
return wrappedChatBox(chatbox);
};
if (typeof jids === "string") {
return _transform(jids);
}
return _.map(jids, _transform);
} }
}, },
'getRID': function () { 'tokens': {
if (converse.expose_rid_and_sid && typeof converse.connection !== "undefined") { 'get': function (id) {
return converse.connection.rid || converse.connection._proto.rid; if (!converse.expose_rid_and_sid || typeof converse.connection === "undefined") {
return null;
}
if (id.toLowerCase() === 'rid') {
return converse.connection.rid || converse.connection._proto.rid;
} else if (id.toLowerCase() === 'sid') {
return converse.connection.sid || converse.connection._proto.sid;
}
} }
return null;
}, },
'getSID': function () { 'listen': {
if (converse.expose_rid_and_sid && typeof converse.connection !== "undefined") { 'once': function (evt, handler) {
return converse.connection.sid || converse.connection._proto.sid; converse.once(evt, handler);
},
'on': function (evt, handler) {
converse.on(evt, handler);
},
'not': function (evt, handler) {
converse.off(evt, handler);
},
},
'plugins': {
'add': function (name, callback) {
converse.plugins[name] = callback;
},
'remove': function (name) {
delete converse.plugins[name];
},
'override': function (obj, attributes) {
/* Helper method for overriding or extending Converse's Backbone Views or Models
*
* When a method is overriden, the original will still be available
* on the _super attribute of the object being overridden.
*
* obj: The Backbone View or Model
* attributes: A hash of attributes, such as you would pass to Backbone.Model.extend or Backbone.View.extend
*/
if (!obj.prototype._super) {
obj.prototype._super = {};
}
_.each(attributes, function (value, key) {
if (key === 'events') {
obj.prototype[key] = _.extend(value, obj.prototype[key]);
} else {
if (typeof key === 'function') {
obj.prototype._super[key] = obj.prototype[key];
}
obj.prototype[key] = value;
}
});
} }
return null;
}, },
'initialize': function (settings, callback) { 'env': {
converse.initialize(settings, callback); 'jQuery': $,
'Strophe': Strophe,
'_': _
},
// Deprecated API methods
'getBuddy': function (jid) {
converse.log('WARNING: the "getBuddy" API method has been deprecated. Please use "contacts.get" instead');
return this.contacts.get(jid);
},
'getChatBox': function (jid) {
converse.log('WARNING: the "getChatBox" API method has been deprecated. Please use "chats.get" instead');
return this.chats.get(jid);
}, },
'jQuery': $,
'openChatBox': function (jid) { 'openChatBox': function (jid) {
var contact = converse.roster.get(Strophe.getBareJidFromJid(jid)); converse.log('WARNING: the "openChatBox" API method has been deprecated. Please use "chats.get(jid).open()" instead');
if (contact) { var chat = this.chats.get(jid);
return wrappedChatBox(converse.chatboxviews.showChat(contact.attributes)); if (chat) { chat.open(); }
} return chat;
},
'getRID': function () {
converse.log('WARNING: the "getRID" API method has been deprecated. Please use "tokens.get(\'rid\')" instead');
return this.tokens.get('rid');
},
'getSID': function () {
converse.log('WARNING: the "getSID" API method has been deprecated. Please use "tokens.get(\'sid\')" instead');
return this.tokens.get('sid');
}, },
'once': function (evt, handler) { 'once': function (evt, handler) {
converse.once(evt, handler); converse.log('WARNING: the "one" API method has been deprecated. Please use "listen.once" instead');
return this.listen.once(evt, handler);
}, },
'on': function (evt, handler) { 'on': function (evt, handler) {
converse.on(evt, handler); converse.log('WARNING: the "on" API method has been deprecated. Please use "listen.on" instead');
return this.listen.on(evt, handler);
}, },
'off': function (evt, handler) { 'off': function (evt, handler) {
converse.off(evt, handler); converse.log('WARNING: the "off" API method has been deprecated. Please use "listen.not" instead');
}, return this.listen.not(evt, handler);
'override': function (obj, attributes) {
/* Helper method for overriding or extending Converse's Backbone Views or Models
*
* When a method is overriden, the original will still be available
* on the _super attribute of the object being overridden.
*
* obj: The Backbone View or Model
* attributes: A hash of attributes, such as you would pass to Backbone.Model.extend or Backbone.View.extend
*/
if (!obj.prototype._super) {
obj.prototype._super = {};
}
_.each(attributes, function (value, key) {
if (key === 'events') {
obj.prototype[key] = _.extend(value, obj.prototype[key]);
} else {
if (typeof key === 'function') {
obj.prototype._super[key] = obj.prototype[key];
}
obj.prototype[key] = value;
}
});
},
'registerPlugin': function (name, callback) {
converse.plugins[name] = callback;
} }
}; };
})); }));
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
...@@ -515,11 +515,38 @@ You can run both the tests and jshint in one go by calling: ...@@ -515,11 +515,38 @@ You can run both the tests and jshint in one go by calling:
Developer API Developer API
============= =============
.. note:: see also the `event api methods`_, not listed here. .. note:: The API documented here is available in Converse.js 0.8.4 and higher.
Earlier versions of Converse.js might have different API methods or none at all.
In the Converse.js API, you traverse towards a logical grouping, from
which you can then call certain standardised accessors and mutators, like::
.get
.set
.add
.all
.remove
This is done to increase readability and to allow intuitive method chaining.
For example, to get a contact, you would do the following::
converse.contacts.get('jid@example.com');
To get multiple contacts, just pass in an array of jids::
converse.contacts.get(['jid1@example.com', 'jid2@example.com']);
**Here follows now a breakdown of all API groupings and methods**:
initialize initialize
---------- ----------
.. note:: This method is the one exception of a method which is not logically grouped
as explained above.
Initializes converse.js. This method must always be called when using Initializes converse.js. This method must always be called when using
converse.js. converse.js.
...@@ -544,15 +571,18 @@ Example:: ...@@ -544,15 +571,18 @@ Example::
}); });
getBuddy "contacts" grouping
-------- -------------------
get
~~~
Returns a map of attributes for a given buddy (i.e. roster contact), specified Returns a map of attributes for a given buddy (i.e. roster contact), specified
by JID (Jabber ID). by JID (Jabber ID).
Example:: Example::
converse.getBuddy('buddy@example.com') converse.contacts.get('buddy@example.com')
The map of attributes: The map of attributes:
...@@ -590,17 +620,19 @@ The map of attributes: ...@@ -590,17 +620,19 @@ The map of attributes:
| vcard_updated | When last the buddy's VCard was updated. | | vcard_updated | When last the buddy's VCard was updated. |
+----------------+--------------------------------------------------------------------------------------------------------------------------------------+ +----------------+--------------------------------------------------------------------------------------------------------------------------------------+
getChatBox "chats" grouping
---------- ----------------
get
~~~
Returns an object/map representing a chat box (without opening or affecting that chat box). Returns an object/map representing a chat box (without opening or affecting that chat box).
Example:: Example::
converse.getChatBox('buddy@example.com') converse.chats.get('buddy@example.com')
The returned chat box contains the following methods: *The returned chat box contains the following methods:*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------+------------------------------------------+ +-------------+------------------------------------------+
| Method | Description | | Method | Description |
...@@ -618,8 +650,7 @@ The returned chat box contains the following methods: ...@@ -618,8 +650,7 @@ The returned chat box contains the following methods:
| set | Set an attribute (i.e. mutator). | | set | Set an attribute (i.e. mutator). |
+-------------+------------------------------------------+ +-------------+------------------------------------------+
The get and set methods can be used to retrieve and change the following attributes: *The get and set methods can be used to retrieve and change the following attributes:*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------+-----------------------------------------------------+ +-------------+-----------------------------------------------------+
| Attribute | Description | | Attribute | Description |
...@@ -629,39 +660,25 @@ The get and set methods can be used to retrieve and change the following attribu ...@@ -629,39 +660,25 @@ The get and set methods can be used to retrieve and change the following attribu
| url | The URL of the chat box heading. | | url | The URL of the chat box heading. |
+-------------+-----------------------------------------------------+ +-------------+-----------------------------------------------------+
getRID "tokens" grouping
------ -----------------
Returns the current RID (request ID) value.
getSID
------
Returns the current SID (Session ID) value. get
~~~
openChatBox Returns a token, either the RID or SID token depending on what's asked for.
-----------
Opens a chat box and returns an object/map representating that chat box.
If the chat box is already open, its text area will be focused.
Example:: Example::
converse.openChatBox('buddy@example.com') converse.tokens.get('rid')
Refer to `getChatBox`_ for more information on the object returned by this
method (which is the same for both).
"listen" grouping
Events -----------------
======
Converse.js emits events to which you can subscribe from your own Javascript. Converse.js emits events to which you can subscribe from your own Javascript.
Concerning events, the following methods are available: Concerning events, the following methods are available under the "listen"
grouping:
Event API Methods
-----------------
* **on(eventName, callback)**: * **on(eventName, callback)**:
...@@ -676,7 +693,7 @@ Event API Methods ...@@ -676,7 +693,7 @@ Event API Methods
For example:: For example::
converse.on('message', function (messageXML) { ... }); converse.listen.on('message', function (messageXML) { ... });
* **once(eventName, callback)**: * **once(eventName, callback)**:
...@@ -690,17 +707,25 @@ Event API Methods ...@@ -690,17 +707,25 @@ Event API Methods
For example:: For example::
converse.once('message', function (messageXML) { ... }); converse.listen.once('message', function (messageXML) { ... });
* **off(eventName, callback)** * **not(eventName, callback)**
To stop listening to an event, you can use the ``off`` method. To stop listening to an event, you can use the ``not`` method.
Parameters: Parameters:
* ``eventName`` is the event name as a string. * ``eventName`` is the event name as a string.
* ``callback`` refers to the function that is to be no longer executed. * ``callback`` refers to the function that is to be no longer executed.
For example::
converse.listen.not('message', function (messageXML) { ... });
Events
======
.. note:: see also the `"listen" grouping`_ API section above.
Event Types Event Types
----------- -----------
...@@ -750,7 +775,6 @@ Here are the different events that are emitted: ...@@ -750,7 +775,6 @@ Here are the different events that are emitted:
+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+ +--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+
Minification Minification
============ ============
......
...@@ -10,82 +10,130 @@ ...@@ -10,82 +10,130 @@
} (this, function ($, mock, test_utils) { } (this, function ($, mock, test_utils) {
return describe("Converse", $.proxy(function(mock, test_utils) { return describe("Converse", $.proxy(function(mock, test_utils) {
beforeEach($.proxy(function () { describe("The \"tokens\" API", $.proxy(function () {
test_utils.closeAllChatBoxes(); beforeEach($.proxy(function () {
test_utils.clearBrowserStorage(); test_utils.closeAllChatBoxes();
converse.rosterview.model.reset(); test_utils.clearBrowserStorage();
test_utils.createContacts('current'); converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
it("has a method for retrieving the next RID", $.proxy(function () {
var old_connection = converse.connection;
converse.connection._proto.rid = '1234';
converse.expose_rid_and_sid = false;
expect(converse_api.tokens.get('rid')).toBe(null);
converse.expose_rid_and_sid = true;
expect(converse_api.tokens.get('rid')).toBe('1234');
converse.connection = undefined;
expect(converse_api.tokens.get('rid')).toBe(null);
// Restore the connection
converse.connection = old_connection;
}, converse));
it("has a method for retrieving the SID", $.proxy(function () {
var old_connection = converse.connection;
converse.connection._proto.sid = '1234';
converse.expose_rid_and_sid = false;
expect(converse_api.tokens.get('sid')).toBe(null);
converse.expose_rid_and_sid = true;
expect(converse_api.tokens.get('sid')).toBe('1234');
converse.connection = undefined;
expect(converse_api.tokens.get('sid')).toBe(null);
// Restore the connection
converse.connection = old_connection;
}, converse));
}, converse)); }, converse));
it("has an API method for retrieving the next RID", $.proxy(function () { describe("The \"contacts\" API", $.proxy(function () {
var old_connection = converse.connection; beforeEach($.proxy(function () {
converse.connection._proto.rid = '1234'; test_utils.closeAllChatBoxes();
converse.expose_rid_and_sid = false; test_utils.clearBrowserStorage();
expect(converse_api.getRID()).toBe(null); converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
converse.expose_rid_and_sid = true; it("has a method 'get' which returns a wrapped contact", $.proxy(function () {
expect(converse_api.getRID()).toBe('1234'); // TODO: test multiple JIDs passed in
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
expect(converse_api.contacts.get('non-existing@jabber.org')).toBeFalsy();
var attrs = converse_api.contacts.get(jid);
expect(typeof attrs).toBe('object');
expect(attrs.fullname).toBe(mock.cur_names[0]);
expect(attrs.jid).toBe(jid);
}, converse));
}, converse));
converse.connection = undefined; describe("The \"chats\" API", $.proxy(function() {
expect(converse_api.getRID()).toBe(null); beforeEach($.proxy(function () {
// Restore the connection test_utils.closeAllChatBoxes();
converse.connection = old_connection; test_utils.clearBrowserStorage();
converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
it("has a method 'get' which returns a wrapped chat box object", $.proxy(function () {
// TODO: test multiple JIDs passed in
// FIXME: when a non-existing chat box is "get(ted)", it's
// opened, which we don't want...
expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy(); // test on user that doesn't exist.
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var box = converse_api.chats.get(jid);
expect(box instanceof Object).toBeTruthy();
expect(box.get('box_id')).toBe(b64_sha1(jid));
var chatboxview = this.chatboxviews.get(jid);
expect(chatboxview.$el.is(':visible')).toBeTruthy();
}, converse));
}, converse)); }, converse));
it("has an API method for retrieving the SID", $.proxy(function () { describe("The DEPRECATED API", $.proxy(function() {
var old_connection = converse.connection; beforeEach($.proxy(function () {
converse.connection._proto.sid = '1234'; test_utils.closeAllChatBoxes();
converse.expose_rid_and_sid = false; test_utils.clearBrowserStorage();
expect(converse_api.getSID()).toBe(null); converse.rosterview.model.reset();
test_utils.createContacts('current');
}, converse));
converse.expose_rid_and_sid = true; it("has a method for retrieving the next RID", $.proxy(function () {
expect(converse_api.getSID()).toBe('1234'); var old_connection = converse.connection;
converse.connection._proto.rid = '1234';
converse.expose_rid_and_sid = false;
expect(converse_api.getRID()).toBe(null);
converse.connection = undefined; converse.expose_rid_and_sid = true;
expect(converse_api.getSID()).toBe(null); expect(converse_api.getRID()).toBe('1234');
// Restore the connection
converse.connection = old_connection;
}, converse));
it("has an API method for retrieving a buddy's attributes", $.proxy(function () { converse.connection = undefined;
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; expect(converse_api.getRID()).toBe(null);
expect(converse_api.getBuddy('non-existing@jabber.org')).toBeFalsy(); // Restore the connection
var attrs = converse_api.getBuddy(jid); converse.connection = old_connection;
expect(typeof attrs).toBe('object'); }, converse));
expect(attrs.fullname).toBe(mock.cur_names[0]);
expect(attrs.jid).toBe(jid);
}, converse));
it("has an API method, openChatBox, for opening a chat box for a buddy", $.proxy(function () { it("has a method for retrieving the SID", $.proxy(function () {
expect(converse_api.openChatBox('non-existing@jabber.org')).toBeFalsy(); // test on user that doesn't exist. var old_connection = converse.connection;
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; converse.connection._proto.sid = '1234';
var box = converse_api.openChatBox(jid); converse.expose_rid_and_sid = false;
expect(box instanceof Object).toBeTruthy(); expect(converse_api.getSID()).toBe(null);
expect(box.get('box_id')).toBe(b64_sha1(jid));
var chatboxview = this.chatboxviews.get(jid);
expect(chatboxview.$el.is(':visible')).toBeTruthy();
}, converse));
it("will focus an already open chat box, if the openChatBox API method is called for it.", $.proxy(function () { converse.expose_rid_and_sid = true;
// Calling openChatBox on an already open chat will focus it. expect(converse_api.getSID()).toBe('1234');
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
var chatboxview = this.chatboxviews.get(jid);
spyOn(chatboxview, 'focus');
test_utils.openChatBoxFor(jid);
box = converse_api.openChatBox(jid);
expect(chatboxview.focus).toHaveBeenCalled();
expect(box.get('box_id')).toBe(b64_sha1(jid));
}, converse)); converse.connection = undefined;
expect(converse_api.getSID()).toBe(null);
// Restore the connection
converse.connection = old_connection;
}, converse));
it("has an API method, getChatBox, for retrieving chat box", $.proxy(function () { it("has a method for retrieving a buddy's attributes", $.proxy(function () {
var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost'; var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
expect(converse_api.getChatBox(jid)).toBeFalsy(); expect(converse_api.getBuddy('non-existing@jabber.org')).toBeFalsy();
test_utils.openChatBoxFor(jid); var attrs = converse_api.getBuddy(jid);
var box = converse_api.getChatBox(jid); expect(typeof attrs).toBe('object');
expect(box instanceof Object).toBeTruthy(); expect(attrs.fullname).toBe(mock.cur_names[0]);
expect(box.get('box_id')).toBe(b64_sha1(jid)); expect(attrs.jid).toBe(jid);
}, converse));
}, converse)); }, converse));
}, converse, mock, test_utils)); }, converse, mock, test_utils));
})); }));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment