Bug 955642 - Handle Twitter direct messages (DMs) - Pull out shared methods from TimelineConversation, r=clokep.

This commit is contained in:
Arlo Breault 2016-07-06 12:41:00 -04:00
Родитель 0f0bed4fa5
Коммит 13461cb1c0
1 изменённых файлов: 97 добавлений и 91 удалений

Просмотреть файл

@ -123,87 +123,13 @@ Action.prototype = {
get run() { return this._action.bind(this._tweet); } get run() { return this._action.bind(this._tweet); }
}; };
function Conversation(aAccount) // Properties / methods shared by both DirectMessageConversation and
{ // TimelineConversation.
this._init(aAccount); var GenericTwitterConversation = {
this._ensureParticipantExists(aAccount.name);
// We need the screen names for the IDs in _friends, but _userInfo is
// indexed by name, so we build an ID -> name map.
let entries = [];
for (let [name, userInfo] of aAccount._userInfo) {
entries.push([userInfo.id_str, name]);
}
let names = new Map(entries);
for (let id_str of aAccount._friends)
this._ensureParticipantExists(names.get(id_str));
// If the user's info has already been received, update the timeline topic.
if (aAccount._userInfo.has(aAccount.name)) {
let userInfo = aAccount._userInfo.get(aAccount.name);
if ("description" in userInfo)
this.setTopic(userInfo.description, aAccount.name, true);
}
}
Conversation.prototype = {
__proto__: GenericConvChatPrototype,
unInit: function() {
delete this._account._timeline;
GenericConvChatPrototype.unInit.call(this);
},
inReplyToStatusId: null,
startReply: function(aTweet) {
this.inReplyToStatusId = aTweet.id_str;
let entities = aTweet.entities;
// Twitter replies go to all the users mentioned in the tweet.
let nicks = [aTweet.user.screen_name];
if ("user_mentions" in entities && Array.isArray(entities.user_mentions)) {
nicks = nicks.concat(entities.user_mentions
.map(um => um.screen_name));
}
// Ignore duplicates and the user's nick.
let prompt =
nicks.filter(function(aNick, aPos) {
return nicks.indexOf(aNick) == aPos && aNick != this._account.name;
}, this)
.map(aNick => "@" + aNick)
.join(" ") + " ";
this.notifyObservers(null, "replying-to-prompt", prompt);
this.notifyObservers(null, "status-text-changed",
_("replyingToStatusText", aTweet.text));
},
reTweet: function(aTweet) {
this._account.reTweet(aTweet, this.onSentCallback,
function(aException, aData) {
this.systemMessage(_("error.retweet", this._parseError(aData),
aTweet.text), true);
}, this);
},
getTweetLength: function (aString) { getTweetLength: function (aString) {
// Use the Twitter library to calculate the length. // Use the Twitter library to calculate the length.
return twttr.txt.getTweetLength(aString, this._account.config); return twttr.txt.getTweetLength(aString, this._account.config);
}, },
sendMsg: function (aMsg) {
if (this.getTweetLength(aMsg) > kMaxMessageLength) {
this.systemMessage(_("error.tooLong"), true);
throw Cr.NS_ERROR_INVALID_ARG;
}
this._account.tweet(aMsg, this.inReplyToStatusId, this.onSentCallback,
function(aException, aData) {
let error = this._parseError(aData);
this.systemMessage(_("error.general", error, aMsg), true);
}, this);
this.sendTyping("");
},
sendTyping: function(aString) {
if (aString.length == 0 && this.inReplyToStatusId) {
delete this.inReplyToStatusId;
this.notifyObservers(null, "status-text-changed", "");
return kMaxMessageLength;
}
return kMaxMessageLength - this.getTweetLength(aString);
},
systemMessage: function(aMessage, aIsError, aDate) { systemMessage: function(aMessage, aIsError, aDate) {
let flags = {system: true}; let flags = {system: true};
if (aIsError) if (aIsError)
@ -218,19 +144,6 @@ Conversation.prototype = {
throw "Wrong screen_name... Uh?"; throw "Wrong screen_name... Uh?";
this._account.displayMessages([tweet]); this._account.displayMessages([tweet]);
}, },
_parseError: function(aData) {
let error = "";
try {
let data = JSON.parse(aData);
if ("error" in data)
error = data.error;
else if ("errors" in data)
error = data.errors[0].message;
if (error)
error = "(" + error + ")";
} catch(e) {}
return error;
},
parseTweet: function(aTweet) { parseTweet: function(aTweet) {
let text = aTweet.text; let text = aTweet.text;
let entities = {}; let entities = {};
@ -362,6 +275,98 @@ Conversation.prototype = {
(new Tweet(aTweet, name, text, flags)).conversation = this; (new Tweet(aTweet, name, text, flags)).conversation = this;
}, },
_parseError: function(aData) {
let error = "";
try {
let data = JSON.parse(aData);
if ("error" in data)
error = data.error;
else if ("errors" in data)
error = data.errors[0].message;
if (error)
error = "(" + error + ")";
} catch(e) {}
return error;
}
};
function TimelineConversation(aAccount)
{
this._init(aAccount);
this._ensureParticipantExists(aAccount.name);
// We need the screen names for the IDs in _friends, but _userInfo is
// indexed by name, so we build an ID -> name map.
let entries = [];
for (let [name, userInfo] of aAccount._userInfo) {
entries.push([userInfo.id_str, name]);
}
let names = new Map(entries);
for (let id_str of aAccount._friends)
this._ensureParticipantExists(names.get(id_str));
// If the user's info has already been received, update the timeline topic.
if (aAccount._userInfo.has(aAccount.name)) {
let userInfo = aAccount._userInfo.get(aAccount.name);
if ("description" in userInfo)
this.setTopic(userInfo.description, aAccount.name, true);
}
}
TimelineConversation.prototype = {
__proto__: GenericConvChatPrototype,
unInit: function() {
delete this._account._timeline;
GenericConvChatPrototype.unInit.call(this);
},
inReplyToStatusId: null,
startReply: function(aTweet) {
this.inReplyToStatusId = aTweet.id_str;
let entities = aTweet.entities;
// Twitter replies go to all the users mentioned in the tweet.
let nicks = [aTweet.user.screen_name];
if ("user_mentions" in entities && Array.isArray(entities.user_mentions)) {
nicks = nicks.concat(entities.user_mentions
.map(um => um.screen_name));
}
// Ignore duplicates and the user's nick.
let prompt =
nicks.filter(function(aNick, aPos) {
return nicks.indexOf(aNick) == aPos && aNick != this._account.name;
}, this)
.map(aNick => "@" + aNick)
.join(" ") + " ";
this.notifyObservers(null, "replying-to-prompt", prompt);
this.notifyObservers(null, "status-text-changed",
_("replyingToStatusText", aTweet.text));
},
reTweet: function(aTweet) {
this._account.reTweet(aTweet, this.onSentCallback,
function(aException, aData) {
this.systemMessage(_("error.retweet", this._parseError(aData),
aTweet.text), true);
}, this);
},
sendMsg: function (aMsg) {
if (this.getTweetLength(aMsg) > kMaxMessageLength) {
this.systemMessage(_("error.tooLong"), true);
throw Cr.NS_ERROR_INVALID_ARG;
}
this._account.tweet(aMsg, this.inReplyToStatusId, this.onSentCallback,
function(aException, aData) {
let error = this._parseError(aData);
this.systemMessage(_("error.general", error, aMsg), true);
}, this);
this.sendTyping("");
},
sendTyping: function(aString) {
if (aString.length == 0 && this.inReplyToStatusId) {
delete this.inReplyToStatusId;
this.notifyObservers(null, "status-text-changed", "");
return kMaxMessageLength;
}
return kMaxMessageLength - this.getTweetLength(aString);
},
_ensureParticipantExists: function(aNick) { _ensureParticipantExists: function(aNick) {
if (this._participants.has(aNick)) if (this._participants.has(aNick))
return; return;
@ -382,6 +387,7 @@ Conversation.prototype = {
this._account.setUserDescription(aTopic); this._account.setUserDescription(aTopic);
} }
}; };
Object.assign(TimelineConversation.prototype, GenericTwitterConversation);
function Account(aProtocol, aImAccount) function Account(aProtocol, aImAccount)
{ {
@ -621,7 +627,7 @@ Account.prototype = {
} }
}, },
get timeline() { return this._timeline || (this._timeline = new Conversation(this)); }, get timeline() { return this._timeline || (this._timeline = new TimelineConversation(this)); },
displayMessages: function(aMessages) { displayMessages: function(aMessages) {
let lastMsgId = this._lastMsgId; let lastMsgId = this._lastMsgId;
for (let tweet of aMessages) { for (let tweet of aMessages) {