Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
715 lines
24 KiB
JavaScript
Executable file
715 lines
24 KiB
JavaScript
Executable file
/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
|
|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
|
|
|
|
|
/* global EventDispatcher,
|
|
Promise,
|
|
Settings,
|
|
SMIL,
|
|
Threads,
|
|
Utils
|
|
*/
|
|
|
|
/*exported MessageManager */
|
|
|
|
/**
|
|
* MessageManager wraps around {@link http://mdn.io/MozMobileMessageManager}
|
|
* that makes access to SMS/MMS related operations (sending, handling
|
|
* read/delivery reports etc.) and respective events easier.
|
|
* @module MessageManager
|
|
*/
|
|
'use strict';
|
|
(function(exports) {
|
|
var MessageManager = {
|
|
|
|
/**
|
|
* Initializes MessageManager and subscribes for required
|
|
* {@link http://mdn.io/MozMobileMessageManager} events.
|
|
* Should be always called before calling any other MessageManager methods.
|
|
*/
|
|
init: function mm_init() {
|
|
this._mozMobileMessage = navigator.mozMobileMessage;
|
|
|
|
this._mozMobileMessage.addEventListener(
|
|
'received', this.onMessageReceived.bind(this)
|
|
);
|
|
this._mozMobileMessage.addEventListener(
|
|
'sending', this.onMessageSending.bind(this)
|
|
);
|
|
this._mozMobileMessage.addEventListener(
|
|
'sent', this.onMessageSent.bind(this)
|
|
);
|
|
this._mozMobileMessage.addEventListener(
|
|
'failed', this.onMessageFailed.bind(this)
|
|
);
|
|
this._mozMobileMessage.addEventListener(
|
|
'readsuccess', this.onReadSuccess.bind(this)
|
|
);
|
|
this._mozMobileMessage.addEventListener(
|
|
'deliverysuccess', this.onDeliverySuccess.bind(this)
|
|
);
|
|
this._mozMobileMessage.addEventListener(
|
|
'deleted', this.onDeleted.bind(this)
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Event occurs when an SMS or MMS enters the send flow.
|
|
* @param {MozSmsEvent|MozMmsEvent} e Instance of
|
|
* {@link http://mdn.io/MozSmsEvent} or {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onMessageSending: function mm_onMessageSending(e) {
|
|
Threads.registerMessage(e.message);
|
|
|
|
this.emit('message-sending', { message: e.message });
|
|
},
|
|
|
|
/**
|
|
* Specifies an event listener to receive "failed" events. These events occur
|
|
* when sending an MMS or SMS has failed.
|
|
* @param {MozSmsEvent|MozMmsEvent} e Instance of
|
|
* {@link http://mdn.io/MozSmsEvent} or {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onMessageFailed: function mm_onMessageFailed(e) {
|
|
this.emit('message-failed-to-send', { message: e.message });
|
|
},
|
|
|
|
/**
|
|
* Specifies an event listener to receive "deliverysuccess" events. These
|
|
* events occur when an SMS or MMS is delivered.
|
|
* @param {MozSmsEvent|MozMmsEvent} e Instance of
|
|
* {@link http://mdn.io/MozSmsEvent} or {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onDeliverySuccess: function mm_onDeliverySuccess(e) {
|
|
this.emit('message-delivered', { message: e.message });
|
|
},
|
|
|
|
/**
|
|
* Specifies an event listener to receive "read" events. These events
|
|
* occur when MMS is read by recipient (read status isn't supported by SMS).
|
|
* @param {MozMmsEvent} e Instance of {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onReadSuccess: function mm_onReadSuccess(e) {
|
|
this.emit('message-read', { message: e.message });
|
|
},
|
|
|
|
/**
|
|
* Specifies an event listener to receive "sent" events. These events occur
|
|
* when an SMS or MMS is sent.
|
|
* @param {MozSmsEvent|MozMmsEvent} e Instance of
|
|
* {@link http://mdn.io/MozSmsEvent} or {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onMessageSent: function mm_onMessageSent(e) {
|
|
this.emit('message-sent', { message: e.message });
|
|
},
|
|
|
|
/**
|
|
* Specifies an event listener to receive "received" events. These events
|
|
* occur when an SMS or MMS is received. Event handler executed when new SMS
|
|
* or MMS is received.
|
|
* @param {MozSmsEvent|MozMmsEvent} e Instance of
|
|
* {@link http://mdn.io/MozSmsEvent} or {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onMessageReceived: function mm_onMessageReceived(e) {
|
|
var message = e.message;
|
|
|
|
if (message.messageClass && message.messageClass === 'class-0') {
|
|
return;
|
|
}
|
|
|
|
// Here we can only have one sender, so deliveryInfo[0].deliveryStatus =>
|
|
// message status from sender. Ignore 'pending' messages that are received
|
|
// this means we are in automatic download mode.
|
|
if (message.delivery === 'not-downloaded' &&
|
|
message.deliveryInfo[0].deliveryStatus === 'pending') {
|
|
return;
|
|
}
|
|
|
|
Threads.registerMessage(message);
|
|
|
|
this.emit('message-received', { message: message });
|
|
},
|
|
|
|
/**
|
|
* Event handler executed when message is deleted.
|
|
* @param {MozSmsEvent|MozMmsEvent} e Instance of
|
|
* {@link http://mdn.io/MozSmsEvent} or {@link http://mdn.io/MozMmsEvent}.
|
|
*/
|
|
onDeleted: function(e) {
|
|
// The method verifies that some threads have been deleted.
|
|
if (e.deletedThreadIds && e.deletedThreadIds.length) {
|
|
this.emit('threads-deleted', {
|
|
ids: e.deletedThreadIds
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Obtains all the treads and takes a set of callback functions as an
|
|
* argument.
|
|
* @param {Object} options A set of callback functions as described below:-
|
|
* @param {function) options.each: callback function invoked for each message.
|
|
* @param {function} options.end: callback function run when cursor is "done".
|
|
* @param {function} options.done: callback function run when we iterated
|
|
* through all the threads or consumer requested to do so.
|
|
*/
|
|
getThreads: function mm_getThreads(options) {
|
|
|
|
var each = options.each;
|
|
var end = options.end;
|
|
var done = options.done;
|
|
var cursor = null;
|
|
|
|
// WORKAROUND for bug 958738. We can remove 'try\catch' block once this bug
|
|
// is resolved.
|
|
try {
|
|
cursor = this._mozMobileMessage.getThreads();
|
|
} catch(e) {
|
|
console.error('Error occurred while retrieving threads:', e.name, e);
|
|
end && end();
|
|
done && done();
|
|
|
|
return;
|
|
}
|
|
|
|
cursor.onsuccess = function onsuccess() {
|
|
if (this.result) {
|
|
// Invoking callback on each thread.
|
|
each && each(this.result);
|
|
|
|
this.continue();
|
|
return;
|
|
}
|
|
|
|
// Invoking terminating callbacks.
|
|
end && end();
|
|
done && done();
|
|
};
|
|
|
|
cursor.onerror = function onerror() {
|
|
console.error('Reading the database. Error: ' + this.error.name);
|
|
done && done();
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Method used to access message having a given id.
|
|
* @param {number} id The id of the message we wish to get.
|
|
* @return {DOMRequest<SmsMessage|MmsMessage>}
|
|
*/
|
|
getMessage: function mm_getMsg(id) {
|
|
return this._mozMobileMessage.getMessage(id);
|
|
},
|
|
|
|
/**
|
|
* Method to get the MMS object having a given id.
|
|
* @param {number} id The id of the MMS we wish to get.
|
|
* @return {DOMRequest<MmsMessage>}
|
|
*/
|
|
retrieveMMS: function mm_retrieveMMS(id) {
|
|
return this._mozMobileMessage.retrieveMMS(id);
|
|
},
|
|
|
|
/**
|
|
* Obtains all the messages using a given filter.
|
|
* @param {Object} options A set of callback functions as described below:-
|
|
* @param {function} options.each callback function invoked for each message.
|
|
* @param {function} options.end callback function run when cursor is "done".
|
|
* @param {function} options.endArgs specify arguments for the "end" callback.
|
|
* @param {function} options.done callback function invoked when we iterated
|
|
* through all the messages or consumer requested to do so.
|
|
* @param {function} options.filter a MobileMessageFilter or similar object.
|
|
* @param {boolean} invert option to invert the selection.
|
|
*/
|
|
getMessages: function mm_getMgs(options) {
|
|
var each = options.each;
|
|
var invert = options.invert;
|
|
var end = options.end;
|
|
var endArgs = options.endArgs;
|
|
var done = options.done;
|
|
var filter = options.filter;
|
|
var cursor = this._mozMobileMessage.getMessages(filter, !invert);
|
|
|
|
cursor.onsuccess = function onsuccess() {
|
|
if (!this.done) {
|
|
var shouldContinue = true;
|
|
if (each) {
|
|
shouldContinue = each(this.result);
|
|
}
|
|
// if each returns false the iteration stops.
|
|
if (shouldContinue !== false) { // if this is undefined this is fine.
|
|
this.continue();
|
|
} else {
|
|
done && done();
|
|
}
|
|
} else {
|
|
end && end(endArgs);
|
|
done && done();
|
|
}
|
|
};
|
|
cursor.onerror = function onerror() {
|
|
var msg = 'Reading the database. Error: ' + this.error.name;
|
|
console.log(msg);
|
|
done && done();
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Sanitizes the "serviceId". It works as follows:-
|
|
* 0 is a valid value so we need to take care to not consider it as a falsy
|
|
* value. We want to return null for anything that's not a number or a string
|
|
* containing a number.
|
|
* @param {number|string} id The service ID.
|
|
* @private
|
|
* @return {?number}
|
|
*/
|
|
_sanitizeServiceId: function mm_sanitizeServiceId(serviceId) {
|
|
if (serviceId == null || // null or undefined
|
|
isNaN(+serviceId)) {
|
|
serviceId = null;
|
|
} else {
|
|
serviceId = +serviceId;
|
|
}
|
|
|
|
return serviceId;
|
|
},
|
|
|
|
/**
|
|
* Gets send options for the specified "serviceId".
|
|
* @param {number|string} id The service ID.
|
|
* @private
|
|
* @return {{ serviceId: number|string }}
|
|
*/
|
|
_getSendOptionsFromServiceId: function mm_gSOFSI(serviceId) {
|
|
var sendOpts;
|
|
|
|
if (serviceId != null && // not null, not undefined
|
|
Settings.hasSeveralSim()) {
|
|
sendOpts = { serviceId: serviceId };
|
|
}
|
|
|
|
return sendOpts;
|
|
},
|
|
|
|
/**
|
|
* Sends an SMS based on the specified parameters object
|
|
* @param {Object} opts Options object that contains :-
|
|
* - recipients (string or array of string): contains the list of recipients
|
|
* for this message.
|
|
* - content (string): the message's body.
|
|
* - serviceId (optional long or string): the SIM serviceId we use to send the
|
|
* message.
|
|
* - onsuccess (optional function): will be called when one SMS has been
|
|
* sent successfully, with the request's result as argument. Can be called
|
|
* several times.
|
|
* - onerror (optional function): will be called when one SMS transmission
|
|
* failed, with the error object as argument. Can be called several times.
|
|
* - oncomplete (optional function): will be called when all messages have
|
|
* been sent. It's argument will have the following properties:
|
|
* + hasError (boolean): whether we had at least one error
|
|
* + return (array): each item is an object with the following properties:
|
|
* . success (boolean): whether this is a success or an error.
|
|
* . result (request's result): the request's result object.
|
|
* . recipient (string): the recipient used for this transmission.
|
|
*/
|
|
sendSMS: function mm_send(opts) {
|
|
var recipients = opts.recipients || [],
|
|
content = opts.content,
|
|
serviceId = this._sanitizeServiceId(opts.serviceId),
|
|
onsuccess = opts.onsuccess,
|
|
onerror = opts.onerror,
|
|
oncomplete = opts.oncomplete;
|
|
|
|
if (!Array.isArray(recipients)) {
|
|
recipients = [recipients];
|
|
}
|
|
|
|
// The returned value is not a DOM request!
|
|
// Instead, It's an array of DOM requests.
|
|
var i = 0;
|
|
var requestResult = { hasError: false, return: [] };
|
|
|
|
// Getting serviceId field in sendOpts.
|
|
var sendOpts = this._getSendOptionsFromServiceId(serviceId);
|
|
|
|
var requests = this._mozMobileMessage.send(recipients, content, sendOpts);
|
|
|
|
var numberOfRequests = requests.length;
|
|
|
|
requests.forEach(function(request, idx) {
|
|
request.onsuccess = function onSuccess(event) {
|
|
// Callback functions executed message has been successfully sent.
|
|
onsuccess && onsuccess(event.target.result);
|
|
|
|
requestResult.return.push({
|
|
success: true,
|
|
result: event.target.result,
|
|
recipient: recipients[idx]
|
|
});
|
|
|
|
// Last callback, oncomplete, executed at the end of the loop.
|
|
if (i === numberOfRequests - 1) {
|
|
oncomplete && oncomplete(requestResult);
|
|
}
|
|
i++;
|
|
};
|
|
|
|
request.onerror = function onError(event) {
|
|
console.error('Error Sending: ' + JSON.stringify(event.target.error));
|
|
onerror && onerror(event.target.error);
|
|
|
|
requestResult.hasError = true;
|
|
requestResult.return.push({
|
|
success: false,
|
|
code: event.target.error,
|
|
recipient: recipients[idx]
|
|
});
|
|
|
|
if (i === numberOfRequests - 1) {
|
|
oncomplete && oncomplete(requestResult);
|
|
}
|
|
i++;
|
|
};
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Sends an MMS based on the specified parameters object
|
|
* @param {Object} opts is the options field with the following properties:
|
|
* - recipients (string or array of string): recipients for this message
|
|
* - subject (optional string): subject for this message
|
|
* - content (array of SMIL slides): this is the content for the message (see
|
|
* ConversationView for more information)
|
|
* - serviceId (optional long or string): the SIM that should be used for
|
|
* sending this message. If this is not the current default configuration
|
|
* for sending MMS, then we'll first switch the configuration to this
|
|
* serviceId, and only then send the message. That means that the "sending"
|
|
* event will come quite late in this case.
|
|
* - onsuccess (optional func): called only once, even for several recipients,
|
|
* when the message is successfully sent.
|
|
* - onerror (optional func): called only once if there is an error.
|
|
*/
|
|
sendMMS: function mm_sendMMS(opts) {
|
|
var request;
|
|
var recipients = opts.recipients,
|
|
subject = opts.subject,
|
|
content = opts.content,
|
|
serviceId = opts.serviceId = this._sanitizeServiceId(opts.serviceId),
|
|
onsuccess = opts.onsuccess,
|
|
onerror = opts.onerror;
|
|
|
|
if (!Array.isArray(recipients)) {
|
|
recipients = [recipients];
|
|
}
|
|
|
|
var message = SMIL.generate(content);
|
|
|
|
var sendOpts = this._getSendOptionsFromServiceId(serviceId);
|
|
|
|
request = this._mozMobileMessage.sendMMS({
|
|
receivers: recipients,
|
|
subject: subject,
|
|
smil: message.smil,
|
|
attachments: message.attachments
|
|
}, sendOpts);
|
|
|
|
request.onsuccess = function onSuccess(event) {
|
|
onsuccess && onsuccess(event.target.result);
|
|
};
|
|
|
|
request.onerror = function onError(event) {
|
|
onerror && onerror(event.target.error);
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Resends message with the given options.
|
|
* @param {Object} opts Options is the object with the following properties:-
|
|
* - message (object): the message object containing all the information
|
|
* depending on the type of the message which can be 'sms' or 'mms'.
|
|
* - onsuccess (optional function): will be called when the message has been
|
|
* sent successfully, with the request's result as argument. Can be called
|
|
* several times.
|
|
* - onerror (optional function): will be called when the message transmission
|
|
* failed, with the error object as argument. Can be called several times.
|
|
*/
|
|
resendMessage: function mm_resendMessage(opts) {
|
|
var message = opts.message;
|
|
|
|
if (!message) {
|
|
throw new Error('Message to resend is not defined.');
|
|
}
|
|
|
|
var serviceId = Settings.getServiceIdByIccId(message.iccId);
|
|
var sendOpts = this._getSendOptionsFromServiceId(serviceId);
|
|
var onsuccess = opts.onsuccess;
|
|
var onerror = opts.onerror;
|
|
var request;
|
|
|
|
if (message.type === 'sms') {
|
|
request = this._mozMobileMessage.send(
|
|
message.receiver, message.body, sendOpts);
|
|
}
|
|
if (message.type === 'mms') {
|
|
request = this._mozMobileMessage.sendMMS({
|
|
receivers: message.receivers,
|
|
subject: message.subject,
|
|
smil: message.smil,
|
|
attachments: message.attachments
|
|
}, sendOpts);
|
|
}
|
|
|
|
request.onsuccess = function onSuccess(evt) {
|
|
MessageManager.deleteMessages(message.id);
|
|
onsuccess && onsuccess(evt.target.result);
|
|
};
|
|
|
|
request.onerror = function onError(evt) {
|
|
MessageManager.deleteMessages(message.id);
|
|
onerror && onerror(evt.target.error);
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Deletes messages using the message id provided.
|
|
* @param {number} id The ID of the message to be deleted.
|
|
* @return {Promise}
|
|
*/
|
|
deleteMessages: function mm_deleteMessages(id) {
|
|
// As DOMRequest doesn't have "catch" method we should use "then" with
|
|
// "null" for the success callback to handle reject case only.
|
|
return this._mozMobileMessage.delete(id).then(null, (e) => {
|
|
// TODO: If the messages could not be deleted completely, conversation
|
|
// view will also update without notification currently. May need more
|
|
// information for user that the messages were not removed completely.
|
|
// See bug #1045666 for details.
|
|
console.error(`Deleting in the database. [${e.name}] ${e.message || ''}`);
|
|
|
|
return null;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Marks a thread as read or unread depending on value of isRead as true or
|
|
* false respectively.
|
|
* @param {number|string} threadId The ID of the thread to be marked as read.
|
|
* @param {boolean} isRead If "true" then message is to be marked as read
|
|
* otherwise message is to be marked as unread.
|
|
*/
|
|
markThreadRead: function mm_markThreadRead(threadId, isRead = true) {
|
|
// Create filter object to mark all unread messages of the specified thread.
|
|
var filter = {};
|
|
filter.threadId = +threadId;
|
|
filter.read = !isRead;
|
|
|
|
var messagesUnreadIDs = [];
|
|
|
|
// Building the options field in getMessages() with above filter.
|
|
var changeStatusOptions = {
|
|
each: function addUnreadMessage(message) {
|
|
// First build up array of Unread message ID.
|
|
messagesUnreadIDs.push(message.id);
|
|
return true;
|
|
},
|
|
filter: filter,
|
|
invert: true,
|
|
end: function handleUnread() {
|
|
// end with marking each of them as read.
|
|
MessageManager.markMessagesRead(messagesUnreadIDs, isRead);
|
|
}
|
|
};
|
|
MessageManager.getMessages(changeStatusOptions);
|
|
},
|
|
|
|
/**
|
|
* Marks messages with specified ids as read.
|
|
* @param {Array<Number>} list List of all the message IDs to be changed to
|
|
* read.
|
|
* @param {boolean} isRead Pass true if message is to be marked as read and
|
|
* false if message is to be marked as unread.
|
|
*/
|
|
markMessagesRead: function mm_markMessagesRead(list, isRead = true) {
|
|
if (!this._mozMobileMessage || !list.length) {
|
|
return;
|
|
}
|
|
|
|
// We chain the calls to the API in a way that we make no call to
|
|
// 'markMessageRead' until a previous call is completed. This way any
|
|
// other potential call to the API, like the one for getting a message
|
|
// list, could be done within the calls to mark the messages as read.
|
|
|
|
var id = list.pop();
|
|
// TODO: Third parameter of markMessageRead is return read request.
|
|
// Here we always return read request for now, but we can let user
|
|
// decide to return request or not in Bug 971658.
|
|
var req = this._mozMobileMessage.markMessageRead(id, isRead, true);
|
|
// isRead == false i.e mark as unread case, marking only one message
|
|
// as unread is sufficient.
|
|
req.onsuccess = (function onsuccess() {
|
|
if (!list.length || !isRead) {
|
|
return;
|
|
} else if (isRead) {
|
|
this.markMessagesRead(list, isRead);
|
|
}
|
|
}).bind(this);
|
|
|
|
req.onerror = function onerror() {
|
|
console.error(
|
|
'Error while marking message %d as read: %s', id, this.error.name
|
|
);
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Method used to get the information necessary to create a multipart SMS for
|
|
* a given text.
|
|
* @param {string} text The text used to create the SMS.
|
|
* @return {Promise<MozSmsSegmentInfo>} Instance of
|
|
* {@link http://mdn.io/MozSmsSegmentInfo}
|
|
*/
|
|
getSegmentInfo: function mm_getSegmentInfo(text) {
|
|
if (!(this._mozMobileMessage &&
|
|
this._mozMobileMessage.getSegmentInfoForText)) {
|
|
return Promise.reject(new Error('mozMobileMessage is unavailable.'));
|
|
}
|
|
|
|
var defer = Utils.Promise.defer();
|
|
|
|
var request = this._mozMobileMessage.getSegmentInfoForText(text);
|
|
request.onsuccess = function onsuccess(e) {
|
|
defer.resolve(e.target.result);
|
|
};
|
|
|
|
request.onerror = function onerror(e) {
|
|
defer.reject(e.target.error);
|
|
};
|
|
|
|
return defer.promise;
|
|
},
|
|
|
|
/**
|
|
* This method checks whether message is received from a sender with specified
|
|
* number or sent to this particular number. (in case of MMS only 1-to-1,
|
|
* non-group MMS's are counted).
|
|
* It's used to differentiate from broadcast messages ---> group MMS.
|
|
* @param {number} number Phone number.
|
|
* @param {Object} message A composite object having details about message
|
|
* delivery, type, sender and receiver.
|
|
* @private
|
|
* @return {boolean}
|
|
*/
|
|
_isMessageBelongTo1to1Conversation:
|
|
function isMessageBelongTo1to1Conversation(number, message) {
|
|
var isIncoming = message.delivery === 'received' ||
|
|
message.delivery === 'not-downloaded';
|
|
// if it is a received message, it is a candidate
|
|
// we still need to test the sender in case the user filters with his own
|
|
// number, because we would get all the received messages in this case.
|
|
if (isIncoming) {
|
|
return Utils.probablyMatches(message.sender, number);
|
|
} else {
|
|
switch (message.type) {
|
|
case 'sms':
|
|
// in case of sent messages and sms, we test if the receiver match the
|
|
// filter, to filter out other sent messages in the case user is
|
|
// sending message to himself
|
|
return Utils.probablyMatches(message.receiver, number);
|
|
case 'mms':
|
|
return message.receivers.length === 1 &&
|
|
Utils.probablyMatches(message.receivers[0], number);
|
|
default:
|
|
console.error('Got an unknown message type: ' + message.type);
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Find a SMS/MMS thread from a number.
|
|
* @param {number} number Phone number to find thread for.
|
|
* @return {Promise<number>} that is resolved to a threadId or rejected if
|
|
* not found
|
|
*/
|
|
findThreadFromNumber: function mm_findThread(number) {
|
|
|
|
function checkCandidate(message) {
|
|
var isMessageInThread = MessageManager.
|
|
_isMessageBelongTo1to1Conversation(number, message);
|
|
if (isMessageInThread) {
|
|
threadId = message.threadId;
|
|
return false; // found the message, stop iterating
|
|
}
|
|
}
|
|
|
|
var threadId = null;
|
|
var deferred = Utils.Promise.defer();
|
|
|
|
MessageManager.getMessages({
|
|
filter: { numbers: [number] },
|
|
each: checkCandidate,
|
|
done: function() {
|
|
if (threadId == null) {
|
|
deferred.reject(new Error('No thread found for number: ' + number));
|
|
return;
|
|
} else {
|
|
deferred.resolve(threadId);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
|
|
return deferred.promise;
|
|
},
|
|
|
|
/**
|
|
* This method ensures that threads have been registered in the in-memory
|
|
* cache. In the case it has, the promise returned resolves immediately. If
|
|
* not, it loads the last message from the thread and creates a new entry in
|
|
* cache based on it. It can happen when application loaded from non default
|
|
* page and Thread cache hasn't been populated.
|
|
* @param {number|string} threadId The ID of the thread we wish to register.
|
|
* @return {Promise}
|
|
*/
|
|
ensureThreadRegistered(threadId) {
|
|
var getOneMessageForThread = (threadId) => {
|
|
var defer = Utils.Promise.defer();
|
|
this.getMessages({
|
|
each: function(message) {
|
|
defer.resolve(message);
|
|
return false;
|
|
},
|
|
done: function() {
|
|
defer.reject(new Error('found no message'));
|
|
},
|
|
filter: { threadId: threadId }
|
|
});
|
|
return defer.promise;
|
|
};
|
|
|
|
// Checking whether Thread cache has this thread.
|
|
if (Threads.has(threadId)) {
|
|
return Promise.resolve();
|
|
}
|
|
|
|
return getOneMessageForThread(threadId).then(
|
|
(message) => Threads.registerMessage(message)
|
|
);
|
|
}
|
|
};
|
|
|
|
Object.defineProperty(exports, 'MessageManager', {
|
|
get: function () {
|
|
delete exports.MessageManager;
|
|
|
|
exports.MessageManager = EventDispatcher.mixin(MessageManager, [
|
|
'message-sending', 'message-failed-to-send', 'message-delivered',
|
|
'message-read', 'message-sent', 'message-received', 'threads-deleted'
|
|
]);
|
|
|
|
return exports.MessageManager;
|
|
},
|
|
configurable: true,
|
|
enumerable: true
|
|
});
|
|
|
|
})(window);
|