Explorar el Código

Split API into public and private (plugin only) parts.

JC Brand hace 8 años
padre
commit
4dcb855562

+ 2 - 4
docs/CHANGES.md

@@ -1,14 +1,12 @@
 # Changelog
 
 ## 3.0.0 (Unreleased)
-- Use lodash instead of underscore.js [jcbrand]
 - Case insensitive matching of moderation commands. [jcbrand]
 - Add `/subject` as alias to `/topic` [jcbrand]
 - `allow_chat_pending_contacts` now defaults to `true` [jcbrand]
-- Breaking change: Callbacks for `converse.on` now no longer receive an event
+- *Breaking change*: Callbacks for `converse.on` now no longer receive an event
   object as first parameter. [jcbrand]
-- Cancel button shown while the registration form is being fetched wasn't working
-  properly. [jcbrand]
+- Use lodash instead of underscore.js [jcbrand]
 
 ## 2.0.5 (Unreleased)
 - #743, #751, #753 Update to Strophe 1.2.12. SASL-EXTERNAL now has reduced priority, so it won't

+ 16 - 7
docs/source/developer_api.rst

@@ -12,17 +12,27 @@ The converse.js developer API
 .. 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, such as::
+.. note:: From version 3.0.0 and onwards many API methods have been made
+        private and available to plugins only. This means that if you want to
+        use the API, you'll first need to create a plugin from which you can
+        access it. This change is done to avoid leakage of sensitive data to
+        malicious or non-whitelisted scripts.
+
+The Converse.js API is broken up into different logical "groupings" (for
+example ``converse.plugins`` or ``converse.contacts``).
+
+The one exception, is ``converse.initialize``, which is not a grouping, but a
+single method.
+
+The groupings logically group methods, such as standardised accessors and
+mutators::
 
     .get
     .set
     .add
     .remove
 
-This is done to increase readability and to allow intuitive method chaining.
-
-For example, to get a contact, you would do the following::
+So for example, to get a contact, you would do the following::
 
     converse.contacts.get('jid@example.com');
 
@@ -41,8 +51,7 @@ To get all contacts, simply call ``get`` without any jids::
 initialize
 ----------
 
-.. note:: This method is the one exception of a method which is not logically grouped
-    as explained above.
+.. 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
 converse.js.

+ 3 - 31
spec/bookmarks.js

@@ -14,12 +14,6 @@
 
     describe("A chat room", function () {
 
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
-
         it("can be bookmarked", mock.initConverse(function (converse) {
             var sent_stanza, IQ_id;
             var sendIQ = converse.connection.sendIQ;
@@ -151,12 +145,6 @@
 
         describe("when bookmarked", function () {
 
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
-
             it("displays that it's bookmarked through its bookmark icon", mock.initConverse(function (converse) {
                 runs(function () {
                     test_utils.openChatRoom(converse, 'lounge', 'localhost', 'dummy');
@@ -241,14 +229,9 @@
         });
 
         describe("and when autojoin is set", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("will be be opened and joined automatically upon login", mock.initConverse(function (converse) {
-                spyOn(converse_api.rooms, 'open');
+                spyOn(converse.api.rooms, 'open');
                 var jid = 'theplay@conference.shakespeare.lit';
                 var model = converse.bookmarks.create({
                     'jid': jid,
@@ -256,7 +239,7 @@
                     'name':  'The Play',
                     'nick': ''
                 });
-                expect(converse_api.rooms.open).not.toHaveBeenCalled();
+                expect(converse.api.rooms.open).not.toHaveBeenCalled();
                 converse.bookmarks.remove(model);
 
                 converse.bookmarks.create({
@@ -265,19 +248,13 @@
                     'name':  'Hamlet',
                     'nick': ''
                 });
-                expect(converse_api.rooms.open).toHaveBeenCalled();
+                expect(converse.api.rooms.open).toHaveBeenCalled();
             }));
         });
     });
 
     describe("Bookmarks", function () {
 
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
-
         it("can be pushed from the XMPP server", mock.initConverse(function (converse) {
             // TODO
             /* The stored data is automatically pushed to all of the user's
@@ -395,11 +372,6 @@
         }));
 
         describe("The rooms panel", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("shows a list of bookmarks", mock.initConverse(function (converse) {
                 var IQ_id;

+ 1 - 61
spec/chatbox.js

@@ -15,11 +15,6 @@
 
     return describe("Chatboxes", function() {
         describe("A Chatbox", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("is created when you click on a roster item", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'current');
@@ -277,11 +272,6 @@
             }));
 
             describe("A chat toolbar", function () {
-                afterEach(function () {
-                    converse_api.user.logout();
-                    converse_api.listen.not();
-                    test_utils.clearBrowserStorage();
-                });
 
                 it("can be found on each chat box", mock.initConverse(function (converse) {
                     test_utils.createContacts(converse, 'current');
@@ -452,11 +442,6 @@
             });
 
             describe("A Chat Message", function () {
-                afterEach(function () {
-                    converse_api.user.logout();
-                    converse_api.listen.not();
-                    test_utils.clearBrowserStorage();
-                });
 
                 describe("when received from someone else", function () {
                     it("can be received which will open a chatbox and be displayed inside it", mock.initConverse(function (converse) {
@@ -564,11 +549,6 @@
                     });
 
                     describe("and for which then an error message is received from the server", function () {
-                        afterEach(function () {
-                            converse_api.user.logout();
-                            converse_api.listen.not();
-                            test_utils.clearBrowserStorage();
-                        });
 
                         it("will have the error message displayed after itself", mock.initConverse(function (converse) {
                             test_utils.createContacts(converse, 'current');
@@ -593,7 +573,7 @@
                             var sender_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
                             var fullname = converse.xmppstatus.get('fullname');
                             fullname = _.isEmpty(fullname)? converse.bare_jid: fullname;
-                            converse_api.chats.open(sender_jid);
+                            converse.api.chats.open(sender_jid);
                             var msg_text = 'This message will not be sent, due to an error';
                             var view = converse.chatboxviews.get(sender_jid);
                             var message = view.model.messages.create({
@@ -1237,11 +1217,6 @@
             });
 
             describe("A Chat Status Notification", function () {
-                afterEach(function () {
-                    converse_api.user.logout();
-                    converse_api.listen.not();
-                    test_utils.clearBrowserStorage();
-                });
 
                 it("does not open automatically if a chat state notification is received", mock.initConverse(function (converse) {
                     test_utils.createContacts(converse, 'current');
@@ -1262,11 +1237,6 @@
                 }));
 
                 describe("An active notification", function () {
-                    afterEach(function () {
-                        converse_api.user.logout();
-                        converse_api.listen.not();
-                        test_utils.clearBrowserStorage();
-                    });
 
                     it("is sent when the user opens a chat box", mock.initConverse(function (converse) {
                         test_utils.createContacts(converse, 'current');
@@ -1319,11 +1289,6 @@
                 });
 
                 describe("A composing notification", function () {
-                    afterEach(function () {
-                        converse_api.user.logout();
-                        converse_api.listen.not();
-                        test_utils.clearBrowserStorage();
-                    });
 
                     it("is sent as soon as the user starts typing a message which is not a command", mock.initConverse(function (converse) {
                         test_utils.createContacts(converse, 'current');
@@ -1386,11 +1351,6 @@
                 });
 
                 describe("A paused notification", function () {
-                    afterEach(function () {
-                        converse_api.user.logout();
-                        converse_api.listen.not();
-                        test_utils.clearBrowserStorage();
-                    });
 
                     it("is sent if the user has stopped typing since 30 seconds", mock.initConverse(function (converse) {
                         test_utils.createContacts(converse, 'current');
@@ -1475,11 +1435,6 @@
                 });
 
                 describe("An inactive notifciation", function () {
-                    afterEach(function () {
-                        converse_api.user.logout();
-                        converse_api.listen.not();
-                        test_utils.clearBrowserStorage();
-                    });
 
                     it("is sent if the user has stopped typing since 2 minutes", mock.initConverse(function (converse) {
                         test_utils.createContacts(converse, 'current');
@@ -1587,11 +1542,6 @@
                 });
 
                 describe("A gone notifciation", function () {
-                    afterEach(function () {
-                        converse_api.user.logout();
-                        converse_api.listen.not();
-                        test_utils.clearBrowserStorage();
-                    });
 
                     it("will be shown if received", mock.initConverse(function (converse) {
                         test_utils.createContacts(converse, 'current');
@@ -1618,11 +1568,6 @@
         });
 
         describe("Special Messages", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("'/clear' can be used to clear messages in a conversation", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'current');
@@ -1659,11 +1604,6 @@
         });
 
         describe("A Message Counter", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("is incremented when the message is received and the window is not focused", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'current');

+ 17 - 37
spec/chatroom.js

@@ -10,11 +10,6 @@
 
     return describe("ChatRooms", function () {
         describe("The \"rooms\" API", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'current');
@@ -28,11 +23,11 @@
                 });
                 waits('100');
                 runs(function () {
-                    converse_api.rooms.close('lounge@localhost');
+                    converse.api.rooms.close('lounge@localhost');
                     expect(converse.chatboxviews.get('lounge@localhost')).toBeUndefined();
                     expect(converse.chatboxviews.get('leisure@localhost').$el.is(':visible')).toBeTruthy();
                     expect(converse.chatboxviews.get('news@localhost').$el.is(':visible')).toBeTruthy();
-                    converse_api.rooms.close(['leisure@localhost', 'news@localhost']);
+                    converse.api.rooms.close(['leisure@localhost', 'news@localhost']);
                     expect(converse.chatboxviews.get('lounge@localhost')).toBeUndefined();
                     expect(converse.chatboxviews.get('leisure@localhost')).toBeUndefined();
                     expect(converse.chatboxviews.get('news@localhost')).toBeUndefined();
@@ -44,7 +39,7 @@
                 });
                 waits('100');
                 runs(function () {
-                    converse_api.rooms.close();
+                    converse.api.rooms.close();
                     expect(converse.chatboxviews.get('lounge@localhost')).toBeUndefined();
                     expect(converse.chatboxviews.get('leisure@localhost')).toBeUndefined();
                 });
@@ -56,7 +51,7 @@
                 runs(function () {
                     test_utils.openChatRoom(converse, 'lounge', 'localhost', 'dummy');
                     var jid = 'lounge@localhost';
-                    var room = converse_api.rooms.get(jid);
+                    var room = converse.api.rooms.get(jid);
                     expect(room instanceof Object).toBeTruthy();
                     expect(room.is_chatroom).toBeTruthy();
                     var chatroomview = converse.chatboxviews.get(jid);
@@ -68,7 +63,7 @@
                     // Test with mixed case
                     test_utils.openChatRoom(converse, 'Leisure', 'localhost', 'dummy');
                     var jid = 'Leisure@localhost';
-                    var room = converse_api.rooms.get(jid);
+                    var room = converse.api.rooms.get(jid);
                     expect(room instanceof Object).toBeTruthy();
                     var chatroomview = converse.chatboxviews.get(jid.toLowerCase());
                     expect(chatroomview.$el.is(':visible')).toBeTruthy();
@@ -76,13 +71,13 @@
                 waits('300'); // ChatBox.show() is debounced for 250ms
                 runs(function () {
                     var jid = 'leisure@localhost';
-                    var room = converse_api.rooms.get(jid);
+                    var room = converse.api.rooms.get(jid);
                     expect(room instanceof Object).toBeTruthy();
                     var chatroomview = converse.chatboxviews.get(jid.toLowerCase());
                     expect(chatroomview.$el.is(':visible')).toBeTruthy();
 
                     jid = 'leiSure@localhost';
-                    room = converse_api.rooms.get(jid);
+                    room = converse.api.rooms.get(jid);
                     expect(room instanceof Object).toBeTruthy();
                     chatroomview = converse.chatboxviews.get(jid.toLowerCase());
                     expect(chatroomview.$el.is(':visible')).toBeTruthy();
@@ -90,7 +85,7 @@
 
                     // Non-existing room
                     jid = 'lounge2@localhost';
-                    room = converse_api.rooms.get(jid);
+                    room = converse.api.rooms.get(jid);
                     expect(typeof room === 'undefined').toBeTruthy();
                 });
             }));
@@ -99,7 +94,7 @@
                 test_utils.createContacts(converse, 'current');
                 var chatroomview;
                 var jid = 'lounge@localhost';
-                var room = converse_api.rooms.open(jid);
+                var room = converse.api.rooms.open(jid);
                 runs(function () {
                     // Test on chat room that doesn't exist.
                     expect(room instanceof Object).toBeTruthy();
@@ -110,7 +105,7 @@
                 waits('300'); // ChatBox.show() is debounced for 250ms
                 runs(function () {
                     // Test again, now that the room exists.
-                    room = converse_api.rooms.open(jid);
+                    room = converse.api.rooms.open(jid);
                     expect(room instanceof Object).toBeTruthy();
                     expect(room.is_chatroom).toBeTruthy();
                     chatroomview = converse.chatboxviews.get(jid);
@@ -120,19 +115,19 @@
                 runs(function () {
                     // Test with mixed case in JID
                     jid = 'Leisure@localhost';
-                    room = converse_api.rooms.open(jid);
+                    room = converse.api.rooms.open(jid);
                     expect(room instanceof Object).toBeTruthy();
                     chatroomview = converse.chatboxviews.get(jid.toLowerCase());
                     expect(chatroomview.$el.is(':visible')).toBeTruthy();
 
                     jid = 'leisure@localhost';
-                    room = converse_api.rooms.open(jid);
+                    room = converse.api.rooms.open(jid);
                     expect(room instanceof Object).toBeTruthy();
                     chatroomview = converse.chatboxviews.get(jid.toLowerCase());
                     expect(chatroomview.$el.is(':visible')).toBeTruthy();
 
                     jid = 'leiSure@localhost';
-                    room = converse_api.rooms.open(jid);
+                    room = converse.api.rooms.open(jid);
                     expect(room instanceof Object).toBeTruthy();
                     chatroomview = converse.chatboxviews.get(jid.toLowerCase());
                     expect(chatroomview.$el.is(':visible')).toBeTruthy();
@@ -148,7 +143,7 @@
                         IQ_id = sendIQ.bind(this)(iq, callback, errback);
                     });
                     // Test with configuration
-                    converse_api.rooms.open('room@conference.example.org', {
+                    converse.api.rooms.open('room@conference.example.org', {
                         'nick': 'some1',
                         'auto_configure': true,
                         'roomconfig': {
@@ -241,11 +236,6 @@
         });
 
         describe("A Chat Room", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("can have spaces and special characters in its name", mock.initConverse(function (converse) {
                 test_utils.openChatRoom(converse, 'lounge & leisure', 'localhost', 'dummy');
@@ -263,7 +253,7 @@
                     IQ_id = sendIQ.bind(this)(iq, callback, errback);
                 });
                 runs(function () {
-                    converse_api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
+                    converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
                     view = converse.chatboxviews.get('coven@chat.shakespeare.lit');
                     spyOn(view, 'saveAffiliationAndRole').andCallThrough();
 
@@ -915,7 +905,7 @@
                     IQ_id = sendIQ.bind(this)(iq, callback, errback);
                 });
 
-                converse_api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
+                converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
 
                 // Check that the room queried for the feautures.
                 expect(sent_IQ.toLocaleString()).toBe(
@@ -980,7 +970,7 @@
                     sent_IQ = iq;
                     IQ_id = sendIQ.bind(this)(iq, callback, errback);
                 });
-                converse_api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
+                converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
 
                 // We pretend this is a new room, so no disco info is returned.
                 var features_stanza = $iq({
@@ -1145,11 +1135,6 @@
 
 
         describe("Each chat room can take special commands", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("to set the room subject", mock.initConverse(function (converse) {
                 var sent_stanza;
@@ -1284,11 +1269,6 @@
         });
 
         describe("When attempting to enter a chatroom", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             var submitRoomForm = function (converse) {
                 var roomspanel = converse.chatboxviews.get('controlbox').roomspanel;

+ 0 - 56
spec/controlbox.js

@@ -23,11 +23,6 @@
     };
 
     describe("The Control Box", function () {
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
 
         it("can be opened by clicking a DOM element with class 'toggle-controlbox'", mock.initConverse(function (converse) {
             runs(function () {
@@ -51,11 +46,6 @@
         }));
 
         describe("The Status Widget", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("shows the user's chat status, which is online by default", mock.initConverse(function (converse) {
                 test_utils.openControlBox();
@@ -123,11 +113,6 @@
     describe("The Contacts Roster", function () {
 
         describe("The live filter", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("will only appear when roster contacts flow over the visible area", mock.initConverse(function (converse) {
                 var $filter = converse.rosterview.$('.roster-filter');
@@ -332,11 +317,6 @@
         });
 
         describe("A Roster Group", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("can be used to organize existing contacts", mock.initConverse(function (converse) {
                 runs(function () {
@@ -432,11 +412,6 @@
         });
 
         describe("Pending Contacts", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             function _addContacts (converse) {
                 // Must be initialized, so that render is called and documentFragment set up.
@@ -600,12 +575,6 @@
                 test_utils.createContacts(converse, 'current').openControlBox().openContactsPanel(converse);
             };
 
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
-
             it("can be collapsed under their own header", mock.initConverse(function (converse) {
                 runs(function () {
                     _addContacts(converse);
@@ -897,11 +866,6 @@
         });
 
         describe("Requesting Contacts", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("can be added to the roster and they will be sorted alphabetically", mock.initConverse(function (converse) {
                 var i, children;
@@ -1062,11 +1026,6 @@
         });
 
         describe("All Contacts", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("are saved to, and can be retrieved from browserStorage", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'all').openControlBox();
@@ -1117,11 +1076,6 @@
     });
 
     describe("The 'Add Contact' widget", function () {
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
 
         it("opens up an add form when you click on it", mock.initConverse(function (converse) {
             var panel = converse.chatboxviews.get('controlbox').contactspanel;
@@ -1135,11 +1089,6 @@
     });
 
     describe("The Controlbox Tabs", function () {
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
 
         it("contains two tabs, 'Contacts' and 'ChatRooms'", mock.initConverse(function (converse) {
             test_utils.openControlBox();
@@ -1164,11 +1113,6 @@
         }));
 
         describe("chatrooms panel", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
             it("is opened by clicking the 'Chatrooms' tab", mock.initConverse(function (converse) {
                 test_utils.openControlBox();

+ 31 - 37
spec/converse.js

@@ -10,12 +10,6 @@
 
     describe("Converse", function() {
         
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
-
         describe("Authentication", function () {
             it("needs either a bosh_service_url a websocket_url or both", mock.initConverse(function (converse) {
                 var url = converse.bosh_service_url;
@@ -133,41 +127,41 @@
 
                 it("has a method for getting the user's availability", mock.initConverse(function (converse) {
                     converse.xmppstatus.set('status', 'online');
-                    expect(converse_api.user.status.get()).toBe('online');
+                    expect(converse.api.user.status.get()).toBe('online');
                     converse.xmppstatus.set('status', 'dnd');
-                    expect(converse_api.user.status.get()).toBe('dnd');
+                    expect(converse.api.user.status.get()).toBe('dnd');
                 }));
 
                 it("has a method for setting the user's availability", mock.initConverse(function (converse) {
-                    converse_api.user.status.set('away');
+                    converse.api.user.status.set('away');
                     expect(converse.xmppstatus.get('status')).toBe('away');
-                    converse_api.user.status.set('dnd');
+                    converse.api.user.status.set('dnd');
                     expect(converse.xmppstatus.get('status')).toBe('dnd');
-                    converse_api.user.status.set('xa');
+                    converse.api.user.status.set('xa');
                     expect(converse.xmppstatus.get('status')).toBe('xa');
-                    converse_api.user.status.set('chat');
+                    converse.api.user.status.set('chat');
                     expect(converse.xmppstatus.get('status')).toBe('chat');
-                    expect(_.partial(converse_api.user.status.set, 'invalid')).toThrow(
+                    expect(_.partial(converse.api.user.status.set, 'invalid')).toThrow(
                         new Error('Invalid availability value. See https://xmpp.org/rfcs/rfc3921.html#rfc.section.2.2.2.1')
                     );
                 }));
 
                 it("allows setting the status message as well", mock.initConverse(function (converse) {
-                    converse_api.user.status.set('away', "I'm in a meeting");
+                    converse.api.user.status.set('away', "I'm in a meeting");
                     expect(converse.xmppstatus.get('status')).toBe('away');
                     expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
                 }));
 
                 it("has a method for getting the user's status message", mock.initConverse(function (converse) {
                     converse.xmppstatus.set('status_message', undefined);
-                    expect(converse_api.user.status.message.get()).toBe(undefined);
+                    expect(converse.api.user.status.message.get()).toBe(undefined);
                     converse.xmppstatus.set('status_message', "I'm in a meeting");
-                    expect(converse_api.user.status.message.get()).toBe("I'm in a meeting");
+                    expect(converse.api.user.status.message.get()).toBe("I'm in a meeting");
                 }));
 
                 it("has a method for setting the user's status message", mock.initConverse(function (converse) {
                     converse.xmppstatus.set('status_message', undefined);
-                    converse_api.user.status.message.set("I'm in a meeting");
+                    converse.api.user.status.message.set("I'm in a meeting");
                     expect(converse.xmppstatus.get('status_message')).toBe("I'm in a meeting");
                 }));
             });
@@ -180,11 +174,11 @@
                 var old_connection = converse.connection;
                 converse.connection._proto.rid = '1234';
                 converse.expose_rid_and_sid = false;
-                expect(converse_api.tokens.get('rid')).toBe(null);
+                expect(converse.api.tokens.get('rid')).toBe(null);
                 converse.expose_rid_and_sid = true;
-                expect(converse_api.tokens.get('rid')).toBe('1234');
+                expect(converse.api.tokens.get('rid')).toBe('1234');
                 converse.connection = undefined;
-                expect(converse_api.tokens.get('rid')).toBe(null);
+                expect(converse.api.tokens.get('rid')).toBe(null);
                 // Restore the connection
                 converse.connection = old_connection;
             }));
@@ -194,11 +188,11 @@
                 var old_connection = converse.connection;
                 converse.connection._proto.sid = '1234';
                 converse.expose_rid_and_sid = false;
-                expect(converse_api.tokens.get('sid')).toBe(null);
+                expect(converse.api.tokens.get('sid')).toBe(null);
                 converse.expose_rid_and_sid = true;
-                expect(converse_api.tokens.get('sid')).toBe('1234');
+                expect(converse.api.tokens.get('sid')).toBe('1234');
                 converse.connection = undefined;
-                expect(converse_api.tokens.get('sid')).toBe(null);
+                expect(converse.api.tokens.get('sid')).toBe(null);
                 // Restore the connection
                 converse.connection = old_connection;
             }));
@@ -209,10 +203,10 @@
             it("has a method 'get' which returns wrapped contacts", mock.initConverse(function (converse) {
                 // Check that it returns nothing if a non-existing JID is given
                 test_utils.createContacts(converse, 'current');
-                expect(converse_api.contacts.get('non-existing@jabber.org')).toBeFalsy();
+                expect(converse.api.contacts.get('non-existing@jabber.org')).toBeFalsy();
                 // Check when a single jid is given
                 var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
-                var attrs = converse_api.contacts.get(jid);
+                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);
@@ -223,17 +217,17 @@
                 expect(list[0].fullname).toBe(mock.cur_names[0]);
                 expect(list[1].fullname).toBe(mock.cur_names[1]);
                 // Check that all JIDs are returned if you call without any parameters
-                list = converse_api.contacts.get();
+                list = converse.api.contacts.get();
                 expect(list.length).toBe(mock.cur_names.length);
             }));
 
             it("has a method 'add' with which contacts can be added", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'current');
                 var error = new TypeError('contacts.add: invalid jid');
-                expect(converse_api.contacts.add).toThrow(error);
-                expect(converse_api.contacts.add.bind(converse_api, "invalid jid")).toThrow(error);
+                expect(converse.api.contacts.add).toThrow(error);
+                expect(converse.api.contacts.add.bind(converse.api, "invalid jid")).toThrow(error);
                 spyOn(converse.roster, 'addAndSubscribe');
-                converse_api.contacts.add("newcontact@example.org");
+                converse.api.contacts.add("newcontact@example.org");
                 expect(converse.roster.addAndSubscribe).toHaveBeenCalled();
             }));
         });
@@ -243,17 +237,17 @@
             it("has a method 'get' which returns a wrapped chat box", mock.initConverse(function (converse) {
                 test_utils.createContacts(converse, 'current');
                 // Test on chat that doesn't exist.
-                expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy();
+                expect(converse.api.chats.get('non-existing@jabber.org')).toBeFalsy();
                 var jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
 
                 // Test on chat that's not open
-                var box = converse_api.chats.get(jid);
+                var box = converse.api.chats.get(jid);
                 expect(typeof box === 'undefined').toBeTruthy();
 
                 var chatboxview = converse.chatboxviews.get(jid);
                 // Test for single JID
                 test_utils.openChatBoxFor(converse, jid);
-                box = converse_api.chats.get(jid);
+                box = converse.api.chats.get(jid);
                 expect(box instanceof Object).toBeTruthy();
                 expect(box.get('box_id')).toBe(b64_sha1(jid));
                 chatboxview = converse.chatboxviews.get(jid);
@@ -274,8 +268,8 @@
                 waits('300'); // ChatBox.show() is debounced for 250ms
                 runs(function () {
                     // Test on chat that doesn't exist.
-                    expect(converse_api.chats.get('non-existing@jabber.org')).toBeFalsy();
-                    var box = converse_api.chats.open(jid);
+                    expect(converse.api.chats.get('non-existing@jabber.org')).toBeFalsy();
+                    var box = converse.api.chats.open(jid);
                     expect(box instanceof Object).toBeTruthy();
                     expect(box.get('box_id')).toBe(b64_sha1(jid));
                     expect(
@@ -303,9 +297,9 @@
                 converse_api.settings.set({"play_sounds": false});
                 expect(converse_api.settings.get("play_sounds")).toBe(false);
                 // Only whitelisted settings allowed.
-                expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
-                converse_api.settings.set("non_existing", true);
-                expect(typeof converse_api.settings.get("non_existing")).toBe("undefined");
+                expect(typeof converse.api.settings.get("non_existing")).toBe("undefined");
+                converse.api.settings.set("non_existing", true);
+                expect(typeof converse.api.settings.get("non_existing")).toBe("undefined");
             }));
         });
     });

+ 0 - 5
spec/disco.js

@@ -11,11 +11,6 @@
     describe("Service Discovery", function () {
 
         describe("Whenever converse.js discovers a new server feature", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
 
            it("emits the serviceDiscovered event", mock.initConverse(function (converse) {
                 spyOn(converse, 'emit');

+ 0 - 5
spec/headline.js

@@ -13,11 +13,6 @@
 
     describe("A headlines box", function () {
 
-        afterEach(function () {
-            converse_api.user.logout();
-            test_utils.clearBrowserStorage();
-        });
-
         it("will not open nor display non-headline messages", mock.initConverse(function (converse) {
             /* XMPP spam message:
              *

+ 10 - 22
spec/mam.js

@@ -15,12 +15,6 @@
 
         describe("The archive.query API", function () {
 
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
-
            it("can be used to query for all archived messages", mock.initConverse(function (converse) {
                 var sent_stanza, IQ_id;
                 var sendIQ = converse.connection.sendIQ;
@@ -31,7 +25,7 @@
                 if (!converse.features.findWhere({'var': Strophe.NS.MAM})) {
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
-                converse_api.archive.query();
+                converse.api.archive.query();
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'><query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'/></iq>");
@@ -47,7 +41,7 @@
                 if (!converse.features.findWhere({'var': Strophe.NS.MAM})) {
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
-                converse_api.archive.query({'with':'juliet@capulet.lit'});
+                converse.api.archive.query({'with':'juliet@capulet.lit'});
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
@@ -77,7 +71,7 @@
                 }
                 var start = '2010-06-07T00:00:00Z';
                 var end = '2010-07-07T13:23:54Z';
-                converse_api.archive.query({
+                converse.api.archive.query({
                     'start': start,
                     'end': end
 
@@ -106,7 +100,7 @@
                 if (!converse.features.findWhere({'var': Strophe.NS.MAM})) {
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
-                expect(_.partial(converse_api.archive.query, {'start': 'not a real date'})).toThrow(
+                expect(_.partial(converse.api.archive.query, {'start': 'not a real date'})).toThrow(
                     new TypeError('archive.query: invalid date provided for: start')
                 );
            }));
@@ -122,7 +116,7 @@
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
                 var start = '2010-06-07T00:00:00Z';
-                converse_api.archive.query({'start': start});
+                converse.api.archive.query({'start': start});
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
@@ -151,7 +145,7 @@
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
                 var start = '2010-06-07T00:00:00Z';
-                converse_api.archive.query({'start': start, 'max':10});
+                converse.api.archive.query({'start': start, 'max':10});
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
@@ -183,7 +177,7 @@
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
                 var start = '2010-06-07T00:00:00Z';
-                converse_api.archive.query({
+                converse.api.archive.query({
                     'start': start,
                     'after': '09af3-cc343-b409f',
                     'max':10
@@ -219,7 +213,7 @@
                 if (!converse.features.findWhere({'var': Strophe.NS.MAM})) {
                     converse.features.create({'var': Strophe.NS.MAM});
                 }
-                converse_api.archive.query({'before': '', 'max':10});
+                converse.api.archive.query({'before': '', 'max':10});
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
@@ -255,7 +249,7 @@
                 var rsm =  new Strophe.RSM({'max': '10'});
                 rsm['with'] = 'romeo@montague.lit';
                 rsm.start = '2010-06-07T00:00:00Z';
-                converse_api.archive.query(rsm);
+                converse.api.archive.query(rsm);
 
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
@@ -292,7 +286,7 @@
                 });
                 var callback = jasmine.createSpy('callback');
 
-                converse_api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback);
+                converse.api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback);
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
 
                 // Send the result stanza, so that the callback is called.
@@ -373,12 +367,6 @@
 
         describe("The default preference", function () {
 
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
-
             it("is set once server support for MAM has been confirmed", mock.initConverse(function (converse) {
                 var sent_stanza, IQ_id;
                 var sendIQ = converse.connection.sendIQ;

+ 0 - 6
spec/minchats.js

@@ -5,12 +5,6 @@
     var $msg = converse_api.env.$msg;
 
     describe("The Minimized Chats Widget", function () {
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
-
 
         it("shows chats that have been minimized",  mock.initConverse(function (converse) {
             test_utils.createContacts(converse, 'current');

+ 0 - 9
spec/notification.js

@@ -10,10 +10,6 @@
         describe("When show_desktop_notifications is set to true", function () {
             describe("And the desktop is not focused", function () {
                 describe("an HTML5 Notification", function () {
-                    afterEach(function () {
-                        converse_api.user.logout();
-                        test_utils.clearBrowserStorage();
-                    });
 
                     it("is shown when a new private message is received", mock.initConverse(function (converse) {
                         // TODO: not yet testing show_desktop_notifications setting
@@ -95,11 +91,6 @@
         describe("When play_sounds is set to true", function () {
             describe("A notification sound", function () {
 
-                afterEach(function () {
-                    converse_api.user.logout();
-                    test_utils.clearBrowserStorage();
-                });
-
                 it("is played when the current user is mentioned in a chat room", mock.initConverse(function (converse) {
                     test_utils.createContacts(converse, 'current');
                     test_utils.openAndEnterChatRoom(converse, 'lounge', 'localhost', 'dummy');

+ 1 - 5
spec/otr.js

@@ -6,10 +6,6 @@
     var b64_sha1 = converse_api.env.b64_sha1;
 
     return describe("The OTR module", function() {
-        afterEach(function () {
-            converse_api.user.logout();
-            test_utils.clearBrowserStorage();
-        });
 
         it("can store a session passphrase in session storage", mock.initConverse(function (converse) {
             // With no prebind, the user's XMPP password is used and nothing is
@@ -65,7 +61,7 @@
 
                 var msgtext = "?OTR,1,3,?OTR:AAIDAAAAAAEAAAABAAAAwCQ8HKsag0y0DGKsneo0kzKu1ua5L93M4UKTkCf1I2kbm2RgS5kIxDTxrTj3wVRB+H5Si86E1fKtuBgsDf/bKkGTM0h/49vh5lOD9HkE8cnSrFEn5GN,";
                 var sender_jid = mock.cur_names[3].replace(/ /g,'.').toLowerCase() + '@localhost';
-                converse_api.chats.open(sender_jid);
+                converse.api.chats.open(sender_jid);
                 var chatbox = converse.chatboxes.get(sender_jid);
                 spyOn(converse.connection, 'send');
                 chatbox.set('otr_status', 1); // Set OTR status to UNVERIFIED, to mock an encrypted session

+ 1 - 9
spec/ping.js

@@ -1,14 +1,10 @@
 (function (root, factory) {
     define(["mock", "converse-api", "test_utils", "converse-ping"], factory);
-} (this, function (mock, converse_api, test_utils) {
+} (this, function (mock, test_utils) {
     "use strict";
 
     describe("XMPP Ping", function () {
         describe("Ping and pong handlers", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                test_utils.clearBrowserStorage();
-            });
 
             it("are registered when converse.js is connected", mock.initConverse(function (converse) {
                 spyOn(converse, 'registerPingHandler').andCallThrough();
@@ -28,10 +24,6 @@
         });
 
         describe("An IQ stanza", function () {
-            afterEach(function () {
-                converse_api.user.logout();
-                test_utils.clearBrowserStorage();
-            });
 
             it("is sent out when converse.js pings a server", mock.initConverse(function (converse) {
                 var sent_stanza, IQ_id;

+ 0 - 6
spec/protocol.js

@@ -18,12 +18,6 @@
             // Stub the trimChat method. It causes havoc when running with
             // phantomJS.
 
-            afterEach(function () {
-                converse_api.user.logout();
-                converse_api.listen.not();
-                test_utils.clearBrowserStorage();
-            });
-
             /* Some level of integration between roster items and presence
              * subscriptions is normally expected by an instant messaging user
              * regarding the user's subscriptions to and from other contacts. This

+ 0 - 5
spec/register.js

@@ -6,11 +6,6 @@
     var $iq = converse_api.env.$iq;
 
     describe("The Registration Panel", function () {
-        afterEach(function () {
-            converse_api.user.logout();
-            converse_api.listen.not();
-            test_utils.clearBrowserStorage();
-        });
 
         it("is not available unless allow_registration=true",  mock.initConverse(function (converse) {
             runs(test_utils.openControlBox);

+ 0 - 4
spec/xmppstatus.js

@@ -4,10 +4,6 @@
     var $ = converse_api.env.jQuery;
 
     return describe("The XMPPStatus model", function() {
-        afterEach(function () {
-            converse_api.user.logout();
-            test_utils.clearBrowserStorage();
-        });
 
         it("won't send <show>online when setting a custom status message", mock.initConverse(function (converse) {
             converse.xmppstatus.save({'status': 'online'});

+ 11 - 30
src/converse-api.js

@@ -17,11 +17,9 @@
         factory);
 }(this, function ($, _, moment, strophe, utils, converse) {
     var Strophe = strophe.Strophe;
-    return {
-        'initialize': function (settings, callback) {
-            return converse.initialize(settings, callback);
-        },
-        'log': converse.log,
+
+    // API methods only available to plugins
+    converse.api = {
         'connection': {
             'connected': function () {
                 return converse.connection && converse.connection.connected || false;
@@ -185,38 +183,21 @@
         'send': function (stanza) {
             converse.connection.send(stanza);
         },
+    };
+
+    // The public API
+    return {
+        'initialize': function (settings, callback) {
+            return converse.initialize(settings, callback);
+        },
         'plugins': {
             'add': function (name, plugin) {
                 plugin.__name__ = name;
                 converse.pluggable.plugins[name] = plugin;
             },
             'remove': function (name) {
-                delete converse.plugins[name];
+                delete converse.pluggable.plugins[name];
             },
-            'override': function (name, value) {
-                /* Helper method for overriding methods and attributes directly on the
-                 * converse object. For Backbone objects, use instead the 'extend'
-                 * method.
-                 *
-                 * If a method is overridden, then the original method will still be
-                 * available via the __super__ attribute.
-                 *
-                 * name: The attribute being overridden.
-                 * value: The value of the attribute being overridden.
-                 */
-                converse._overrideAttribute(name, value);
-            },
-            'extend': 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
-                 */
-                converse._extendObject(obj, attributes);
-            }
         },
         'env': {
             '$build': strophe.$build,

+ 1 - 1
src/converse-bookmarks.js

@@ -220,7 +220,7 @@
 
                 openBookmarkedRoom: function (bookmark) {
                     if (bookmark.get('autojoin')) {
-                        converse_api.rooms.open(bookmark.get('jid'), bookmark.get('nick'));
+                        converse.api.rooms.open(bookmark.get('jid'), bookmark.get('nick'));
                     }
                     return bookmark;
                 },

+ 1 - 1
src/converse-mam.js

@@ -228,7 +228,7 @@
                 converse.connection.sendIQ(stanza, null, errback, converse.message_archiving_timeout);
             };
 
-            _.extend(converse_api, {
+            _.extend(converse.api, {
                 /* Extend default converse.js API to add methods specific to MAM
                  */
                 'archive': {

+ 3 - 3
src/converse-muc.js

@@ -1859,7 +1859,7 @@
                         return;
                     }
                     this.addSpinner();
-                    converse_api.archive.query(_.extend(options, {'groupchat': true}),
+                    converse.api.archive.query(_.extend(options, {'groupchat': true}),
                         function (messages) {
                             that.clearSpinner();
                             if (messages.length) {
@@ -2379,7 +2379,7 @@
                  */
                 _.each(converse.auto_join_rooms, function (room) {
                     if (_.isString(room)) {
-                        converse_api.rooms.open(room);
+                        converse.api.rooms.open(room);
                     } else if (_.isObject(room)) {
                         converse_api.rooms.open(room.jid, room.nick);
                     } else {
@@ -2404,7 +2404,7 @@
             /* We extend the default converse.js API to add methods specific to MUC
              * chat rooms.
              */
-            _.extend(converse_api, {
+            _.extend(converse.api, {
                 'rooms': {
                     'close': function (jids) {
                         if (_.isUndefined(jids)) {

+ 0 - 11
src/converse-ping.js

@@ -19,8 +19,6 @@
     "use strict";
     // Strophe methods for building stanzas
     var Strophe = converse_api.env.Strophe;
-    // Other necessary globals
-    var _ = converse_api.env._;
     
     converse_api.plugins.add('converse-ping', {
 
@@ -89,15 +87,6 @@
                 }
             };
 
-            _.extend(converse_api, {
-                /* We extend the default converse.js API to add a method specific
-                 * to this plugin.
-                 */
-                'ping': function (jid) {
-                    converse.ping(jid);
-                }
-            });
-
             var onConnected = function () {
                 // Wrapper so that we can spy on registerPingHandler in tests
                 converse.registerPingHandler();

+ 3 - 0
tests/mock.js

@@ -78,6 +78,9 @@
 
     mock.initConverse = function (func, settings) {
         return function () {
+            window.localStorage.clear();
+            window.sessionStorage.clear();
+
             var converse = converse_api.initialize(_.extend({
                 i18n: window.locales.en,
                 auto_subscribe: false,