Bug 1857959 - De-XPCOM chat conversations service. r=mkmelin
Differential Revision: https://phabricator.services.mozilla.com/D190480 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
fc27896e89
Коммит
e20b662b9d
|
@ -5,76 +5,6 @@
|
|||
#include "nsISupports.idl"
|
||||
#include "prplIConversation.idl"
|
||||
#include "prplIMessage.idl"
|
||||
#include "imIContactsService.idl"
|
||||
|
||||
interface imIMessage;
|
||||
|
||||
[scriptable, uuid(81b8d9a9-4715-4109-b522-84b9d31493a3)]
|
||||
interface imIConversation: prplIConversation {
|
||||
// Will be null for MUCs and IMs from people not in the contacts list.
|
||||
readonly attribute imIContact contact;
|
||||
|
||||
// Write a system message into the conversation.
|
||||
// Note: this will not be logged.
|
||||
void systemMessage(in AUTF8String aMessage,
|
||||
[optional] in boolean aIsError,
|
||||
[optional] in boolean aNoCollapse);
|
||||
|
||||
// Write a system message into the conversation and trigger the update of the
|
||||
// notification counter during an off-the-record authentication request.
|
||||
// Note: this will not be logged.
|
||||
void notifyVerifyOTR(in AUTF8String aMessage);
|
||||
|
||||
attribute prplIConversation target;
|
||||
|
||||
// Number of unread messages (all messages, including system
|
||||
// messages are counted).
|
||||
readonly attribute unsigned long unreadMessageCount;
|
||||
// Number of unread incoming messages targeted at the user (= IMs or
|
||||
// message containing the user's nick in MUCs).
|
||||
readonly attribute unsigned long unreadTargetedMessageCount;
|
||||
// Number of unread incoming messages (both targeted and untargeted
|
||||
// messages are counted).
|
||||
readonly attribute unsigned long unreadIncomingMessageCount;
|
||||
// Number of unread off-the-record authentication requests.
|
||||
readonly attribute unsigned long unreadOTRNotificationCount;
|
||||
// Reset all unread message counts.
|
||||
void markAsRead();
|
||||
|
||||
// Can be used instead of the topic when no topic is set.
|
||||
readonly attribute AUTF8String noTopicString;
|
||||
|
||||
// Call this to give the core an opportunity to close an inactive
|
||||
// conversation. If the conversation is a left MUC or an IM
|
||||
// conversation without unread message, the implementation will call
|
||||
// close().
|
||||
// The returned value indicates if the conversation was closed.
|
||||
boolean checkClose();
|
||||
|
||||
// Get an array of all messages of the conversation.
|
||||
Array<imIMessage> getMessages();
|
||||
};
|
||||
|
||||
[scriptable, uuid(984e182c-d395-4fba-ba6e-cc80c71f57bf)]
|
||||
interface imIConversationsService: nsISupports {
|
||||
void initConversations();
|
||||
void unInitConversations();
|
||||
|
||||
// Register a conversation. This will create a unique id for the
|
||||
// conversation and set it.
|
||||
void addConversation(in prplIConversation aConversation);
|
||||
void removeConversation(in prplIConversation aConversation);
|
||||
|
||||
Array<imIConversation> getUIConversations();
|
||||
imIConversation getUIConversation(in prplIConversation aConversation);
|
||||
imIConversation getUIConversationByContactId(in long aId);
|
||||
|
||||
Array<prplIConversation> getConversations();
|
||||
prplIConversation getConversationById(in unsigned long aId);
|
||||
prplIConversation getConversationByNameAndAccount(in AUTF8String aName,
|
||||
in imIAccount aAccount,
|
||||
in boolean aIsChat);
|
||||
};
|
||||
|
||||
// Because of limitations in libpurple (write_conv is called without context),
|
||||
// there's an implicit contract that whatever message string the conversation
|
||||
|
|
|
@ -23,10 +23,4 @@ Classes = [
|
|||
'esModule': "resource:///modules/imContacts.sys.mjs",
|
||||
"constructor": "TagsService",
|
||||
},
|
||||
{
|
||||
"cid": "{b2397cd5-c76d-4618-8410-f344c7c6443a}",
|
||||
"contract_ids": ["@mozilla.org/chat/conversations-service;1"],
|
||||
'esModule': "resource:///modules/imConversations.sys.mjs",
|
||||
"constructor": "ConversationsService",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -133,45 +133,51 @@ imMessage.prototype = {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {prplIConversation} aPrplConversation
|
||||
* @param {number} [idToReuse] - ID to use for this UI conversation if it replaces another UI conversation.
|
||||
* @implements {prplIMessage}
|
||||
* @implements {nsIObserver}
|
||||
*/
|
||||
export function UIConversation(aPrplConversation, idToReuse) {
|
||||
this._prplConv = {};
|
||||
if (idToReuse) {
|
||||
this.id = idToReuse;
|
||||
} else {
|
||||
this.id = ++gLastUIConvId;
|
||||
export class UIConversation {
|
||||
QueryInterface = ChromeUtils.generateQI(["nsIObserver"]);
|
||||
get wrappedJSObject() {
|
||||
return this;
|
||||
}
|
||||
// Observers listening to this instance's notifications.
|
||||
this._observers = [];
|
||||
// Observers this instance has attached to prplIConversations.
|
||||
this._convObservers = new WeakMap();
|
||||
this._messages = [];
|
||||
this.changeTargetTo(aPrplConversation);
|
||||
const iface = Ci["prplIConv" + (aPrplConversation.isChat ? "Chat" : "IM")];
|
||||
this._interfaces = this._interfaces.concat(iface);
|
||||
// XPConnect will create a wrapper around 'this' after here,
|
||||
// so the list of exposed interfaces shouldn't change anymore.
|
||||
this.updateContactObserver();
|
||||
if (!idToReuse) {
|
||||
Services.obs.notifyObservers(this, "new-ui-conversation");
|
||||
}
|
||||
}
|
||||
|
||||
UIConversation.prototype = {
|
||||
__proto__: ClassInfo(
|
||||
["imIConversation", "prplIConversation", "nsIObserver"],
|
||||
"UI conversation"
|
||||
),
|
||||
_observedContact: null,
|
||||
/**
|
||||
* @param {prplIConversation} aPrplConversation
|
||||
* @param {number} [idToReuse] - ID to use for this UI conversation if it replaces another UI conversation.
|
||||
*/
|
||||
constructor(aPrplConversation, idToReuse) {
|
||||
this._prplConv = {};
|
||||
if (idToReuse) {
|
||||
this.id = idToReuse;
|
||||
} else {
|
||||
this.id = ++gLastUIConvId;
|
||||
}
|
||||
// Observers listening to this instance's notifications.
|
||||
this._observers = [];
|
||||
// Observers this instance has attached to prplIConversations.
|
||||
this._convObservers = new WeakMap();
|
||||
this._messages = [];
|
||||
this.changeTargetTo(aPrplConversation);
|
||||
this.updateContactObserver();
|
||||
if (!idToReuse) {
|
||||
Services.obs.notifyObservers(this, "new-ui-conversation");
|
||||
}
|
||||
}
|
||||
|
||||
_observedContact = null;
|
||||
/**
|
||||
* Will be null for MUCs and IMs from people not in the contacts list.
|
||||
*
|
||||
* @type {imIContact}
|
||||
*/
|
||||
get contact() {
|
||||
const target = this.target;
|
||||
if (!target.isChat && target.buddy) {
|
||||
return target.buddy.buddy.contact;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
updateContactObserver() {
|
||||
const contact = this.contact;
|
||||
if (contact && !this._observedContact) {
|
||||
|
@ -181,19 +187,19 @@ UIConversation.prototype = {
|
|||
this._observedContact.removeObserver(this);
|
||||
delete this._observedContact;
|
||||
}
|
||||
},
|
||||
}
|
||||
/**
|
||||
* @type {prplIConversation}
|
||||
*/
|
||||
get target() {
|
||||
return this._prplConv[this._currentTargetId];
|
||||
},
|
||||
}
|
||||
set target(aPrplConversation) {
|
||||
this.changeTargetTo(aPrplConversation);
|
||||
},
|
||||
}
|
||||
get hasMultipleTargets() {
|
||||
return Object.keys(this._prplConv).length > 1;
|
||||
},
|
||||
}
|
||||
getTargetByAccount(aAccount) {
|
||||
const accountId = aAccount.id;
|
||||
for (const id in this._prplConv) {
|
||||
|
@ -203,8 +209,8 @@ UIConversation.prototype = {
|
|||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
_currentTargetId: 0,
|
||||
}
|
||||
_currentTargetId = 0;
|
||||
changeTargetTo(aPrplConversation) {
|
||||
const id = aPrplConversation.id;
|
||||
if (this._currentTargetId == id) {
|
||||
|
@ -213,7 +219,9 @@ UIConversation.prototype = {
|
|||
|
||||
if (!(id in this._prplConv)) {
|
||||
this._prplConv[id] = aPrplConversation;
|
||||
const observeConv = this.observeConv.bind(this, id);
|
||||
const observeConv = {
|
||||
observe: (...args) => this.observeConv(id, ...args),
|
||||
};
|
||||
this._convObservers.set(aPrplConversation, observeConv);
|
||||
aPrplConversation.addObserver(observeConv);
|
||||
}
|
||||
|
@ -234,7 +242,7 @@ UIConversation.prototype = {
|
|||
lazy.bundle.formatStringFromName("targetChanged", params)
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
// Returns a boolean indicating if the ui-conversation was closed.
|
||||
// If the conversation was closed, aContactId.value is set to the contact id
|
||||
// or 0 if no contact was associated with the conversation.
|
||||
|
@ -265,35 +273,61 @@ UIConversation.prototype = {
|
|||
delete this._currentTargetId;
|
||||
this.notifyObservers(this, "ui-conversation-closed");
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
_unreadMessageCount: 0,
|
||||
_unreadMessageCount = 0;
|
||||
/**
|
||||
* Number of unread messages (all messages, including system
|
||||
* messages are counted).
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get unreadMessageCount() {
|
||||
return this._unreadMessageCount;
|
||||
},
|
||||
_unreadTargetedMessageCount: 0,
|
||||
}
|
||||
_unreadTargetedMessageCount = 0;
|
||||
/**
|
||||
* Number of unread incoming messages targeted at the user (= IMs or
|
||||
* message containing the user's nick in MUCs).
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get unreadTargetedMessageCount() {
|
||||
return this._unreadTargetedMessageCount;
|
||||
},
|
||||
_unreadIncomingMessageCount: 0,
|
||||
}
|
||||
_unreadIncomingMessageCount = 0;
|
||||
/**
|
||||
* Number of unread incoming messages (both targeted and untargeted
|
||||
* messages are counted).
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get unreadIncomingMessageCount() {
|
||||
return this._unreadIncomingMessageCount;
|
||||
},
|
||||
_unreadOTRNotificationCount: 0,
|
||||
}
|
||||
_unreadOTRNotificationCount = 0;
|
||||
/**
|
||||
* Number of unread off-the-record authentication requests.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get unreadOTRNotificationCount() {
|
||||
return this._unreadOTRNotificationCount;
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Reset all unread message counts.
|
||||
*/
|
||||
markAsRead() {
|
||||
delete this._unreadMessageCount;
|
||||
delete this._unreadTargetedMessageCount;
|
||||
delete this._unreadIncomingMessageCount;
|
||||
delete this._unreadOTRNotificationCount;
|
||||
this._unreadMessageCount = 0;
|
||||
this._unreadTargetedMessageCount = 0;
|
||||
this._unreadIncomingMessageCount = 0;
|
||||
this._unreadOTRNotificationCount = 0;
|
||||
if (this._messages.length) {
|
||||
this._messages[this._messages.length - 1].whenDisplayed();
|
||||
}
|
||||
this._notifyUnreadCountChanged();
|
||||
},
|
||||
_lastNotifiedUnreadCount: 0,
|
||||
}
|
||||
_lastNotifiedUnreadCount = 0;
|
||||
_notifyUnreadCountChanged() {
|
||||
if (this._unreadIncomingMessageCount == this._lastNotifiedUnreadCount) {
|
||||
return;
|
||||
|
@ -307,10 +341,24 @@ UIConversation.prototype = {
|
|||
this._unreadIncomingMessageCount.toString()
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Get an array of all messages of the conversation.
|
||||
*
|
||||
* @returns {imIMessage[]}
|
||||
*/
|
||||
getMessages() {
|
||||
return this._messages;
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Call this to give the core an opportunity to close an inactive
|
||||
* conversation. If the conversation is a left MUC or an IM
|
||||
* conversation without unread message, the implementation will call
|
||||
* close().
|
||||
* The returned value indicates if the conversation was closed.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
checkClose() {
|
||||
if (!this._currentTargetId) {
|
||||
// Already closed.
|
||||
|
@ -331,7 +379,7 @@ UIConversation.prototype = {
|
|||
|
||||
this.close();
|
||||
return true;
|
||||
},
|
||||
}
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "contact-no-longer-dummy") {
|
||||
|
@ -370,15 +418,15 @@ UIConversation.prototype = {
|
|||
) {
|
||||
this.notifyObservers(this, "update-buddy-display-name");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
_iconUpdatePending: false,
|
||||
_iconUpdatePending = false;
|
||||
updateIcon() {
|
||||
delete this._iconUpdatePending;
|
||||
this.notifyObservers(this, "update-buddy-icon");
|
||||
},
|
||||
}
|
||||
|
||||
_statusUpdatePending: false,
|
||||
_statusUpdatePending = false;
|
||||
updateBuddyStatus() {
|
||||
delete this._statusUpdatePending;
|
||||
const { statusType: statusType, statusText: statusText } = this.buddy;
|
||||
|
@ -418,9 +466,9 @@ UIConversation.prototype = {
|
|||
}
|
||||
}
|
||||
this.systemMessage(msg);
|
||||
},
|
||||
}
|
||||
|
||||
_disconnected: false,
|
||||
_disconnected = false;
|
||||
disconnecting() {
|
||||
if (this._disconnected) {
|
||||
return;
|
||||
|
@ -438,7 +486,7 @@ UIConversation.prototype = {
|
|||
this.systemMessage(lazy.bundle.GetStringFromName("accountDisconnected"));
|
||||
}
|
||||
this.notifyObservers(this, "update-buddy-status");
|
||||
},
|
||||
}
|
||||
connected() {
|
||||
if (this._disconnected) {
|
||||
delete this._disconnected;
|
||||
|
@ -463,7 +511,7 @@ UIConversation.prototype = {
|
|||
}
|
||||
}
|
||||
this.notifyObservers(this, "update-buddy-status");
|
||||
},
|
||||
}
|
||||
|
||||
observeConv(aTargetId, aSubject, aTopic, aData) {
|
||||
if (
|
||||
|
@ -478,8 +526,16 @@ UIConversation.prototype = {
|
|||
}
|
||||
|
||||
this.notifyObservers(aSubject, aTopic, aData);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a system message into the conversation.
|
||||
* Note: this will not be logged.
|
||||
*
|
||||
* @param {string} aText
|
||||
* @param {boolean} [aIsError=false]
|
||||
* @param {boolean} [aNoCollapse=false]
|
||||
*/
|
||||
systemMessage(aText, aIsError, aNoCollapse) {
|
||||
const flags = {
|
||||
system: true,
|
||||
|
@ -489,13 +545,17 @@ UIConversation.prototype = {
|
|||
};
|
||||
const message = new Message("system", aText, flags, this);
|
||||
this.notifyObservers(message, "new-text");
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a notification sound for a new chat message and trigger the
|
||||
* global notificationbox to prompt the user with the verifiation request.
|
||||
*
|
||||
* @param String aText - The system message.
|
||||
* Write a system message into the conversation and trigger the update of the
|
||||
* notification counter during an off-the-record authentication request.
|
||||
* Note: this will not be logged.
|
||||
*
|
||||
* @param {string} aText - The system message.
|
||||
*/
|
||||
notifyVerifyOTR(aText) {
|
||||
this._unreadOTRNotificationCount++;
|
||||
|
@ -507,39 +567,39 @@ UIConversation.prototype = {
|
|||
this._unreadOTRNotificationCount.toString()
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// prplIConversation
|
||||
get isChat() {
|
||||
return this.target.isChat;
|
||||
},
|
||||
}
|
||||
get account() {
|
||||
return this.target.account;
|
||||
},
|
||||
}
|
||||
get name() {
|
||||
return this.target.name;
|
||||
},
|
||||
}
|
||||
get normalizedName() {
|
||||
return this.target.normalizedName;
|
||||
},
|
||||
}
|
||||
get title() {
|
||||
return this.target.title;
|
||||
},
|
||||
}
|
||||
get startDate() {
|
||||
return this.target.startDate;
|
||||
},
|
||||
}
|
||||
get convIconFilename() {
|
||||
return this.target.convIconFilename;
|
||||
},
|
||||
}
|
||||
get encryptionState() {
|
||||
return this.target.encryptionState;
|
||||
},
|
||||
}
|
||||
initializeEncryption() {
|
||||
this.target.initializeEncryption();
|
||||
},
|
||||
}
|
||||
sendMsg(aMsg, aAction = false, aNotice = false) {
|
||||
this.target.sendMsg(aMsg, aAction, aNotice);
|
||||
},
|
||||
}
|
||||
unInit() {
|
||||
for (const id in this._prplConv) {
|
||||
const conv = this._prplConv[id];
|
||||
|
@ -552,7 +612,7 @@ UIConversation.prototype = {
|
|||
this._prplConv = {}; // Prevent .close from failing.
|
||||
delete this._currentTargetId;
|
||||
this.notifyObservers(this, "ui-conversation-destroyed");
|
||||
},
|
||||
}
|
||||
close() {
|
||||
for (const id in this._prplConv) {
|
||||
const conv = this._prplConv[id];
|
||||
|
@ -564,15 +624,15 @@ UIConversation.prototype = {
|
|||
delete this._currentTargetId;
|
||||
this.notifyObservers(this, "ui-conversation-closed");
|
||||
Services.obs.notifyObservers(this, "ui-conversation-closed");
|
||||
},
|
||||
}
|
||||
addObserver(aObserver) {
|
||||
if (!this._observers.includes(aObserver)) {
|
||||
this._observers.push(aObserver);
|
||||
}
|
||||
},
|
||||
}
|
||||
removeObserver(aObserver) {
|
||||
this._observers = this._observers.filter(o => o !== aObserver);
|
||||
},
|
||||
}
|
||||
notifyObservers(aSubject, aTopic, aData) {
|
||||
if (aTopic == "new-text" || aTopic == "update-text") {
|
||||
aSubject = new imMessage(aSubject);
|
||||
|
@ -650,64 +710,70 @@ UIConversation.prototype = {
|
|||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Used above when notifying of new-texts originating in the
|
||||
// UIConversation. This happens when this.systemMessage() is called. The
|
||||
// conversation for the message is set as the UIConversation.
|
||||
prepareForDisplaying(aMsg) {},
|
||||
prepareForDisplaying(aMsg) {}
|
||||
|
||||
// prplIConvIM
|
||||
get buddy() {
|
||||
return this.target.buddy;
|
||||
},
|
||||
}
|
||||
get typingState() {
|
||||
return this.target.typingState;
|
||||
},
|
||||
}
|
||||
sendTyping(aString) {
|
||||
return this.target.sendTyping(aString);
|
||||
},
|
||||
}
|
||||
|
||||
// Chat only
|
||||
getParticipants() {
|
||||
return this.target.getParticipants();
|
||||
},
|
||||
}
|
||||
get topic() {
|
||||
return this.target.topic;
|
||||
},
|
||||
}
|
||||
set topic(aTopic) {
|
||||
this.target.topic = aTopic;
|
||||
},
|
||||
}
|
||||
get topicSetter() {
|
||||
return this.target.topicSetter;
|
||||
},
|
||||
}
|
||||
get topicSettable() {
|
||||
return this.target.topicSettable;
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Can be used instead of the topic when no topic is set.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
get noTopicString() {
|
||||
return lazy.bundle.GetStringFromName("noTopic");
|
||||
},
|
||||
}
|
||||
get nick() {
|
||||
return this.target.nick;
|
||||
},
|
||||
}
|
||||
get left() {
|
||||
return this.target.left;
|
||||
},
|
||||
}
|
||||
get joining() {
|
||||
return this.target.joining;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var gConversationsService;
|
||||
|
||||
export function ConversationsService() {
|
||||
gConversationsService = this;
|
||||
}
|
||||
/**
|
||||
* @implements {nsIObserver}
|
||||
*/
|
||||
class ConversationsService {
|
||||
QueryInterface = ChromeUtils.generateQI(["nsIObserver"]);
|
||||
|
||||
ConversationsService.prototype = {
|
||||
get wrappedJSObject() {
|
||||
return this;
|
||||
},
|
||||
constructor() {
|
||||
gConversationsService = this;
|
||||
}
|
||||
|
||||
initConversations() {
|
||||
this._uiConv = {};
|
||||
|
@ -717,7 +783,7 @@ ConversationsService.prototype = {
|
|||
Services.obs.addObserver(this, "account-connected");
|
||||
Services.obs.addObserver(this, "account-buddy-added");
|
||||
Services.obs.addObserver(this, "account-buddy-removed");
|
||||
},
|
||||
}
|
||||
|
||||
unInitConversations() {
|
||||
const UIConvs = this.getUIConversations();
|
||||
|
@ -735,7 +801,7 @@ ConversationsService.prototype = {
|
|||
Services.obs.removeObserver(this, "account-connected");
|
||||
Services.obs.removeObserver(this, "account-buddy-added");
|
||||
Services.obs.removeObserver(this, "account-buddy-removed");
|
||||
},
|
||||
}
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "account-connected") {
|
||||
|
@ -804,8 +870,14 @@ ConversationsService.prototype = {
|
|||
uiConv.updateContactObserver();
|
||||
uiConv.notifyObservers(uiConv, "update-conv-buddy");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a conversation. This will create a unique id for the
|
||||
* conversation and set it.
|
||||
*
|
||||
* @param {prplIConversation} aPrplConversation
|
||||
*/
|
||||
addConversation(aPrplConversation) {
|
||||
// Give an id to the new conversation.
|
||||
aPrplConversation.id = ++gLastPrplConvId;
|
||||
|
@ -837,7 +909,7 @@ ConversationsService.prototype = {
|
|||
if (contactId) {
|
||||
this._uiConvByContactId[contactId] = newUIConv;
|
||||
}
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Informs the conversation service that the type of the conversation changed, which then lets the
|
||||
* UI components know to use a new UI conversation instance.
|
||||
|
@ -874,7 +946,10 @@ ConversationsService.prototype = {
|
|||
this._uiConvByContactId[contactId] = uiConv;
|
||||
}
|
||||
Services.obs.notifyObservers(uiConv, "conversation-update-type");
|
||||
},
|
||||
}
|
||||
/**
|
||||
* @param {prplIConversation} aPrplConversation
|
||||
*/
|
||||
removeConversation(aPrplConversation) {
|
||||
Services.obs.notifyObservers(aPrplConversation, "conversation-closed");
|
||||
|
||||
|
@ -888,15 +963,18 @@ ConversationsService.prototype = {
|
|||
Services.obs.notifyObservers(uiConv, "ui-conversation-closed");
|
||||
}
|
||||
this.forgetConversation(aPrplConversation);
|
||||
},
|
||||
}
|
||||
forgetConversation(aPrplConversation) {
|
||||
aPrplConversation.unInit();
|
||||
|
||||
this._prplConversations = this._prplConversations.filter(
|
||||
c => c !== aPrplConversation
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {IMConversation[]}
|
||||
*/
|
||||
getUIConversations() {
|
||||
const rv = [];
|
||||
if (this._uiConv) {
|
||||
|
@ -911,21 +989,36 @@ ConversationsService.prototype = {
|
|||
}
|
||||
}
|
||||
return rv;
|
||||
},
|
||||
}
|
||||
/**
|
||||
* @param {prplIConversation} aPrplConversation
|
||||
* @returns {IMConversation}
|
||||
*/
|
||||
getUIConversation(aPrplConversation) {
|
||||
const id = aPrplConversation.id;
|
||||
if (this._uiConv && id in this._uiConv) {
|
||||
return this._uiConv[id];
|
||||
}
|
||||
throw new Error("Unknown conversation");
|
||||
},
|
||||
}
|
||||
/**
|
||||
* @param {number} aId
|
||||
* @returns {IMConversation}
|
||||
*/
|
||||
getUIConversationByContactId(aId) {
|
||||
return aId in this._uiConvByContactId ? this._uiConvByContactId[aId] : null;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {prplIConversation[]}
|
||||
*/
|
||||
getConversations() {
|
||||
return this._prplConversations;
|
||||
},
|
||||
}
|
||||
/**
|
||||
* @param {number} aId
|
||||
* @returns {prplIConversation}
|
||||
*/
|
||||
getConversationById(aId) {
|
||||
for (const conv of this._prplConversations) {
|
||||
if (conv.id == aId) {
|
||||
|
@ -933,7 +1026,14 @@ ConversationsService.prototype = {
|
|||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {string} aName
|
||||
* @param {imIAccount} aAccount
|
||||
* @param {boolean} aIsChat
|
||||
* @returns {prplIConversation}
|
||||
*/
|
||||
getConversationByNameAndAccount(aName, aAccount, aIsChat) {
|
||||
const normalizedName = aAccount.normalize(aName);
|
||||
for (const conv of this._prplConversations) {
|
||||
|
@ -946,8 +1046,7 @@ ConversationsService.prototype = {
|
|||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI(["imIConversationsService"]),
|
||||
classDescription: "Conversations",
|
||||
};
|
||||
export const conversations = new ConversationsService();
|
||||
|
|
|
@ -33,7 +33,7 @@ Conversation.prototype = {
|
|||
DEBUG() {},
|
||||
},
|
||||
addObserver(aObserver) {
|
||||
if (!(aObserver instanceof Ci.nsIObserver)) {
|
||||
if (!(aObserver instanceof Ci.nsIObserver) && !("observe" in aObserver)) {
|
||||
aObserver = { observe: aObserver };
|
||||
}
|
||||
GenericConvIMPrototype.addObserver.call(this, aObserver);
|
||||
|
|
|
@ -409,7 +409,7 @@
|
|||
* Regenerate the tooltip based on a buddy.
|
||||
*
|
||||
* @param {prplIAccountBuddy} aBuddy - The buddy to generate the conversation.
|
||||
* @param {imIConversation} [aConv] - A conversation associated with this buddy.
|
||||
* @param {IMConversation} [aConv] - A conversation associated with this buddy.
|
||||
* @param {string} [overrideAvatar] - URL for the user avatar to use
|
||||
* instead.
|
||||
*/
|
||||
|
@ -500,7 +500,7 @@
|
|||
/**
|
||||
* Regenerate the tooltip based on a conversation.
|
||||
*
|
||||
* @param {imIConversation} aConv - The conversation to generate the tooltip from.
|
||||
* @param {IMConversation} aConv - The conversation to generate the tooltip from.
|
||||
* @param {string} [overrideAvatar] - URL for the user avatar to use
|
||||
* instead if the conversation is a direct conversation.
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,7 @@ export const IMServices = {};
|
|||
// eslint-disable-next-line mozilla/lazy-getter-object-name
|
||||
ChromeUtils.defineESModuleGetters(IMServices, {
|
||||
cmd: "resource:///modules/imCommands.sys.mjs",
|
||||
conversations: "resource:///modules/imConversations.sys.mjs",
|
||||
core: "resource:///modules/imCore.sys.mjs",
|
||||
logs: "resource:///modules/logger.sys.mjs",
|
||||
});
|
||||
|
@ -25,12 +26,6 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"@mozilla.org/chat/contacts-service;1",
|
||||
"imIContactsService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
IMServices,
|
||||
"conversations",
|
||||
"@mozilla.org/chat/conversations-service;1",
|
||||
"imIConversationsService"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
IMServices,
|
||||
"tags",
|
||||
|
|
|
@ -1188,13 +1188,15 @@ export var OTR = {
|
|||
this.onReceive(aObject);
|
||||
break;
|
||||
case "new-ui-conversation":
|
||||
this.addConversation(aObject);
|
||||
this.addConversation(aObject.wrappedJSObject);
|
||||
break;
|
||||
case "conversation-update-type":
|
||||
if (this._convos.has(aObject.target.id)) {
|
||||
this._convos.get(aObject.target.id).removeObserver(this);
|
||||
if (this._convos.has(aObject.wrappedJSObject.target.id)) {
|
||||
this._convos
|
||||
.get(aObject.wrappedJSObject.target.id)
|
||||
.removeObserver(this);
|
||||
}
|
||||
this.addConversation(aObject);
|
||||
this.addConversation(aObject.wrappedJSObject);
|
||||
break;
|
||||
case "update-conv-encryption": {
|
||||
// Disable OTR encryption when the chat protocol initiates encryption
|
||||
|
|
|
@ -213,7 +213,7 @@ function publishRoomDetails(account, conv) {
|
|||
* @param {number} [options.requiredCount] - How many of the parameters are required (from the start).
|
||||
* @param {(string[]) => boolean} [options.validateParams] - Validator function for params.
|
||||
* @param {(prplIConversation, string[]) => any[]} [options.formatParams] - Formatting function for params.
|
||||
* @returns {(string, imIConversation) => boolean} Command handler function that returns true when the command was handled.
|
||||
* @returns {(string, IMConversation) => boolean} Command handler function that returns true when the command was handled.
|
||||
*/
|
||||
function runCommand(
|
||||
commandCallback,
|
||||
|
@ -279,7 +279,7 @@ function runCommand(
|
|||
* @param {number} [options.requiredCount] - How many of the parameters are required (from the start).
|
||||
* @param {(string[]) => boolean} [options.validateParams] - Validator function for params.
|
||||
* @param {(prplIConversation, string[]) => any[]} [options.formatParams] - Formatting function for params.
|
||||
* @returns {(string, imIConversation) => boolean} Command handler function that returns true when the command was handled.
|
||||
* @returns {(string, IMConversation) => boolean} Command handler function that returns true when the command was handled.
|
||||
*/
|
||||
function clientCommand(clientMethod, parameterCount, options) {
|
||||
return runCommand(
|
||||
|
|
|
@ -1687,7 +1687,7 @@
|
|||
* Change the UI Conversation attached to this component and its browser.
|
||||
* Does not clear any existing messages in the conversation browser.
|
||||
*
|
||||
* @param {imIConversation} conv
|
||||
* @param {IMConversation} conv
|
||||
*/
|
||||
changeConversation(conv) {
|
||||
this._conv.removeObserver(this.observer);
|
||||
|
|
|
@ -166,7 +166,7 @@
|
|||
* Set the conversation this item should represent. Updates appearance and
|
||||
* adds observers to keep it up to date.
|
||||
*
|
||||
* @param {imIConversation} conv - Conversation this item represents.
|
||||
* @param {IMConversation} conv - Conversation this item represents.
|
||||
*/
|
||||
build(conv) {
|
||||
this.conv = conv;
|
||||
|
@ -340,7 +340,7 @@
|
|||
/**
|
||||
* Replace the conversation that this item represents.
|
||||
*
|
||||
* @param {imIConversation} conv - Updated conversation this should
|
||||
* @param {IMConversation} conv - Updated conversation this should
|
||||
* represent.
|
||||
*/
|
||||
changeConversation(conv) {
|
||||
|
|
|
@ -1442,7 +1442,7 @@ var chatHandler = {
|
|||
}
|
||||
if (aTopic == "new-ui-conversation") {
|
||||
if (chatTabType.hasBeenOpened) {
|
||||
chatHandler._addConversation(aSubject);
|
||||
chatHandler._addConversation(aSubject.wrappedJSObject);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1453,7 +1453,7 @@ var chatHandler = {
|
|||
}
|
||||
let conv = document
|
||||
.getElementById("conversationsGroup")
|
||||
.removeContact(aSubject);
|
||||
.removeContact(aSubject.wrappedJSObject);
|
||||
if (conv.imContact) {
|
||||
let contact = conv.imContact;
|
||||
let groupName = (contact.online ? "on" : "off") + "linecontactsGroup";
|
||||
|
@ -1646,22 +1646,23 @@ var chatHandler = {
|
|||
let contactlistbox = document.getElementById("contactlistbox");
|
||||
let convs = document.getElementById("conversationsGroup");
|
||||
let convItem = convs.nextElementSibling;
|
||||
const updatedConv = aSubject.wrappedJSObject;
|
||||
while (
|
||||
convItem.conv.target.id !== aSubject.target.id &&
|
||||
convItem.conv.target.id !== updatedConv.target.id &&
|
||||
convItem.id != "searchResultConv"
|
||||
) {
|
||||
convItem = convItem.nextElementSibling;
|
||||
}
|
||||
if (convItem.conv.target.id !== aSubject.target.id) {
|
||||
if (convItem.conv.target.id !== updatedConv.target.id) {
|
||||
// Could not find a matching conversation in the front end.
|
||||
return;
|
||||
}
|
||||
// Update UI conversation associated with components
|
||||
if (convItem.convView && convItem.convView.conv !== aSubject) {
|
||||
convItem.convView.changeConversation(aSubject);
|
||||
if (convItem.convView && convItem.convView.conv !== updatedConv) {
|
||||
convItem.convView.changeConversation(updatedConv);
|
||||
}
|
||||
if (convItem.conv !== aSubject) {
|
||||
convItem.changeConversation(aSubject);
|
||||
if (convItem.conv !== updatedConv) {
|
||||
convItem.changeConversation(updatedConv);
|
||||
} else {
|
||||
convItem.update();
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ export const ChatEncryption = {
|
|||
* given conversation, if encryption is available.
|
||||
*
|
||||
* @param {DOMDocument} document
|
||||
* @param {imIConversation} conversation
|
||||
* @param {IMConversation} conversation
|
||||
*/
|
||||
updateEncryptionButton(document, conversation) {
|
||||
if (!this.hasEncryptionActions(conversation)) {
|
||||
|
|
|
@ -557,7 +557,7 @@ var GlodaIMIndexer = {
|
|||
// Add ourselves to the ui-conversation's list of observers for the
|
||||
// unread-message-count-changed notification.
|
||||
// For this notification, aSubject is the ui-conversation that is opened.
|
||||
aSubject.addObserver(this);
|
||||
aSubject.wrappedJSObject.addObserver(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -565,7 +565,7 @@ var GlodaIMIndexer = {
|
|||
aTopic == "ui-conversation-closed" ||
|
||||
aTopic == "ui-conversation-replaced"
|
||||
) {
|
||||
aSubject.removeObserver(this);
|
||||
aSubject.wrappedJSObject.removeObserver(this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче