Can I store the converse object (which currently attaches to the browser window object) in another in-memory object, like Vuex (https://vuex.vuejs.org/)?
If you don't know how it works, to simplify: it is a in-memory object which is a centralized store for a Vue application (React has its version, too, Redux).
Basically, can I attach the converse object to other than the browser window object?
The window.converse object is not that interesting. All the interesting stuff is stored on the internal _converse object that is only available to plugins and which exposes the internal API.
Both objects get created automatically when Converse starts and then all relevant Models and Collections get populated as well, so it's not necessary to try and persist the converse or _converse objects.
Converse stores all relevant data in localStorage and sessionStorage (and I'm working on adding support for IndexedDB).
All the data is modeled with Backbone.Model and Backbone.Collection instances and they automatically get persisted to the browser storage.
Whenever model.save is called the data gets persisted. When you reload the page or log in again, then the data is loaded by calling fetch.
Hmm... Now I understand...
Something related to this structure of plugins... so, lets suppose I would like to send a simple message. Can plugins expose some public method I create? A method so I could call:
window.converse.sendMessage(msg, to). ?
Or what would be another aproach to this scenario? Because, from what I understood from this plugin structure, one must define a course of action before initializing the converse, so... how could I make message content and recepient dynamic parameters to a send method?
If it is something docs related I've missed, I'm sorry, and thanks in advance.
The API methods on the window.converse object are known as the "public API". They are public because you don't need to register a plugin in order to access them.
If you look at the relevant code, you'll see that there aren't many of them. Really just converse.initialize and converse.plugins.add.
All the other API methods which you might want to use are (until now) in the private _converse object (note the underscore prefix), which is only available to plugins. This is to avoid untrusted 3rd party code from easily accessing the API and doing nefarious things with it.
So, you'll need to register a plugin first, before you can start calling private API methods.
Here's where it gets interesting :)
Until now, we've only been documenting everything under the _converse.api namespace as API methods and we only tried to keep these methods stable (or when we changed one, we made a major semver release).
However, sending messages is a bit of a special case and it also recently came up in #1496.
Generally, you send a message from a ChatBox (or just "Chat"). So generally you'd first need to get the chat, and then call sendMessage on it, in order to send out a message.
However, because the sendMessage method is on a ChatBox, and not explicitly exposed under the _converse.api namespace, I didn't consider it to be an official API method and we didn't document it as one or tried to keep it stable. However, as I now tried to think of the best way to expose an API for sending messages, I realised that letting people just use sendMessage seems to be the best way (and I assume this is what most people have been doing anyway).
So, I've now documented sendMessage as an official API method, which means that we will keep it stable and if we change it we need to make a major version change for the next release.
I also took the opportunity to slightly refactor it, to make it simpler to use. This however means that you need to update your checkout of converse.js to the latest version!
Here's what you would now do to send out a message:
converse.plugins.add('myplugin', {
async initialize: function () {
const { _converse } = this;
await _converse.api.waitUntil('chatBoxesFetched');
const chat = _converse.api.chats.get('[email protected]');
chat.sendMessage('hello world!');
},
});
BTW, if you don't know already, when adding a plugin, you need to whitelist it.
converse.plugins.add('myplugin', {
async initialize: function () {
const { _converse } = this;
await _converse.api.waitUntil('chatBoxesFetched');
const chat = _converse.api.chats.get('[email protected]');
chat.sendMessage('hello world!');
},
});
About this example, what would be a good aproach if I needed to send a message on demand... like, if the user clicks on some contact, open its chatbox, and send a message: then calls a ConverseJS Headless method to send the message to the contact (my question is this).
But it appears to me, with the plugins aproach, there is no way I can call a sendMessage method onDemand for some contact... Also, there is another agravating: the message content and the user JID should be parameters, as I would call the plugin on demand (this, however, I've a solution for).
Do I need to add a plugin everytime I need to send a message? Then, what is the logic behind? I mean, if I add a plugin to send my message on the "initialize()" function, everytime the ConverseJS is initialized (and the plugin) it would send the message... That is not what I want... I want to send messages in a dynamic way, like when the user sends to JID some message.
I'm sorry if I did not understand something basic, my difficulty lies in understanding how to use this plugin structure if I need to trigger a plugin method on demand only, like sending a message, changing status, etc and not everytime the plugin is initialized...
I'm not using ConverseJS frontend client, only ConverseJS headless...
The expectation is that you'll put ALL your code inside a plugin. That way you always have access to the API and the internal models.
That's how Converse (the app) does it. There's very little code that's outside of a plugin.
If for some reason you don't want to put your code inside a plugin, then you can let your plugin expose the API methods publically, for example on the window object and then call those public methods from your non-plugin code.
I think it's safer to keep sensitive user data and API methods away from third party code, which is why Converse has this plugin structure and keeps everything inside a closure, but you're not required to abide by this approach.
Does this answer your question?
Yes, that clarifies the question for me, thank you very much.
@jcbrand Thank you very much for clarifying. Though I found this issue after understanding the core concepts, I believe it will be really helpful for beginners.
I am using converse headless for my React project.
Most helpful comment
The API methods on the
window.converseobject are known as the "public API". They are public because you don't need to register a plugin in order to access them.If you look at the relevant code, you'll see that there aren't many of them. Really just converse.initialize and converse.plugins.add.
All the other API methods which you might want to use are (until now) in the private
_converseobject (note the underscore prefix), which is only available to plugins. This is to avoid untrusted 3rd party code from easily accessing the API and doing nefarious things with it.So, you'll need to register a plugin first, before you can start calling private API methods.
Here's where it gets interesting :)
Until now, we've only been documenting everything under the
_converse.apinamespace as API methods and we only tried to keep these methods stable (or when we changed one, we made a major semver release).However, sending messages is a bit of a special case and it also recently came up in #1496.
Generally, you send a message from a ChatBox (or just "Chat"). So generally you'd first need to get the chat, and then call sendMessage on it, in order to send out a message.
However, because the
sendMessagemethod is on a ChatBox, and not explicitly exposed under the_converse.apinamespace, I didn't consider it to be an official API method and we didn't document it as one or tried to keep it stable. However, as I now tried to think of the best way to expose an API for sending messages, I realised that letting people just usesendMessageseems to be the best way (and I assume this is what most people have been doing anyway).So, I've now documented
sendMessageas an official API method, which means that we will keep it stable and if we change it we need to make a major version change for the next release.I also took the opportunity to slightly refactor it, to make it simpler to use. This however means that you need to update your checkout of converse.js to the latest version!
Here's what you would now do to send out a message: